about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-08-28T20·44+0300
committertazjin <tazjin@tvl.su>2022-09-06T14·58+0000
commit49296cebe3c1b5644e24f6c3017a75db7c85683d (patch)
treefe964b108a076afc3f2e0a4a028b989a55714703
parent70b27a608090b29b6ae8e455d8f18c7099b2b39d (diff)
refactor(tvix/eval): extract compiler's upvalue logic into helper r/4672
This exact same logic is reused for thunk creation.

Change-Id: I731db9cc659a1f2ca87db55d58d6ff632f417812
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6342
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
-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.