fix(tvix/eval): force left argument of ? before checking for attrs

OpAttrsIsSet and OpAttrsTrySelect will fail silently if the attribute
set value on the stack is actually a thunk, so we need to make sure to
force at every step of the way.

Emitting the force instructions in the compiler because it is easier to
add, but maybe the VM should do this when handling the relevant opcodes?
Comments welcome.

Change-Id: I65c5ef348d59b2d07c9bb06abb24f9f3e6a0fdb2
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6540
Reviewed-by: grfn <grfn@gws.fyi>
Autosubmit: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
Reviewed-by: tazjin <tazjin@tvl.su>
This commit is contained in:
sterni 2022-09-12 18:03:43 +02:00 committed by clbot
parent 7e625afc59
commit 162e21f2bb
3 changed files with 29 additions and 0 deletions

View file

@ -113,12 +113,14 @@ impl Compiler<'_, '_> {
pub(super) fn compile_has_attr(&mut self, slot: LocalIdx, node: ast::HasAttr) {
// Put the attribute set on the stack.
self.compile(slot, node.expr().unwrap());
self.emit_force(&node);
// Push all path fragments with an operation for fetching the
// next nested element, for all fragments except the last one.
for (count, fragment) in node.attrpath().unwrap().attrs().enumerate() {
if count > 0 {
self.push_op(OpCode::OpAttrsTrySelect, &fragment);
self.emit_force(&fragment);
}
self.compile_attr(slot, fragment);

View file

@ -0,0 +1 @@
[ true true true true true true true false false false false false ]

View file

@ -0,0 +1,26 @@
let
set = {
a.b.c = 123;
foo = {
bar = 23;
};
baz = 1;
};
tes = "random value";
in
[
(set ? a)
(set ? a.b)
(set ? a.b.c)
(set ? foo)
(set ? foo.bar)
(set.foo ? bar)
(set ? baz)
(set ? x)
(set ? x.y.z)
(tes ? bar)
(tes ? x.y.z)
(null ? null)
]