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 => {
|
OpCode::OpCall => {
|
||||||
let callable = self.stack_pop();
|
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
|
// exit this loop and let the outer loop enter the new call
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
|
@ -985,7 +985,7 @@ impl<'o> VM<'o> {
|
||||||
fn call_value(
|
fn call_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
span: LightSpan,
|
span: LightSpan,
|
||||||
parent: Option<CallFrame>,
|
parent: Option<(LightSpan, CallFrame)>,
|
||||||
callable: Value,
|
callable: Value,
|
||||||
) -> EvalResult<()> {
|
) -> EvalResult<()> {
|
||||||
match callable {
|
match callable {
|
||||||
|
@ -1002,6 +1002,13 @@ impl<'o> VM<'o> {
|
||||||
// `stack_len - 1`.
|
// `stack_len - 1`.
|
||||||
let stack_offset = self.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(
|
self.push_call_frame(
|
||||||
span,
|
span,
|
||||||
CallFrame {
|
CallFrame {
|
||||||
|
@ -1017,11 +1024,11 @@ impl<'o> VM<'o> {
|
||||||
|
|
||||||
// Attribute sets with a __functor attribute are callable.
|
// Attribute sets with a __functor attribute are callable.
|
||||||
val @ Value::Attrs(_) => {
|
val @ Value::Attrs(_) => {
|
||||||
let gen_span = parent
|
if let Some((parent_span, parent_frame)) = parent {
|
||||||
.map(|p| p.current_light_span())
|
self.push_call_frame(parent_span, parent_frame);
|
||||||
.unwrap_or_else(|| self.reasonable_light_span());
|
}
|
||||||
|
|
||||||
self.enqueue_generator("__functor call", gen_span, |co| call_functor(co, val));
|
self.enqueue_generator("__functor call", span, |co| call_functor(co, val));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
v => Err(ErrorKind::NotCallable(v.type_of())).with_span(&span, self),
|
v => Err(ErrorKind::NotCallable(v.type_of())).with_span(&span, self),
|
||||||
|
|
Loading…
Reference in a new issue