about summary refs log tree commit diff
path: root/tvix/eval/src/compiler/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tvix/eval/src/compiler/mod.rs')
-rw-r--r--tvix/eval/src/compiler/mod.rs24
1 files changed, 21 insertions, 3 deletions
diff --git a/tvix/eval/src/compiler/mod.rs b/tvix/eval/src/compiler/mod.rs
index 3ade6831c286..0c41f06cbde1 100644
--- a/tvix/eval/src/compiler/mod.rs
+++ b/tvix/eval/src/compiler/mod.rs
@@ -856,9 +856,27 @@ impl Compiler {
             crate::disassembler::disassemble_chunk(&compiled.lambda.chunk);
         }
 
-        self.emit_constant(Value::Closure(Closure {
-            lambda: compiled.lambda,
-        }));
+        // If the function is not a closure, just emit it directly and
+        // move on.
+        if compiled.lambda.upvalue_count == 0 {
+            self.emit_constant(Value::Closure(Closure::new(compiled.lambda)));
+            return;
+        }
+
+        // If the function is a closure, we need to emit the variable
+        // number of operands that allow the runtime to close over the
+        // upvalues.
+        let closure_idx = self
+            .chunk()
+            .push_constant(Value::Closure(Closure::new(compiled.lambda)));
+
+        self.chunk().push_op(OpCode::OpClosure(closure_idx));
+        for upvalue in compiled.scope.upvalues {
+            match upvalue {
+                Upvalue::Stack(idx) => self.chunk().push_op(OpCode::DataLocalIdx(idx)),
+                Upvalue::Upvalue(idx) => self.chunk().push_op(OpCode::DataUpvalueIdx(idx)),
+            };
+        }
     }
 
     fn compile_apply(&mut self, node: ast::Apply) {