fix(tvix/eval): correctly resolve dynamic upvalues one scope up

This does not yet correctly resolve them if they are more than one
scope up, however.

Change-Id: I6687073c60aee0282f2b6ffc98b34c1e96a60f20
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6319
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
Vincent Ambo 2022-08-27 23:58:46 +03:00 committed by tazjin
parent e46a2ce3ef
commit a5e22c532b
5 changed files with 29 additions and 6 deletions

View file

@ -992,12 +992,6 @@ impl Compiler {
LocalPosition::Unknown => { /* continue below */ }
};
// Determine whether the upvalue is a dynamic variable in the
// enclosing context.
if self.contexts[ctx_idx - 1].scope.has_with() {
return Some(self.add_upvalue(ctx_idx, Upvalue::Dynamic(SmolStr::new(name))));
}
// If the upvalue comes from even further up, we need to
// recurse to make sure that the upvalues are created at each
// level.
@ -1005,6 +999,13 @@ impl Compiler {
return Some(self.add_upvalue(ctx_idx, Upvalue::Upvalue(idx)));
}
// If the resolution of a statically known upvalue failed,
// attempt to resolve a dynamic one (i.e. search for enclosing
// `with` blocks and make that resolution dynamic).
if self.contexts[ctx_idx - 1].scope.has_with() {
return Some(self.add_upvalue(ctx_idx, Upvalue::Dynamic(SmolStr::new(name))));
}
None
}

View file

@ -0,0 +1,14 @@
# If a closure closes over a variable that is statically known *and*
# available dynamically through `with`, the statically known one must
# have precedence.
let
# introduce statically known `a` (this should be the result)
a = 1;
in
# introduce some closure depth to force both kinds of upvalue
# resolution, and introduce a dynamically known `a` within the
# closures
let f = b: with { a = 2; }; c: a + b + c;
in f 0 0

View file

@ -0,0 +1 @@
[ 1 2 3 4 ]

View file

@ -0,0 +1,6 @@
with { a = 1; b = 1; };
with { b = 2; c = 2; };
with { c = 3; d = 3; };
with { d = 4; };
[ a b c d ]