Merge pull request #4440 from Ma27/misc-pos-fixes

Miscellaneous improvements for positioning in eval-errors
This commit is contained in:
Eelco Dolstra 2021-04-23 11:10:59 +02:00 committed by GitHub
commit 293220bed5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 116 additions and 49 deletions

View file

@ -35,6 +35,7 @@ class Bindings
{ {
public: public:
typedef uint32_t size_t; typedef uint32_t size_t;
Pos *pos;
private: private:
size_t size_, capacity_; size_t size_, capacity_;

View file

@ -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 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->push_back(Attr(nameSym, i.valueExpr->maybeThunk(state, *dynamicEnv), &i.pos));
v.attrs->sort(); // FIXME: inefficient v.attrs->sort(); // FIXME: inefficient
} }
v.attrs->pos = &pos;
} }

View file

@ -180,6 +180,7 @@ struct ExprOpHasAttr : Expr
struct ExprAttrs : Expr struct ExprAttrs : Expr
{ {
bool recursive; bool recursive;
Pos pos;
struct AttrDef { struct AttrDef {
bool inherited; bool inherited;
Expr * e; Expr * e;
@ -199,7 +200,8 @@ struct ExprAttrs : Expr
}; };
typedef std::vector<DynamicAttrDef> DynamicAttrDefs; typedef std::vector<DynamicAttrDef> DynamicAttrDefs;
DynamicAttrDefs dynamicAttrs; DynamicAttrDefs dynamicAttrs;
ExprAttrs() : recursive(false) { }; ExprAttrs(const Pos &pos) : recursive(false), pos(pos) { };
ExprAttrs() : recursive(false), pos(noPos) { };
COMMON_METHODS COMMON_METHODS
}; };

View file

@ -478,7 +478,7 @@ binds
$$->attrs[i.symbol] = ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i.symbol), makeCurPos(@6, data)); $$->attrs[i.symbol] = ExprAttrs::AttrDef(new ExprSelect(CUR_POS, $4, i.symbol), makeCurPos(@6, data));
} }
} }
| { $$ = new ExprAttrs; } | { $$ = new ExprAttrs(makeCurPos(@0, data)); }
; ;
attrs attrs

View file

@ -547,18 +547,56 @@ typedef list<Value *> ValueList;
#endif #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) static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
state.forceAttrs(*args[0], pos); state.forceAttrs(*args[0], pos);
/* Get the start set. */ /* Get the start set. */
Bindings::iterator startSet = Bindings::iterator startSet = getAttr(
args[0]->attrs->find(state.symbols.create("startSet")); state,
if (startSet == args[0]->attrs->end()) "genericClosure",
throw EvalError({ "startSet",
.msg = hintfmt("attribute 'startSet' required"), args[0]->attrs,
.errPos = pos pos
}); );
state.forceList(*startSet->value, pos); state.forceList(*startSet->value, pos);
ValueList workSet; ValueList workSet;
@ -566,13 +604,14 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
workSet.push_back(startSet->value->listElems()[n]); workSet.push_back(startSet->value->listElems()[n]);
/* Get the operator. */ /* Get the operator. */
Bindings::iterator op = Bindings::iterator op = getAttr(
args[0]->attrs->find(state.symbols.create("operator")); state,
if (op == args[0]->attrs->end()) "genericClosure",
throw EvalError({ "operator",
.msg = hintfmt("attribute 'operator' required"), args[0]->attrs,
.errPos = pos pos
}); );
state.forceValue(*op->value, pos); state.forceValue(*op->value, pos);
/* Construct the closure by applying the operator to element of /* 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); state.forceAttrs(*args[0], pos);
/* Figure out the name first (for stack backtraces). */ /* Figure out the name first (for stack backtraces). */
Bindings::iterator attr = args[0]->attrs->find(state.sName); Bindings::iterator attr = getAttr(
if (attr == args[0]->attrs->end()) state,
throw EvalError({ "derivationStrict",
.msg = hintfmt("required attribute 'name' missing"), state.sName,
.errPos = pos args[0]->attrs,
}); pos
);
string drvName; string drvName;
Pos & posDrvName(*attr->pos); Pos & posDrvName(*attr->pos);
try { try {
@ -953,7 +994,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
} }
} else { } 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); drv.env.emplace(key, s);
if (i->name == state.sBuilder) drv.builder = s; if (i->name == state.sBuilder) drv.builder = s;
else if (i->name == state.sSystem) drv.platform = 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()) if (i != v2.attrs->end())
prefix = state.forceStringNoCtx(*i->value, pos); prefix = state.forceStringNoCtx(*i->value, pos);
i = v2.attrs->find(state.symbols.create("path")); i = getAttr(
if (i == v2.attrs->end()) state,
throw EvalError({ "findFile",
.msg = hintfmt("attribute 'path' missing"), "path",
.errPos = pos v2.attrs,
}); pos
);
PathSet context; PathSet context;
string path = state.coerceToString(pos, *i->value, context, false, false); 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); string attr = state.forceStringNoCtx(*args[0], pos);
state.forceAttrs(*args[1], pos); state.forceAttrs(*args[1], pos);
// !!! Should we create a symbol here or just do a lookup? // !!! Should we create a symbol here or just do a lookup?
Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); Bindings::iterator i = getAttr(
if (i == args[1]->attrs->end()) state,
throw EvalError({ "getAttr",
.msg = hintfmt("attribute '%1%' missing", attr), attr,
.errPos = pos args[1]->attrs,
}); pos
);
// !!! add to stack trace? // !!! add to stack trace?
if (state.countCalls && i->pos) state.attrSelects[*i->pos]++; if (state.countCalls && i->pos) state.attrSelects[*i->pos]++;
state.forceValue(*i->value, 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]); Value & v2(*args[0]->listElems()[i]);
state.forceAttrs(v2, pos); state.forceAttrs(v2, pos);
Bindings::iterator j = v2.attrs->find(state.sName); Bindings::iterator j = getAttr(
if (j == v2.attrs->end()) state,
throw TypeError({ "listToAttrs",
.msg = hintfmt("'name' attribute missing in a call to 'listToAttrs'"), state.sName,
.errPos = pos v2.attrs,
}); pos
string name = state.forceStringNoCtx(*j->value, pos); );
string name = state.forceStringNoCtx(*j->value, *j->pos);
Symbol sym = state.symbols.create(name); Symbol sym = state.symbols.create(name);
if (seen.insert(sym).second) { if (seen.insert(sym).second) {
Bindings::iterator j2 = v2.attrs->find(state.symbols.create(state.sValue)); Bindings::iterator j2 = getAttr(
if (j2 == v2.attrs->end()) state,
throw TypeError({ "listToAttrs",
.msg = hintfmt("'value' attribute missing in a call to 'listToAttrs'"), state.sValue,
.errPos = pos v2.attrs,
}); pos
);
v.attrs->push_back(Attr(sym, j2->value, j2->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) { for (unsigned int n = 0; n < nrLists; ++n) {
Value * vElem = args[1]->listElems()[n]; Value * vElem = args[1]->listElems()[n];
state.callFunction(*args[0], *vElem, lists[n], pos); 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(); len += lists[n].listSize();
} }

View file

@ -341,6 +341,8 @@ public:
return internalType == tList1 ? 1 : internalType == tList2 ? 2 : bigList.size; 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 /* Check whether forcing this value requires a trivial amount of
computation. In particular, function applications are computation. In particular, function applications are
non-trivial. */ non-trivial. */