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.rs34
1 files changed, 20 insertions, 14 deletions
diff --git a/tvix/eval/src/compiler/mod.rs b/tvix/eval/src/compiler/mod.rs
index 3f11661a97..c9cd66aca7 100644
--- a/tvix/eval/src/compiler/mod.rs
+++ b/tvix/eval/src/compiler/mod.rs
@@ -657,7 +657,7 @@ impl Compiler {
 
         // First pass to ensure that all identifiers are known;
         // required for resolving recursion.
-        let mut entries: Vec<(LocalIdx, rnix::ast::Expr)> = vec![];
+        let mut entries: Vec<(LocalIdx, ast::Expr)> = vec![];
         for entry in node.attrpath_values() {
             let mut path = match normalise_ident_path(entry.attrpath().unwrap().attrs()) {
                 Ok(p) => p,
@@ -830,12 +830,28 @@ impl Compiler {
         // number of operands that allow the runtime to close over the
         // upvalues and leave a blueprint in the constant index from
         // which the runtime closure can be constructed.
-        let closure_idx = self
+        let blueprint_idx = self
             .chunk()
             .push_constant(Value::Blueprint(Rc::new(compiled.lambda)));
 
-        self.chunk().push_op(OpCode::OpClosure(closure_idx));
-        for upvalue in compiled.scope.upvalues {
+        self.chunk().push_op(OpCode::OpClosure(blueprint_idx));
+        self.emit_upvalue_data(slot, compiled.scope.upvalues);
+    }
+
+    fn compile_apply(&mut self, node: ast::Apply) {
+        // To call a function, we leave its arguments on the stack,
+        // followed by the function expression itself, and then emit a
+        // call instruction. This way, the stack is perfectly laid out
+        // to enter the function call straight away.
+        self.compile(None, node.argument().unwrap());
+        self.compile(None, node.lambda().unwrap());
+        self.chunk().push_op(OpCode::OpCall);
+    }
+
+    /// Emit the data instructions that the runtime needs to correctly
+    /// assemble the provided upvalues array.
+    fn emit_upvalue_data(&mut self, slot: Option<LocalIdx>, upvalues: Vec<Upvalue>) {
+        for upvalue in upvalues {
             match upvalue {
                 Upvalue::Local(idx) if slot.is_none() => {
                     let stack_idx = self.scope().stack_index(idx);
@@ -871,16 +887,6 @@ impl Compiler {
         }
     }
 
-    fn compile_apply(&mut self, node: ast::Apply) {
-        // To call a function, we leave its arguments on the stack,
-        // followed by the function expression itself, and then emit a
-        // call instruction. This way, the stack is perfectly laid out
-        // to enter the function call straight away.
-        self.compile(None, node.argument().unwrap());
-        self.compile(None, node.lambda().unwrap());
-        self.chunk().push_op(OpCode::OpCall);
-    }
-
     /// Emit the literal string value of an identifier. Required for
     /// several operations related to attribute sets, where
     /// identifiers are used as string keys.