From e79278b4fcbc5da5a0213b784741c1202ff899e0 Mon Sep 17 00:00:00 2001 From: skye Date: Fri, 3 Apr 2026 18:24:27 -0400 Subject: [PATCH] Check for throw while evaluating throw message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a small tweak to the logic added in cl/1511 to detect explicit throws when printing stack traces. Now when deciding whether to print "caused by explicit throw", it checks not only that the error is a ThrowError and that we are in a throw, but also that the ThrowError was thrown by *this* throw, and not by another while in the process of evaluating this throw's operand. It turns this: ``` let set = { inner = throw "nested throw"; }; in throw set.inner error: … caused by explicit throw at /pwd/in.nix:6:1: 5| in 6| throw set.inner | ^ 7| … while evaluating the attribute 'inner' at /pwd/in.nix:3:5: 2| set = { 3| inner = throw "nested throw"; | ^ 4| }; … caused by explicit throw at /pwd/in.nix:3:13: 2| set = { 3| inner = throw "nested throw"; | ^ 4| }; error: nested throw ``` into this: ``` error: … while calling the 'throw' builtin at /pwd/in.nix:6:1: 5| in 6| throw set.inner | ^ 7| … while evaluating the attribute 'inner' at /pwd/in.nix:3:5: 2| set = { 3| inner = throw "nested throw"; | ^ 4| }; … caused by explicit throw at /pwd/in.nix:3:13: 2| set = { 3| inner = throw "nested throw"; | ^ 4| }; error: nested throw ``` Notice the difference in the top context frame. Before it incorrectly attributed the throw error to the both throws instead of just the one that actually threw. Change-Id: If3b0b8311f1ae2ff1471e260fe59d9166a6a6964 --- lix/libexpr/eval.cc | 2 +- .../lang/select-err/eval-fail-2.err.exp | 23 +++++++++++++++++++ tests/functional2/lang/select-err/in-2.nix | 6 +++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/functional2/lang/select-err/eval-fail-2.err.exp create mode 100644 tests/functional2/lang/select-err/in-2.nix diff --git a/lix/libexpr/eval.cc b/lix/libexpr/eval.cc index d3f203748..4882199f4 100644 --- a/lix/libexpr/eval.cc +++ b/lix/libexpr/eval.cc @@ -1206,7 +1206,7 @@ Value EvalState::callFunction(Value & fun, std::span args, const PosIdx p } catch (ThrownError & e) { // Distinguish between an error that simply happened while "throw" // was being evaluated and an explicit thrown error. - if (fn->name == "throw") { + if (fn->name == "throw" && !e.hasTrace()) { e.addTrace(ctx.positions[pos], "caused by explicit %s", "throw"); } else { e.addTrace(ctx.positions[pos], "while calling the '%s' builtin", fn->name); diff --git a/tests/functional2/lang/select-err/eval-fail-2.err.exp b/tests/functional2/lang/select-err/eval-fail-2.err.exp new file mode 100644 index 000000000..6ed4d7594 --- /dev/null +++ b/tests/functional2/lang/select-err/eval-fail-2.err.exp @@ -0,0 +1,23 @@ +error: + … while calling the 'throw' builtin + at /pwd/in.nix:6:1: + 5| in + 6| throw set.inner + | ^ + 7| + + … while evaluating the attribute 'inner' + at /pwd/in.nix:3:5: + 2| set = { + 3| inner = throw "nested throw"; + | ^ + 4| }; + + … caused by explicit throw + at /pwd/in.nix:3:13: + 2| set = { + 3| inner = throw "nested throw"; + | ^ + 4| }; + + error: nested throw diff --git a/tests/functional2/lang/select-err/in-2.nix b/tests/functional2/lang/select-err/in-2.nix new file mode 100644 index 000000000..2d4319ed2 --- /dev/null +++ b/tests/functional2/lang/select-err/in-2.nix @@ -0,0 +1,6 @@ +let + set = { + inner = throw "nested throw"; + }; +in +throw set.inner