-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
builtins.catchEvalErrors #12705
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
builtins.catchEvalErrors #12705
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -981,6 +981,58 @@ static RegisterPrimOp primop_tryEval({ | |
| .fun = prim_tryEval, | ||
| }); | ||
|
|
||
| /* Similar to `builtins.tryEval` but catches more, `value` attribute provided only on success. */ | ||
| static void prim_catchEvalError(EvalState & state, const PosIdx pos, Value * * args, Value & v) | ||
| { | ||
| auto attrs = state.buildBindings(2); | ||
|
|
||
| /* increment state.trylevel, and decrement it when this function returns. */ | ||
| MaintainCount trylevel(state.trylevel); | ||
|
|
||
| ReplExitStatus (* savedDebugRepl)(ref<EvalState> es, const ValMap & extraEnv) = nullptr; | ||
| if (state.debugRepl && state.settings.ignoreExceptionsDuringTry) | ||
| { | ||
| /* to prevent starting the repl from exceptions withing a tryEval, null it. */ | ||
| savedDebugRepl = state.debugRepl; | ||
| state.debugRepl = nullptr; | ||
| } | ||
|
|
||
| try { | ||
| state.forceValue(*args[0], pos); | ||
| attrs.insert(state.sValue, args[0]); | ||
| attrs.insert(state.symbols.create("success"), &state.vTrue); | ||
| } catch (EvalError & e) { | ||
| attrs.insert(state.symbols.create("success"), &state.vFalse); | ||
| } catch (FileNotFound & e) { | ||
| attrs.insert(state.symbols.create("success"), &state.vFalse); | ||
| } | ||
|
|
||
| // restore the debugRepl pointer if we saved it earlier. | ||
| if (savedDebugRepl) | ||
| state.debugRepl = savedDebugRepl; | ||
|
|
||
| v.mkAttrs(attrs); | ||
| } | ||
|
|
||
| static RegisterPrimOp primop_catchEvalError({ | ||
| .name = "__catchEvalError", | ||
| .args = {"e"}, | ||
| .doc = R"( | ||
| Similar to `builtins.tryEval` except that it catches | ||
| - `throw` | ||
| - `assert` | ||
| - `abort` | ||
| - missing attribute | ||
| - out of bounds indexing | ||
| - file not found such as `import` and `builtins.readFile` | ||
| - deserialization such as `builtins.fromJSON` | ||
| - detectable infinite recursion | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should never be caught since non-termination is undecidable. Our current blackhole detection is "best effort" since it was easy to implement, but for instance it doesn't currently work with the multi-threaded evaluator. |
||
|
|
||
| And that `value` attribute exists only on success. | ||
| )", | ||
| .fun = prim_catchEvalError, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably be gated behind an experimental feature or enabled by a CLI flag, since allowing a general catch-all sounds like it could lead to some really bad antipatterns (especially if Nixpkgs or the NixOS module system starts using it). |
||
| }); | ||
|
|
||
| /* Return an environment variable. Use with care. */ | ||
| static void prim_getEnv(EvalState & state, const PosIdx pos, Value * * args, Value & v) | ||
| { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allowing aborts to be caught is probably going to lead to a
reallyAbortprimop that isn't caught bycatchEvalError...