aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2021-04-23 11:10:59 +0200
committerGitHub <noreply@github.com>2021-04-23 11:10:59 +0200
commit293220bed5a75efc963e33c183787e87e55e28d9 (patch)
tree25f8f1de0689fe843d3be6acbf2217a224122326
parentd9864be4b757468d33bc49edddce5e4f04ef4b90 (diff)
parent864ef0e93dfd58b147d46c340305acf2f9c6b314 (diff)
Merge pull request #4440 from Ma27/misc-pos-fixes
Miscellaneous improvements for positioning in eval-errors
-rw-r--r--src/libexpr/attr-set.hh1
-rw-r--r--src/libexpr/eval.cc11
-rw-r--r--src/libexpr/nixexpr.hh4
-rw-r--r--src/libexpr/parser.y2
-rw-r--r--src/libexpr/primops.cc145
-rw-r--r--src/libexpr/value.hh2
6 files changed, 116 insertions, 49 deletions
diff --git a/src/libexpr/attr-set.hh b/src/libexpr/attr-set.hh
index 6d68e5df3..1da8d91df 100644
--- a/src/libexpr/attr-set.hh
+++ b/src/libexpr/attr-set.hh
@@ -35,6 +35,7 @@ class Bindings
{
public:
typedef uint32_t size_t;
+ Pos *pos;
private:
size_t size_, capacity_;
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 936bccc8c..ef9f8efca 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -201,6 +201,15 @@ string showType(const Value & v)
}
}
+Pos Value::determinePos(const Pos &pos) const
+{
+ switch (internalType) {
+ case tAttrs: return *attrs->pos;
+ case tLambda: return lambda.fun->pos;
+ case tApp: return app.left->determinePos(pos);
+ default: return pos;
+ }
+}
bool Value::isTrivial() const
{
@@ -1060,6 +1069,8 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
v.attrs->push_back(Attr(nameSym, i.valueExpr->maybeThunk(state, *dynamicEnv), &i.pos));
v.attrs->sort(); // FIXME: inefficient
}
+
+ v.attrs->pos = &pos;
}
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh
index 8df8055b3..51a14cd59 100644
--- a/src/libexpr/nixexpr.hh
+++ b/src/libexpr/nixexpr.hh
@@ -180,6 +180,7 @@ struct ExprOpHasAttr : Expr
struct ExprAttrs : Expr
{
bool recursive;
+ Pos pos;
struct AttrDef {
bool inherited;
Expr * e;
@@ -199,7 +200,8 @@ struct ExprAttrs : Expr
};
typedef std::vector<DynamicAttrDef> DynamicAttrDefs;
DynamicAttrDefs dynamicAttrs;
- ExprAttrs() : recursive(false) { };
+ ExprAttrs(const Pos &pos) : recursive(false), pos(pos) { };
+ ExprAttrs() : recursive(false), pos(noPos) { };
COMMON_METHODS
};
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 49d995bb9..f948dde47 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -478,7 +478,7 @@ binds
$$->attrs[i.symbol] = ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i.symbol), makeCurPos(@6, data));
}
}
- | { $$ = new ExprAttrs; }
+ | { $$ = new ExprAttrs(makeCurPos(@0, data)); }
;
attrs
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 428adf4c2..ff2f302ed 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -547,18 +547,56 @@ typedef list<Value *> ValueList;
#endif
+static Bindings::iterator getAttr(
+ EvalState & state,
+ string funcName,
+ string attrName,
+ Bindings * attrSet,
+ const Pos & pos)
+{
+ Bindings::iterator value = attrSet->find(state.symbols.create(attrName));
+ if (value == attrSet->end()) {
+ hintformat errorMsg = hintfmt(
+ "attribute '%s' missing for call to '%s'",
+ attrName,
+ funcName
+ );
+
+ Pos aPos = *attrSet->pos;
+ if (aPos == noPos) {
+ throw TypeError({
+ .msg = errorMsg,
+ .errPos = pos,
+ });
+ } else {
+ auto e = TypeError({
+ .msg = errorMsg,
+ .errPos = aPos,
+ });
+
+ // Adding another trace for the function name to make it clear
+ // which call received wrong arguments.
+ e.addTrace(pos, hintfmt("while invoking '%s'", funcName));
+ throw e;
+ }
+ }
+
+ return value;
+}
+
static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
state.forceAttrs(*args[0], pos);
/* Get the start set. */
- Bindings::iterator startSet =
- args[0]->attrs->find(state.symbols.create("startSet"));
- if (startSet == args[0]->attrs->end())
- throw EvalError({
- .msg = hintfmt("attribute 'startSet' required"),
- .errPos = pos
- });
+ Bindings::iterator startSet = getAttr(
+ state,
+ "genericClosure",
+ "startSet",
+ args[0]->attrs,
+ pos
+ );
+
state.forceList(*startSet->value, pos);
ValueList workSet;
@@ -566,13 +604,14 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
workSet.push_back(startSet->value->listElems()[n]);
/* Get the operator. */
- Bindings::iterator op =
- args[0]->attrs->find(state.symbols.create("operator"));
- if (op == args[0]->attrs->end())
- throw EvalError({
- .msg = hintfmt("attribute 'operator' required"),
- .errPos = pos
- });
+ Bindings::iterator op = getAttr(
+ state,
+ "genericClosure",
+ "operator",
+ args[0]->attrs,
+ pos
+ );
+
state.forceValue(*op->value, pos);
/* Construct the closure by applying the operator to element of
@@ -816,12 +855,14 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
state.forceAttrs(*args[0], pos);
/* Figure out the name first (for stack backtraces). */
- Bindings::iterator attr = args[0]->attrs->find(state.sName);
- if (attr == args[0]->attrs->end())
- throw EvalError({
- .msg = hintfmt("required attribute 'name' missing"),
- .errPos = pos
- });
+ Bindings::iterator attr = getAttr(
+ state,
+ "derivationStrict",
+ state.sName,
+ args[0]->attrs,
+ pos
+ );
+
string drvName;
Pos & posDrvName(*attr->pos);
try {
@@ -953,7 +994,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
}
} else {
- auto s = state.coerceToString(posDrvName, *i->value, context, true);
+ auto s = state.coerceToString(*i->pos, *i->value, context, true);
drv.env.emplace(key, s);
if (i->name == state.sBuilder) drv.builder = s;
else if (i->name == state.sSystem) drv.platform = s;
@@ -1369,12 +1410,13 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
if (i != v2.attrs->end())
prefix = state.forceStringNoCtx(*i->value, pos);
- i = v2.attrs->find(state.symbols.create("path"));
- if (i == v2.attrs->end())
- throw EvalError({
- .msg = hintfmt("attribute 'path' missing"),
- .errPos = pos
- });
+ i = getAttr(
+ state,
+ "findFile",
+ "path",
+ v2.attrs,
+ pos
+ );
PathSet context;
string path = state.coerceToString(pos, *i->value, context, false, false);
@@ -2016,12 +2058,13 @@ void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
string attr = state.forceStringNoCtx(*args[0], pos);
state.forceAttrs(*args[1], pos);
// !!! Should we create a symbol here or just do a lookup?
- Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr));
- if (i == args[1]->attrs->end())
- throw EvalError({
- .msg = hintfmt("attribute '%1%' missing", attr),
- .errPos = pos
- });
+ Bindings::iterator i = getAttr(
+ state,
+ "getAttr",
+ attr,
+ args[1]->attrs,
+ pos
+ );
// !!! add to stack trace?
if (state.countCalls && i->pos) state.attrSelects[*i->pos]++;
state.forceValue(*i->value, pos);
@@ -2148,22 +2191,25 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
Value & v2(*args[0]->listElems()[i]);
state.forceAttrs(v2, pos);
- Bindings::iterator j = v2.attrs->find(state.sName);
- if (j == v2.attrs->end())
- throw TypeError({
- .msg = hintfmt("'name' attribute missing in a call to 'listToAttrs'"),
- .errPos = pos
- });
- string name = state.forceStringNoCtx(*j->value, pos);
+ Bindings::iterator j = getAttr(
+ state,
+ "listToAttrs",
+ state.sName,
+ v2.attrs,
+ pos
+ );
+
+ string name = state.forceStringNoCtx(*j->value, *j->pos);
Symbol sym = state.symbols.create(name);
if (seen.insert(sym).second) {
- Bindings::iterator j2 = v2.attrs->find(state.symbols.create(state.sValue));
- if (j2 == v2.attrs->end())
- throw TypeError({
- .msg = hintfmt("'value' attribute missing in a call to 'listToAttrs'"),
- .errPos = pos
- });
+ Bindings::iterator j2 = getAttr(
+ state,
+ "listToAttrs",
+ state.sValue,
+ v2.attrs,
+ pos
+ );
v.attrs->push_back(Attr(sym, j2->value, j2->pos));
}
}
@@ -2804,7 +2850,12 @@ static void prim_concatMap(EvalState & state, const Pos & pos, Value * * args, V
for (unsigned int n = 0; n < nrLists; ++n) {
Value * vElem = args[1]->listElems()[n];
state.callFunction(*args[0], *vElem, lists[n], pos);
- state.forceList(lists[n], pos);
+ try {
+ state.forceList(lists[n], lists[n].determinePos(args[0]->determinePos(pos)));
+ } catch (TypeError &e) {
+ e.addTrace(pos, hintfmt("while invoking '%s'", "concatMap"));
+ throw e;
+ }
len += lists[n].listSize();
}
diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh
index b317c1898..a1f131f9e 100644
--- a/src/libexpr/value.hh
+++ b/src/libexpr/value.hh
@@ -341,6 +341,8 @@ public:
return internalType == tList1 ? 1 : internalType == tList2 ? 2 : bigList.size;
}
+ Pos determinePos(const Pos &pos) const;
+
/* Check whether forcing this value requires a trivial amount of
computation. In particular, function applications are
non-trivial. */