lix/doc/manual/rl-next/distinguish-throw-errors.md
Qyriad 4c7165be86 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
2024-07-04 17:43:03 -06:00

2.2 KiB

synopsis cls credits category
Distinguish between explicit throws and errors that happened while evaluating a throw 1511 Qyriad Improvements

Previously, errors caused by an expression like throw "invalid argument" were treated like an error that happened simply while some builtin function was being called:

let
  throwMsg = p: throw "${p} isn't the right package";
in throwMsg "linuz"

error:
       … while calling the 'throw' builtin
         at «string»:2:17:
            1| let
            2|   throwMsg = p: throw "${p} isn't the right package";
             |                 ^
            3| in throwMsg "linuz"

       error: linuz isn't the right package

But the error didn't just happen "while" calling the throw builtin — it's a throw error! Now it looks like this:

let
  throwMsg = p: throw "${p} isn't the right package";
in throwMsg "linuz"

error:
       … caused by explicit throw
         at «string»:2:17:
            1| let
            2|   throwMsg = p: throw "${p} isn't the right package";
             |                 ^
            3| in throwMsg "linuz"

       error: linuz isn't the right package

This also means that incorrect usage of throw or errors evaluating its arguments are easily distinguishable from explicit throws:

let
  throwMsg = p: throw "${p} isn't the right package";
in throwMsg { attrs = "error when coerced in string interpolation"; }

error:
       … while calling the 'throw' builtin
         at «string»:2:17:
            1| let
            2|   throwMsg = p: throw "${p} isn't the right package";
             |                 ^
            3| in throwMsg { attrs = "error when coerced in string interpolation"; }

       … while evaluating a path segment
         at «string»:2:24:
            1| let
            2|   throwMsg = p: throw "${p} isn't the right package";
             |                        ^
            3| in throwMsg { attrs = "error when coerced in string interpolation"; }

       error: cannot coerce a set to a string: { attrs = "error when coerced in string interpolation"; }

Here, instead of an actual thrown error, a type error happens first (trying to coerce an attribute set to a string), but that type error happened while calling throw.