about summary refs log tree commit diff
path: root/tvix/eval
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-09-03T01·05+0300
committertazjin <tazjin@tvl.su>2022-09-08T20·17+0000
commitfe047885d75a97bd303176847db7fdb2a781344d (patch)
tree9b4bef7f2b00c8ce2bc815a73ce68bc63f846e18 /tvix/eval
parent360c805efc8f0d4a6f6631fc229c09d8dea8a216 (diff)
fix(tvix/eval): consider local depth when deciding to defer r/4762
Deferred local upvalues can *only* occur at the same depth as the
thing that is closing over them, but there are various situations with
scope nesting where the actual stack indexes of the local and the
closer look like a deferred value is being accessed.

To fix this, simply compare the depth as well.

Change-Id: Ice77424cc87ab0a2c4f01379e68d4399a917b12b
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6429
Reviewed-by: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/eval')
-rw-r--r--tvix/eval/src/compiler/mod.rs13
-rw-r--r--tvix/eval/src/tests/tvix_tests/eval-okay-toplevel-finaliser.exp1
-rw-r--r--tvix/eval/src/tests/tvix_tests/eval-okay-toplevel-finaliser.nix10
3 files changed, 19 insertions, 5 deletions
diff --git a/tvix/eval/src/compiler/mod.rs b/tvix/eval/src/compiler/mod.rs
index 731ba9179c..f9a2dd32c8 100644
--- a/tvix/eval/src/compiler/mod.rs
+++ b/tvix/eval/src/compiler/mod.rs
@@ -973,17 +973,20 @@ impl Compiler<'_> {
     /// Emit the data instructions that the runtime needs to correctly
     /// assemble the provided upvalues array.
     fn emit_upvalue_data(&mut self, slot: LocalIdx, upvalues: Vec<Upvalue>) {
+        let this_depth = self.scope()[slot].depth;
         let this_stack_slot = self.scope().stack_index(slot);
+
         for upvalue in upvalues {
             match upvalue.kind {
                 UpvalueKind::Local(idx) => {
+                    let target_depth = self.scope()[idx].depth;
                     let stack_idx = self.scope().stack_index(idx);
 
-                    // If the upvalue slot is located *after* the
-                    // closure, the upvalue resolution must be
-                    // deferred until the scope is fully initialised
-                    // and can be finalised.
-                    if this_stack_slot < stack_idx {
+                    // If the upvalue slot is located at the same
+                    // depth, but *after* the closure, the upvalue
+                    // resolution must be deferred until the scope is
+                    // fully initialised and can be finalised.
+                    if this_depth == target_depth && this_stack_slot < stack_idx {
                         self.push_op(OpCode::DataDeferredLocal(stack_idx), &upvalue.node);
                         self.scope_mut().mark_needs_finaliser(slot);
                     } else {
diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-toplevel-finaliser.exp b/tvix/eval/src/tests/tvix_tests/eval-okay-toplevel-finaliser.exp
new file mode 100644
index 0000000000..edca9baca9
--- /dev/null
+++ b/tvix/eval/src/tests/tvix_tests/eval-okay-toplevel-finaliser.exp
@@ -0,0 +1 @@
+{ a = 1; b = 2; c = 3; }
diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-toplevel-finaliser.nix b/tvix/eval/src/tests/tvix_tests/eval-okay-toplevel-finaliser.nix
new file mode 100644
index 0000000000..4c6884bec3
--- /dev/null
+++ b/tvix/eval/src/tests/tvix_tests/eval-okay-toplevel-finaliser.nix
@@ -0,0 +1,10 @@
+# A simple expression with upvalue resolution beyond the target stack
+# index of the root expression.
+
+let
+  a = 1;
+  b = 2;
+  c = 3;
+in {
+  inherit a b c;
+}