about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAdam Joseph <adam@westernsemico.com>2023-12-12T11·45-0800
committerclbot <clbot@tvl.fyi>2023-12-12T16·57+0000
commitfc963033ae0f28a387d6aebcc1e827439f6653ef (patch)
treea558df784931aa8745a59e66a59e260e62b6724e
parent990c4e727f000e7db94e9b1367a55dbbfca68d65 (diff)
fix(tvix/eval): `?`: propagate catchables r/7189
This commit fixes out `?` operator so it correctly propagates
catchables.

Change-Id: Iebaa153a8492101ee3ddd29893c98730ff331547
Reviewed-on: https://cl.tvl.fyi/c/depot/+/10317
Autosubmit: Adam Joseph <adam@westernsemico.com>
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
-rw-r--r--tvix/eval/src/tests/tvix_tests/eval-okay-hasattr-catchable.exp1
-rw-r--r--tvix/eval/src/tests/tvix_tests/eval-okay-hasattr-catchable.nix1
-rw-r--r--tvix/eval/src/vm/mod.rs24
3 files changed, 18 insertions, 8 deletions
diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-hasattr-catchable.exp b/tvix/eval/src/tests/tvix_tests/eval-okay-hasattr-catchable.exp
new file mode 100644
index 000000000000..c508d5366f70
--- /dev/null
+++ b/tvix/eval/src/tests/tvix_tests/eval-okay-hasattr-catchable.exp
@@ -0,0 +1 @@
+false
diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-hasattr-catchable.nix b/tvix/eval/src/tests/tvix_tests/eval-okay-hasattr-catchable.nix
new file mode 100644
index 000000000000..ba85d6b77644
--- /dev/null
+++ b/tvix/eval/src/tests/tvix_tests/eval-okay-hasattr-catchable.nix
@@ -0,0 +1 @@
+(builtins.tryEval ((throw "fred") ? bob)).success
diff --git a/tvix/eval/src/vm/mod.rs b/tvix/eval/src/vm/mod.rs
index 44a29ba86f9d..5b9aecb8d440 100644
--- a/tvix/eval/src/vm/mod.rs
+++ b/tvix/eval/src/vm/mod.rs
@@ -707,16 +707,24 @@ impl<'o> VM<'o> {
                 }
 
                 OpCode::OpHasAttr => {
-                    let key = self.stack_pop().to_str().with_span(&frame, self)?;
-                    let result = match self.stack_pop() {
-                        Value::Attrs(attrs) => attrs.contains(key.as_str()),
+                    let key = self.stack_pop();
+                    let attrs = self.stack_pop();
+                    if key.is_catchable() {
+                        self.stack.push(key);
+                    } else if attrs.is_catchable() {
+                        self.stack.push(attrs);
+                    } else {
+                        let key = key.to_str().with_span(&frame, self)?;
+                        let result = match attrs {
+                            Value::Attrs(attrs) => attrs.contains(key.as_str()),
 
-                        // Nix allows use of `?` on non-set types, but
-                        // always returns false in those cases.
-                        _ => false,
-                    };
+                            // Nix allows use of `?` on non-set types, but
+                            // always returns false in those cases.
+                            _ => false,
+                        };
 
-                    self.stack.push(Value::Bool(result));
+                        self.stack.push(Value::Bool(result));
+                    }
                 }
 
                 OpCode::OpConcat => {