diff options
author | Vincent Ambo <mail@tazj.in> | 2022-08-27T19·58+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-09-06T07·29+0000 |
commit | ae531a2245e83d44ce58ba6c588713265984dbbf (patch) | |
tree | 64b32c14b9bd8ed6db4f24407e58f785a15c2f2b /tvix/eval/src/vm.rs | |
parent | 06b07f5c47cacca7c3e2d265ba23701f99ceabdf (diff) |
feat(tvix/eval): implement capture of self-recursive upvalues r/4653
With this change, it becomes possible for functions to call themselves as they are being defined in local bindings. Change-Id: Ib46a39ba17b1452b5673d96fa729d633d237241a Reviewed-on: https://cl.tvl.fyi/c/depot/+/6314 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
Diffstat (limited to 'tvix/eval/src/vm.rs')
-rw-r--r-- | tvix/eval/src/vm.rs | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs index 527f58ddc8d6..5b6536e98664 100644 --- a/tvix/eval/src/vm.rs +++ b/tvix/eval/src/vm.rs @@ -359,7 +359,15 @@ impl VM { } OpCode::OpClosure(idx) => { - let closure = self.chunk().constant(idx).clone().to_closure()?; + let value = self.chunk().constant(idx).clone(); + self.push(value.clone()); + + // This refers to the same Rc, and from this point + // on internally mutates the closure objects + // upvalues. The closure is already in its stack + // slot, which means that it can capture itself as + // an upvalue for self-recursion. + let closure = value.to_closure()?; debug_assert!( closure.upvalue_count() > 0, @@ -387,8 +395,6 @@ impl VM { _ => panic!("compiler error: missing closure operand"), } } - - self.push(Value::Closure(closure)); } // Data-carrying operands should never be executed, |