diff options
author | Vincent Ambo <mail@tazj.in> | 2022-08-28T21·11+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-09-06T14·58+0000 |
commit | 28a9847c65e316fdb97c1bcb79f48cb0114724af (patch) | |
tree | eb1f917c087a1247f3d951bb96e8d5509fa0bd0d /tvix/eval/src/compiler | |
parent | d1798444bec692a608aa93605cbe449d985c3e16 (diff) |
feat(tvix/eval): emit thunks for recursive local scope resolution r/4675
When resolving a value on the same level that is known but not yet defined, emit a thunk. Consider for example: let # v--- requires a thunk a = 1 * b; b = 10; in a Change-Id: I922cb50973ebe05e335a7bc7cb851960cf34733b Reviewed-on: https://cl.tvl.fyi/c/depot/+/6345 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
Diffstat (limited to 'tvix/eval/src/compiler')
-rw-r--r-- | tvix/eval/src/compiler/mod.rs | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/tvix/eval/src/compiler/mod.rs b/tvix/eval/src/compiler/mod.rs index 7c20307b843b..a1f11501a449 100644 --- a/tvix/eval/src/compiler/mod.rs +++ b/tvix/eval/src/compiler/mod.rs @@ -120,7 +120,7 @@ impl Compiler { ast::Expr::Assert(assert) => self.compile_assert(assert), ast::Expr::IfElse(if_else) => self.compile_if_else(if_else), ast::Expr::LetIn(let_in) => self.compile_let_in(let_in), - ast::Expr::Ident(ident) => self.compile_ident(ident), + ast::Expr::Ident(ident) => self.compile_ident(slot, ident), ast::Expr::With(with) => self.compile_with(with), ast::Expr::Lambda(lambda) => self.compile_lambda(slot, lambda), ast::Expr::Apply(apply) => self.compile_apply(apply), @@ -620,7 +620,7 @@ impl Compiler { continue; } - self.compile_ident(ident.clone()); + self.compile_ident(None, ident.clone()); let idx = self.declare_local( ident.syntax().clone(), ident.ident_token().unwrap().text(), @@ -702,7 +702,7 @@ impl Compiler { self.end_scope(); } - fn compile_ident(&mut self, node: ast::Ident) { + fn compile_ident(&mut self, slot: Option<LocalIdx>, node: ast::Ident) { let ident = node.ident_token().unwrap(); // If the identifier is a global, and it is not poisoned, emit @@ -747,15 +747,22 @@ impl Compiler { // Variable needs to be dynamically resolved at // runtime. self.emit_constant(Value::String(ident.text().into())); - self.chunk().push_op(OpCode::OpResolveWith) + self.chunk().push_op(OpCode::OpResolveWith); } LocalPosition::Known(idx) => { let stack_idx = self.scope().stack_index(idx); - self.chunk().push_op(OpCode::OpGetLocal(stack_idx)) + self.chunk().push_op(OpCode::OpGetLocal(stack_idx)); } - LocalPosition::Recursive(_) => panic!("TODO: unclear if this can happen"), + // This identifier is referring to a value from the same + // scope which is not yet defined. This identifier access + // must be thunked. + LocalPosition::Recursive(idx) => self.thunk(slot, move |compiler, _| { + let upvalue_idx = + compiler.add_upvalue(compiler.contexts.len() - 1, Upvalue::Local(idx)); + compiler.chunk().push_op(OpCode::OpGetUpvalue(upvalue_idx)); + }), }; } |