distinguish between throws & errors during throw

Turns errors like this:

let
  throwMsg = a: throw (a + " invalid bar");
in throwMsg "bullshit"

error:
       … from call site
         at «string»:3:4:
            2|   throwMsg = a: throw (a + " invalid bar");
            3| in throwMsg "bullshit"
             |    ^

       … while calling 'throwMsg'
         at «string»:2:14:
            1| let
            2|   throwMsg = a: throw (a + " invalid bar");
             |              ^
            3| in throwMsg "bullshit"

       … while calling the 'throw' builtin
         at «string»:2:17:
            1| let
            2|   throwMsg = a: throw (a + " invalid bar");
             |                 ^
            3| in throwMsg "bullshit"

       error: bullshit invalid bar

into errors like this:

let
  throwMsg = a: throw (a + " invalid bar");
in throwMsg "bullshit"

error:
       … from call site
         at «string»:3:4:
            2|   throwMsg = a: throw (a + " invalid bar");
            3| in throwMsg "bullshit"
             |    ^

       … while calling 'throwMsg'
         at «string»:2:14:
            1| let
            2|   throwMsg = a: throw (a + " invalid bar");
             |              ^
            3| in throwMsg "bullshit"

       … caused by explicit throw
         at «string»:2:17:
            1| let
            2|   throwMsg = a: throw (a + " invalid bar");
             |                 ^
            3| in throwMsg "bullshit"

       error: bullshit invalid bar

Change-Id: I593688928ece20f97999d1bf03b2b46d9ac338cb
This commit is contained in:
Qyriad 2024-06-24 17:26:21 -06:00
parent 65535edf94
commit 09eccdcbd5
7 changed files with 15 additions and 6 deletions

View file

@ -1807,6 +1807,15 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
try {
fn->fun(*this, vCur.determinePos(noPos), args, vCur);
} catch (ThrownError & e) {
// Distinguish between an error that simply happened while "throw"
// was being evaluated and an explicit thrown error.
if (fn->name == "throw") {
addErrorTrace(e, pos, "caused by explicit %s", "throw");
} else {
addErrorTrace(e, pos, "while calling the '%s' builtin", fn->name);
}
throw;
} catch (Error & e) {
addErrorTrace(e, pos, "while calling the '%1%' builtin", fn->name);
throw;

View file

@ -25,7 +25,7 @@ nix eval -E 'assert 1 + 2 == 3; true'
# Top-level eval errors should be printed to stderr with a traceback.
topLevelThrow="$(expectStderr 1 nix eval --expr 'throw "a sample throw message"')"
[[ "$topLevelThrow" =~ "a sample throw message" ]]
[[ "$topLevelThrow" =~ "while calling the 'throw' builtin" ]]
[[ "$topLevelThrow" =~ "caused by explicit throw" ]]
# But errors inside something should print an elided version, and exit with 0.
outputOfNestedThrow="$(nix eval --expr '{ throws = throw "a sample throw message"; }')"

View file

@ -41,7 +41,7 @@ error:
| ^
5| if n > 0
while calling the 'throw' builtin
caused by explicit throw
at /pwd/lang/eval-fail-duplicate-traces.nix:7:10:
6| then throwAfter (n - 1)
7| else throw "Uh oh!";

View file

@ -27,7 +27,7 @@ error:
| ^
6|
while calling the 'throw' builtin
caused by explicit throw
at /pwd/lang/eval-fail-foldlStrict-strict-op-application.nix:5:9:
4| null
5| [ (_: throw "Not the final value, but is still forced!") (_: 23) ]

View file

@ -54,7 +54,7 @@ error:
(21 duplicate frames omitted)
while calling the 'throw' builtin
caused by explicit throw
at /pwd/lang/eval-fail-mutual-recursion.nix:34:10:
33| then throwAfterB true 10
34| else throw "Uh oh!";

View file

@ -5,7 +5,7 @@ error:
| ^
2|
while calling the 'throw' builtin
caused by explicit throw
at /pwd/lang/eval-fail-not-throws.nix:1:4:
1| ! (throw "uh oh!")
| ^

View file

@ -40,7 +40,7 @@ error:
| ^
8| }
while calling the 'throw' builtin
caused by explicit throw
at /pwd/lang/eval-fail-toJSON.nix:7:13:
6| {
7| c.d = throw "hah no";