diff options
author | Vincent Ambo <mail@tazj.in> | 2022-09-01T16·13+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-09-07T20·04+0000 |
commit | 6cbd580ba53885d6c4dff1e3a81406604ae13f3a (patch) | |
tree | c896f755fb383ff2619f592ed3d3a7e9aab748fe | |
parent | 1ea88fcb6587c110acd8c798a5c198b492e04bad (diff) |
feat(tvix/eval): track source spans for `OpForce` instructions r/4735
These source spans will always point to the *value* that is being forced, not the instruction that caused the force to be emitted. This makes sense so that errors during forcing point at the value and not the surrounding expression. Change-Id: I4694414a3281a0de878f71634105b92148ec61f6 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6402 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
-rw-r--r-- | tvix/eval/src/compiler/mod.rs | 46 |
1 files changed, 23 insertions, 23 deletions
diff --git a/tvix/eval/src/compiler/mod.rs b/tvix/eval/src/compiler/mod.rs index 09123d3a99fb..faeee3dd5723 100644 --- a/tvix/eval/src/compiler/mod.rs +++ b/tvix/eval/src/compiler/mod.rs @@ -251,7 +251,7 @@ impl Compiler<'_> { fn compile_unary_op(&mut self, slot: Option<LocalIdx>, op: ast::UnaryOp) { self.compile(slot, op.expr().unwrap()); - self.emit_force(); + self.emit_force(&op); let opcode = match op.operator().unwrap() { ast::UnaryOpKind::Invert => OpCode::OpInvert, @@ -280,10 +280,10 @@ impl Compiler<'_> { // the stack in the correct order before pushing the // instruction for the operation itself. self.compile(slot, op.lhs().unwrap()); - self.emit_force(); + self.emit_force(&op.lhs().unwrap()); self.compile(slot, op.rhs().unwrap()); - self.emit_force(); + self.emit_force(&op.rhs().unwrap()); match op.operator().unwrap() { BinOpKind::Add => self.push_op(OpCode::OpAdd, &op), @@ -319,7 +319,7 @@ impl Compiler<'_> { // Leave left-hand side value on the stack. self.compile(slot, node.lhs().unwrap()); - self.emit_force(); + self.emit_force(&node.lhs().unwrap()); // If this value is false, jump over the right-hand side - the // whole expression is false. @@ -330,7 +330,7 @@ impl Compiler<'_> { // of the whole expression. self.push_op(OpCode::OpPop, &node); self.compile(slot, node.rhs().unwrap()); - self.emit_force(); + self.emit_force(&node.rhs().unwrap()); self.patch_jump(end_idx); self.push_op(OpCode::OpAssertBool, &node); @@ -345,14 +345,14 @@ impl Compiler<'_> { // Leave left-hand side value on the stack self.compile(slot, node.lhs().unwrap()); - self.emit_force(); + self.emit_force(&node.lhs().unwrap()); // Opposite of above: If this value is **true**, we can // short-circuit the right-hand side. let end_idx = self.push_op(OpCode::OpJumpIfTrue(JumpOffset(0)), &node); self.push_op(OpCode::OpPop, &node); self.compile(slot, node.rhs().unwrap()); - self.emit_force(); + self.emit_force(&node.rhs().unwrap()); self.patch_jump(end_idx); self.push_op(OpCode::OpAssertBool, &node); @@ -367,14 +367,14 @@ impl Compiler<'_> { // Leave left-hand side value on the stack and invert it. self.compile(slot, node.lhs().unwrap()); - self.emit_force(); + self.emit_force(&node.lhs().unwrap()); self.push_op(OpCode::OpInvert, &node); // Exactly as `||` (because `a -> b` = `!a || b`). let end_idx = self.push_op(OpCode::OpJumpIfTrue(JumpOffset(0)), &node); self.push_op(OpCode::OpPop, &node); self.compile(slot, node.rhs().unwrap()); - self.emit_force(); + self.emit_force(&node.rhs().unwrap()); self.patch_jump(end_idx); self.push_op(OpCode::OpAssertBool, &node); @@ -403,12 +403,12 @@ impl Compiler<'_> { match node { ast::Attr::Dynamic(dynamic) => { self.compile(slot, dynamic.expr().unwrap()); - self.emit_force(); + self.emit_force(&dynamic.expr().unwrap()); } ast::Attr::Str(s) => { - self.compile_str(slot, s); - self.emit_force(); + self.compile_str(slot, s.clone()); + self.emit_force(&s); } ast::Attr::Ident(ident) => self.emit_literal_ident(&ident), @@ -469,7 +469,7 @@ impl Compiler<'_> { // than pushing/popping the same attrs // potentially a lot of times. self.compile(slot, from.expr().unwrap()); - self.emit_force(); + self.emit_force(&from.expr().unwrap()); self.emit_literal_ident(&ident); self.push_op(OpCode::OpAttrsSelect, &ident); } @@ -532,8 +532,8 @@ impl Compiler<'_> { } // Push the set onto the stack - self.compile(slot, set); - self.emit_force(); + self.compile(slot, set.clone()); + self.emit_force(&set); // Compile each key fragment and emit access instructions. // @@ -581,8 +581,8 @@ impl Compiler<'_> { path: ast::Attrpath, default: ast::Expr, ) { - self.compile(slot, set); - self.emit_force(); + self.compile(slot, set.clone()); + self.emit_force(&set); let mut jumps = vec![]; for fragment in path.attrs() { @@ -686,7 +686,7 @@ impl Compiler<'_> { Some(from) => { for ident in inherit.idents() { self.compile(slot, from.expr().unwrap()); - self.emit_force(); + self.emit_force(&from.expr().unwrap()); self.emit_literal_ident(&ident); self.push_op(OpCode::OpAttrsSelect, &ident); @@ -836,7 +836,7 @@ impl Compiler<'_> { // resolve that directly (thus avoiding duplication on the // stack). self.compile(slot, node.namespace().unwrap()); - self.emit_force(); + self.emit_force(&node.namespace().unwrap()); let local_idx = self.scope_mut().declare_phantom(); let with_idx = self.scope().stack_index(local_idx); @@ -1224,8 +1224,8 @@ impl Compiler<'_> { idx } - fn emit_force(&mut self) { - self.push_op_old(OpCode::OpForce); + fn emit_force<N: AstNode>(&mut self, node: &N) { + self.push_op(OpCode::OpForce, node); } fn emit_warning(&mut self, node: rnix::SyntaxNode, kind: WarningKind) { @@ -1350,13 +1350,13 @@ pub fn compile<'code>( errors: vec![], }; - c.compile(None, expr); + c.compile(None, expr.clone()); // The final operation of any top-level Nix program must always be // `OpForce`. A thunk should not be returned to the user in an // unevaluated state (though in practice, a value *containing* a // thunk might be returned). - c.emit_force(); + c.emit_force(&expr); Ok(CompilationOutput { lambda: c.contexts.pop().unwrap().lambda, |