Merge "lixexpr: Declutter error traces" into main

This commit is contained in:
Raito Bezarius
2025-04-24 19:07:06 +00:00
committed by Lix Systems Gerrit
13 changed files with 143 additions and 96 deletions
+62 -42
View File
@@ -1039,40 +1039,34 @@ void EvalState::eval(Expr & e, Value & v)
e.eval(*this, ctx.builtins.env, v);
}
#define checkType(typeName, stringName) \
if (v.type() != (typeName)) \
ctx.errors.make<TypeError>( \
"expected a %1% but found %2%: %3%", \
Uncolored(stringName), \
showType(v), \
ValuePrinter(*this, v, errorPrintOptions) \
).atPos(e.getPos()).withFrame(env, e).debugThrow();
inline bool EvalState::evalBool(Env & env, Expr & e, const PosIdx pos, std::string_view errorCtx)
inline bool EvalState::evalBool(Env & env, Expr & e)
{
try {
Value v;
e.eval(*this, env, v);
if (v.type() != nBool)
ctx.errors.make<TypeError>(
"expected a Boolean but found %1%: %2%",
showType(v),
ValuePrinter(*this, v, errorPrintOptions)
).atPos(pos).withFrame(env, e).debugThrow();
return v.boolean;
} catch (Error & e) {
e.addTrace(ctx.positions[pos], errorCtx);
throw;
}
Value v;
e.eval(*this, env, v);
checkType(nBool, "Boolean");
return v.boolean;
}
inline void EvalState::evalAttrs(Env & env, Expr & e, Value & v, const PosIdx pos, std::string_view errorCtx)
inline void EvalState::evalAttrs(Env & env, Expr & e, Value & v)
{
try {
e.eval(*this, env, v);
if (v.type() != nAttrs)
ctx.errors.make<TypeError>(
"expected a set but found %1%: %2%",
showType(v),
ValuePrinter(*this, v, errorPrintOptions)
).withFrame(env, e).debugThrow();
} catch (Error & e) {
e.addTrace(ctx.positions[pos], errorCtx);
throw;
}
e.eval(*this, env, v);
checkType(nAttrs, "set");
}
inline void EvalState::evalList(Env & env, Expr & e, Value & v)
{
e.eval(*this, env, v);
checkType(nList, "list");
}
@@ -1248,7 +1242,19 @@ Value * ExprList::maybeThunk(EvalState & state, Env & env)
void ExprVar::eval(EvalState & state, Env & env, Value & v)
{
Value * v2 = state.lookupVar(&env, *this, false);
state.forceValue(*v2, pos);
try {
state.forceValue(*v2, pos);
} catch (Error & e) {
/* `name` can be invalid if we are an ExprInheritFrom */
if (name) {
e.addTrace(
state.ctx.positions[getPos()],
"while evaluating %s",
state.ctx.symbols[name]
);
}
throw;
}
v = *v2;
}
@@ -1848,14 +1854,13 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v)
void ExprIf::eval(EvalState & state, Env & env, Value & v)
{
// We cheat in the parser, and pass the position of the condition as the position of the if itself.
(state.evalBool(env, *cond, pos, "while evaluating a branch condition") ? *then : *else_).eval(state, env, v);
(state.evalBool(env, *cond) ? *then : *else_).eval(state, env, v);
}
void ExprAssert::eval(EvalState & state, Env & env, Value & v)
{
if (!state.evalBool(env, *cond, pos, "in the condition of the assert statement")) {
if (!state.evalBool(env, *cond)) {
state.ctx.errors.make<AssertionError>("assertion failed")
.atPos(pos)
.withFrame(env, *this)
@@ -1867,7 +1872,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v)
void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
{
v.mkBool(!state.evalBool(env, *e, getPos(), "in the argument of the not operator")); // XXX: FIXME: !
v.mkBool(!state.evalBool(env, *e));
}
@@ -1889,27 +1894,27 @@ void ExprOpNEq::eval(EvalState & state, Env & env, Value & v)
void ExprOpAnd::eval(EvalState & state, Env & env, Value & v)
{
v.mkBool(state.evalBool(env, *e1, pos, "in the left operand of the AND (&&) operator") && state.evalBool(env, *e2, pos, "in the right operand of the AND (&&) operator"));
v.mkBool(state.evalBool(env, *e1) && state.evalBool(env, *e2));
}
void ExprOpOr::eval(EvalState & state, Env & env, Value & v)
{
v.mkBool(state.evalBool(env, *e1, pos, "in the left operand of the OR (||) operator") || state.evalBool(env, *e2, pos, "in the right operand of the OR (||) operator"));
v.mkBool(state.evalBool(env, *e1) || state.evalBool(env, *e2));
}
void ExprOpImpl::eval(EvalState & state, Env & env, Value & v)
{
v.mkBool(!state.evalBool(env, *e1, pos, "in the left operand of the IMPL (->) operator") || state.evalBool(env, *e2, pos, "in the right operand of the IMPL (->) operator"));
v.mkBool(!state.evalBool(env, *e1) || state.evalBool(env, *e2));
}
void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
{
Value v1, v2;
state.evalAttrs(env, *e1, v1, pos, "in the left operand of the update (//) operator");
state.evalAttrs(env, *e2, v2, pos, "in the right operand of the update (//) operator");
state.evalAttrs(env, *e1, v1);
state.evalAttrs(env, *e2, v2);
state.ctx.stats.nrOpUpdates++;
@@ -1945,10 +1950,25 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v)
void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v)
{
Value v1; e1->eval(state, env, v1);
Value v2; e2->eval(state, env, v2);
Value * lists[2] = { &v1, &v2 };
state.concatLists(v, 2, lists, pos, "while evaluating one of the elements to concatenate");
state.ctx.stats.nrListConcats++;
/* We don't call into `concatLists` as that loses the position information of the expressions. */
Value v1; state.evalList(env, *e1, v1);
Value v2; state.evalList(env, *e2, v2);
size_t l1 = v1.listSize(), l2 = v2.listSize(), len = l1 + l2;
if (l1 == 0)
v = v2;
else if (l2 == 0)
v = v1;
else {
v = state.ctx.mem.newList(len);
auto out = v.listElems();
std::copy(v1.listElems(), v1.listElems() + l1, out);
std::copy(v2.listElems(), v2.listElems() + l2, out + l1);
}
}
+2 -2
View File
@@ -717,8 +717,8 @@ public:
* type.
*/
inline bool evalBool(Env & env, Expr & e);
inline bool evalBool(Env & env, Expr & e, const PosIdx pos, std::string_view errorCtx);
inline void evalAttrs(Env & env, Expr & e, Value & v, const PosIdx pos, std::string_view errorCtx);
inline void evalAttrs(Env & env, Expr & e, Value & v);
inline void evalList(Env & env, Expr & e, Value & v);
/**
* If `v` is a thunk, enter it and overwrite `v` with the result
@@ -1,4 +1,19 @@
error: infinite recursion encountered
error:
… while evaluating x
at /pwd/lang/eval-fail-blackhole.nix:5:1:
4| in
5| x
| ^
6|
… while evaluating y
at /pwd/lang/eval-fail-blackhole.nix:2:7:
1| let
2| x = y;
| ^
3| y = x;
error: infinite recursion encountered
at /pwd/lang/eval-fail-blackhole.nix:2:7:
1| let
2| x = y;
+3 -6
View File
@@ -1,8 +1,5 @@
error:
… while evaluating one of the elements to concatenate
at /pwd/lang/eval-fail-list.nix:1:2:
error: expected a list but found an integer: 8
at /pwd/lang/eval-fail-list.nix:1:1:
1| 8++1
| ^
| ^
2|
error: expected a list but found an integer: 8
@@ -1,10 +1,4 @@
error:
… in the argument of the not operator
at /pwd/lang/eval-fail-not-throws.nix:1:1:
1| ! (throw "uh oh!")
| ^
2|
… caused by explicit throw
at /pwd/lang/eval-fail-not-throws.nix:1:4:
1| ! (throw "uh oh!")
@@ -1,12 +1,6 @@
error:
… in the condition of the assert statement
at /pwd/lang/eval-fail-print-limit-list.nix:1:1:
error: expected a Boolean but found a list: [ 1 [ 2 3 4 5 6 7 8 9 [ 1 «2 items elided» ] «2 items elided» ] «1 item elided» ]
at /pwd/lang/eval-fail-print-limit-list.nix:2:3:
1| assert (
| ^
2| let x = [ 1 [ 2 3 4 5 6 7 8 9 x 10 11 ] 12 ];
error: expected a Boolean but found a list: [ 1 [ 2 3 4 5 6 7 8 9 [ 1 «2 items elided» ] «2 items elided» ] «1 item elided» ]
at /pwd/lang/eval-fail-print-limit-list.nix:1:1:
1| assert (
| ^
2| let x = [ 1 [ 2 3 4 5 6 7 8 9 x 10 11 ] 12 ];
| ^
3| in builtins.deepSeq x x
@@ -1,12 +1,6 @@
error:
… in the condition of the assert statement
at /pwd/lang/eval-fail-print-limit-set.nix:1:1:
error: expected a Boolean but found a set: { a = { a = { a = { a = { a = { a = { a = { a = { a = { a = { ... }; b = 2; }; }; }; }; }; }; }; }; «1 attribute elided» }; «1 attribute elided» }
at /pwd/lang/eval-fail-print-limit-set.nix:2:3:
1| assert (
| ^
2| let x = { a.a.a.a.a.a.a.a.a = { a.a = 1; b = 2; }; a.b.c.x = 3; c = 4; };
error: expected a Boolean but found a set: { a = { a = { a = { a = { a = { a = { a = { a = { a = { a = { ... }; b = 2; }; }; }; }; }; }; }; }; «1 attribute elided» }; «1 attribute elided» }
at /pwd/lang/eval-fail-print-limit-set.nix:1:1:
1| assert (
| ^
2| let x = { a.a.a.a.a.a.a.a.a = { a.a = 1; b = 2; }; a.b.c.x = 3; c = 4; };
| ^
3| in builtins.deepSeq x x
@@ -5,10 +5,16 @@ error:
| ^
2|
in the right operand of the update (//) operator
at /pwd/lang/eval-fail-recursion.nix:1:12:
while evaluating a
at /pwd/lang/eval-fail-recursion.nix:1:21:
1| let a = {} // a; in a.foo
| ^
| ^
2|
… while evaluating a
at /pwd/lang/eval-fail-recursion.nix:1:15:
1| let a = {} // a; in a.foo
| ^
2|
error: infinite recursion encountered
@@ -13,6 +13,20 @@ error:
| ^
6| in
… while evaluating x
at /pwd/lang/eval-fail-scope-5.nix:5:23:
4|
5| f = {x ? y, y ? x}: x + y;
| ^
6| in
… while evaluating y
at /pwd/lang/eval-fail-scope-5.nix:5:12:
4|
5| f = {x ? y, y ? x}: x + y;
| ^
6| in
error: infinite recursion encountered
at /pwd/lang/eval-fail-scope-5.nix:5:12:
4|
@@ -20,6 +20,13 @@ We expect to be able to see locals like r in the debugger:
error:
… while evaluating the file '$TEST_DATA/regression_9918.nix':
… while evaluating x
at $TEST_DATA/regression_9918.nix:5:3:
4| in
5| x
| ^
6|
… while calling the 'throw' builtin
at $TEST_DATA/regression_9918.nix:3:7:
2| r = [];
@@ -27,6 +34,6 @@ We expect to be able to see locals like r in the debugger:
| ^
4| in
… while evaluating the error message passed to builtin.throw
(stack trace truncated; use '--show-trace' to show the full trace)
error: cannot coerce a list to a string: [ ]
@@ -16,6 +16,13 @@ debugger should not crash now, but also not show any with variables
error:
… while evaluating the file '$TEST_DATA/regression_l145.nix':
… while evaluating variable x
at $TEST_DATA/regression_l145.nix:5:3:
4| in
5| x
| ^
6|
… while calling the 'break' builtin
at $TEST_DATA/regression_l145.nix:3:7:
2| let
@@ -3,19 +3,19 @@
@args ${PWD}/extra_data/repl-overlay-fail.nix
@should-start false
error:
… while calling the 'foldl'' builtin
at «string»:5:13:
4| functions:
5| let final = builtins.foldl'
| ^
6| (prev: function: prev // (function info final prev))
… while evaluating variable final
at «string»:6:1:
5| in
6| final
| ^
7|
in the right operand of the update (//) operator
at «string»:6:37:
5| let final = builtins.foldl'
6| (prev: function: prev // (function info final prev))
| ^
7| initial
while calling the 'foldl'' builtin
at «string»:4:11:
3| let
4| final = builtins.foldl' (prev: function: prev // (function info final prev)) initial functions;
| ^
5| in
(stack trace truncated; use '--show-trace' to show the full trace)
+2 -3
View File
@@ -779,10 +779,9 @@ namespace nix {
TypeError,
HintFmt("attempt to call something which is not a function but %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)));
ASSERT_TRACE2("foldl' (a: b: a && b) \"foo\" [ true ]",
ASSERT_TRACE1("foldl' (a: b: a && b) \"foo\" [ true ]",
TypeError,
HintFmt("expected a Boolean but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)),
HintFmt("in the left operand of the AND (&&) operator"));
HintFmt("expected a Boolean but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)));
}