Merge pull request #4440 from Ma27/misc-pos-fixes
Miscellaneous improvements for positioning in eval-errors
This commit is contained in:
commit
293220bed5
6 changed files with 116 additions and 49 deletions
|
@ -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_;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
Loading…
Reference in a new issue