diff options
author | Vincent Ambo <mail@tazj.in> | 2023-03-20T22·13+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2023-03-27T09·02+0000 |
commit | 2d305fd5b37fa7bf5a0512e8992b4557a1745296 (patch) | |
tree | 5f554ecb08ce097864f7d2f420bf96d08bbc7c96 /tvix/eval | |
parent | 367a5e9922264b787667fd5e750c8eadf8a7796f (diff) |
refactor(tvix/eval): retain call frames when entering calls r/6045
This grows the frame stack as the call stack grows, which yields *much* better user-facing error messages. I haven't measured the performance impact this has yet, for now I'm still just trying to add more information to errors and then cut down again where necessary. Change-Id: I89f058ef31979edacf4667775d460b60704ce4d7 Reviewed-on: https://cl.tvl.fyi/c/depot/+/8334 Reviewed-by: flokli <flokli@flokli.de> Tested-by: BuildkiteCI Autosubmit: tazjin <tazjin@tvl.su>
Diffstat (limited to 'tvix/eval')
-rw-r--r-- | tvix/eval/src/vm/mod.rs | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/tvix/eval/src/vm/mod.rs b/tvix/eval/src/vm/mod.rs index 13158619c69b..81c9ef39d94d 100644 --- a/tvix/eval/src/vm/mod.rs +++ b/tvix/eval/src/vm/mod.rs @@ -508,7 +508,7 @@ impl<'o> VM<'o> { OpCode::OpCall => { let callable = self.stack_pop(); - self.call_value(frame.current_light_span(), Some(frame), callable)?; + self.call_value(frame.current_light_span(), Some((span, frame)), callable)?; // exit this loop and let the outer loop enter the new call return Ok(true); @@ -985,7 +985,7 @@ impl<'o> VM<'o> { fn call_value( &mut self, span: LightSpan, - parent: Option<CallFrame>, + parent: Option<(LightSpan, CallFrame)>, callable: Value, ) -> EvalResult<()> { match callable { @@ -1002,6 +1002,13 @@ impl<'o> VM<'o> { // `stack_len - 1`. let stack_offset = self.stack.len() - 1; + // Reenqueue the parent frame, which should only have + // `OpReturn` left. Not throwing it away leads to more + // useful error traces. + if let Some((parent_span, parent_frame)) = parent { + self.push_call_frame(parent_span, parent_frame); + } + self.push_call_frame( span, CallFrame { @@ -1017,11 +1024,11 @@ impl<'o> VM<'o> { // Attribute sets with a __functor attribute are callable. val @ Value::Attrs(_) => { - let gen_span = parent - .map(|p| p.current_light_span()) - .unwrap_or_else(|| self.reasonable_light_span()); + if let Some((parent_span, parent_frame)) = parent { + self.push_call_frame(parent_span, parent_frame); + } - self.enqueue_generator("__functor call", gen_span, |co| call_functor(co, val)); + self.enqueue_generator("__functor call", span, |co| call_functor(co, val)); Ok(()) } v => Err(ErrorKind::NotCallable(v.type_of())).with_span(&span, self), |