about summary refs log tree commit diff
diff options
context:
space:
mode:
authorsterni <sternenseemann@systemli.org>2022-09-12T16·03+0200
committerclbot <clbot@tvl.fyi>2022-09-13T22·06+0000
commit162e21f2bb326960770ed55ee44170b924c72fd8 (patch)
treef7dbe91690d2f2a11507e9065aa093a214963a15
parent7e625afc5973b3d3ff08598fb9e513aaf1412e89 (diff)
fix(tvix/eval): force left argument of `?` before checking for attrs r/4849
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>
-rw-r--r--tvix/eval/src/compiler/attrs.rs2
-rw-r--r--tvix/eval/src/tests/tvix_tests/eval-okay-nested-has-attrs.exp1
-rw-r--r--tvix/eval/src/tests/tvix_tests/eval-okay-nested-has-attrs.nix26
3 files changed, 29 insertions, 0 deletions
diff --git a/tvix/eval/src/compiler/attrs.rs b/tvix/eval/src/compiler/attrs.rs
index bb48ffbb0945..c9897daac211 100644
--- a/tvix/eval/src/compiler/attrs.rs
+++ b/tvix/eval/src/compiler/attrs.rs
@@ -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);
diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-nested-has-attrs.exp b/tvix/eval/src/tests/tvix_tests/eval-okay-nested-has-attrs.exp
new file mode 100644
index 000000000000..d2c1c04da3c4
--- /dev/null
+++ b/tvix/eval/src/tests/tvix_tests/eval-okay-nested-has-attrs.exp
@@ -0,0 +1 @@
+[ true true true true true true true false false false false false ]
diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-nested-has-attrs.nix b/tvix/eval/src/tests/tvix_tests/eval-okay-nested-has-attrs.nix
new file mode 100644
index 000000000000..47dcec7a95f4
--- /dev/null
+++ b/tvix/eval/src/tests/tvix_tests/eval-okay-nested-has-attrs.nix
@@ -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)
+]