fix(tvix/eval): consider local depth when deciding to defer
Deferred local upvalues can *only* occur at the same depth as the thing that is closing over them, but there are various situations with scope nesting where the actual stack indexes of the local and the closer look like a deferred value is being accessed. To fix this, simply compare the depth as well. Change-Id: Ice77424cc87ab0a2c4f01379e68d4399a917b12b Reviewed-on: https://cl.tvl.fyi/c/depot/+/6429 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
This commit is contained in:
parent
360c805efc
commit
fe047885d7
3 changed files with 19 additions and 5 deletions
|
@ -973,17 +973,20 @@ impl Compiler<'_> {
|
||||||
/// Emit the data instructions that the runtime needs to correctly
|
/// Emit the data instructions that the runtime needs to correctly
|
||||||
/// assemble the provided upvalues array.
|
/// assemble the provided upvalues array.
|
||||||
fn emit_upvalue_data(&mut self, slot: LocalIdx, upvalues: Vec<Upvalue>) {
|
fn emit_upvalue_data(&mut self, slot: LocalIdx, upvalues: Vec<Upvalue>) {
|
||||||
|
let this_depth = self.scope()[slot].depth;
|
||||||
let this_stack_slot = self.scope().stack_index(slot);
|
let this_stack_slot = self.scope().stack_index(slot);
|
||||||
|
|
||||||
for upvalue in upvalues {
|
for upvalue in upvalues {
|
||||||
match upvalue.kind {
|
match upvalue.kind {
|
||||||
UpvalueKind::Local(idx) => {
|
UpvalueKind::Local(idx) => {
|
||||||
|
let target_depth = self.scope()[idx].depth;
|
||||||
let stack_idx = self.scope().stack_index(idx);
|
let stack_idx = self.scope().stack_index(idx);
|
||||||
|
|
||||||
// If the upvalue slot is located *after* the
|
// If the upvalue slot is located at the same
|
||||||
// closure, the upvalue resolution must be
|
// depth, but *after* the closure, the upvalue
|
||||||
// deferred until the scope is fully initialised
|
// resolution must be deferred until the scope is
|
||||||
// and can be finalised.
|
// fully initialised and can be finalised.
|
||||||
if this_stack_slot < stack_idx {
|
if this_depth == target_depth && this_stack_slot < stack_idx {
|
||||||
self.push_op(OpCode::DataDeferredLocal(stack_idx), &upvalue.node);
|
self.push_op(OpCode::DataDeferredLocal(stack_idx), &upvalue.node);
|
||||||
self.scope_mut().mark_needs_finaliser(slot);
|
self.scope_mut().mark_needs_finaliser(slot);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{ a = 1; b = 2; c = 3; }
|
|
@ -0,0 +1,10 @@
|
||||||
|
# A simple expression with upvalue resolution beyond the target stack
|
||||||
|
# index of the root expression.
|
||||||
|
|
||||||
|
let
|
||||||
|
a = 1;
|
||||||
|
b = 2;
|
||||||
|
c = 3;
|
||||||
|
in {
|
||||||
|
inherit a b c;
|
||||||
|
}
|
Loading…
Reference in a new issue