mirror of
https://github.com/NixOS/nix
synced 2025-06-27 08:31:16 +02:00
libexpr: misc improvements for proper error position
When working on some more complex Nix code, there are sometimes rather unhelpful or misleading error messages, especially if coerce-errors are thrown. This patch is a first steps towards improving that. I'm happy to file more changes after that, but I'd like to gather some feedback first. To summarize, this patch does the following things: * Attrsets (a.k.a. `Bindings` in `libexpr`) now have a `Pos`. This is helpful e.g. to identify which attribute-set in `listToAttrs` is invalid. * The `Value`-struct has a new method named `determinePos` which tries to guess the position of a value and falls back to a default if that's not possible. This can be used to provide better messages if a coercion fails. * The new `determinePos`-API is used by `builtins.concatMap` now. With that change, Nix shows the exact position in the error where a wrong value was returned by the lambda. To make sure it's still obvious that `concatMap` is the problem, another stack-frame was added. * The changes described above can be added to every other `primop`, but first I'd like to get some feedback about the overall approach.
This commit is contained in:
parent
3550a32b25
commit
7c76964daa
6 changed files with 39 additions and 12 deletions
|
@ -2149,21 +2149,27 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
|
|||
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
|
||||
if (j == v2.attrs->end()) {
|
||||
auto e = TypeError({
|
||||
.msg = hintfmt("'name' attribute missing for 'listToAttrs'"),
|
||||
.errPos = *v2.attrs->pos
|
||||
});
|
||||
string name = state.forceStringNoCtx(*j->value, pos);
|
||||
e.addTrace(pos, hintfmt("while invoking '%s'", "listToAttrs"));
|
||||
throw e;
|
||||
}
|
||||
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
|
||||
if (j2 == v2.attrs->end()) {
|
||||
auto e = TypeError({
|
||||
.msg = hintfmt("'value' attribute missing for 'listToAttrs'"),
|
||||
.errPos = *v2.attrs->pos
|
||||
});
|
||||
e.addTrace(pos, hintfmt("while invoking '%s'", "listToAttrs"));
|
||||
throw e;
|
||||
}
|
||||
v.attrs->push_back(Attr(sym, j2->value, j2->pos));
|
||||
}
|
||||
}
|
||||
|
@ -2804,7 +2810,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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue