refactor(tvix/eval): retain call frames when entering calls
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>
This commit is contained in:
parent
367a5e9922
commit
2d305fd5b3
1 changed files with 13 additions and 6 deletions
|
@ -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),
|
||||
|
|
Loading…
Reference in a new issue