about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/eval/src/compiler.rs3
-rw-r--r--tvix/eval/src/opcode.rs3
-rw-r--r--tvix/eval/src/value/mod.rs4
-rw-r--r--tvix/eval/src/vm.rs14
4 files changed, 24 insertions, 0 deletions
diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs
index 90a6155b6b..1bfd765a07 100644
--- a/tvix/eval/src/compiler.rs
+++ b/tvix/eval/src/compiler.rs
@@ -350,6 +350,7 @@ impl Compiler {
         self.compile(node.rhs().unwrap())?;
 
         self.patch_jump(end_idx);
+        self.chunk.add_op(OpCode::OpAssertBool);
 
         Ok(())
     }
@@ -370,6 +371,7 @@ impl Compiler {
         self.chunk.add_op(OpCode::OpPop);
         self.compile(node.rhs().unwrap())?;
         self.patch_jump(end_idx);
+        self.chunk.add_op(OpCode::OpAssertBool);
 
         Ok(())
     }
@@ -390,6 +392,7 @@ impl Compiler {
         self.chunk.add_op(OpCode::OpPop);
         self.compile(node.rhs().unwrap())?;
         self.patch_jump(end_idx);
+        self.chunk.add_op(OpCode::OpAssertBool);
 
         Ok(())
     }
diff --git a/tvix/eval/src/opcode.rs b/tvix/eval/src/opcode.rs
index f577bc985d..4831a71ebd 100644
--- a/tvix/eval/src/opcode.rs
+++ b/tvix/eval/src/opcode.rs
@@ -53,4 +53,7 @@ pub enum OpCode {
 
     // Strings
     OpInterpolate(usize),
+
+    // Type assertion operators
+    OpAssertBool,
 }
diff --git a/tvix/eval/src/value/mod.rs b/tvix/eval/src/value/mod.rs
index 4a34379748..99eb4c657b 100644
--- a/tvix/eval/src/value/mod.rs
+++ b/tvix/eval/src/value/mod.rs
@@ -91,6 +91,10 @@ impl Value {
             }),
         }
     }
+
+    pub fn is_bool(&self) -> bool {
+        matches!(self, Value::Bool(_))
+    }
 }
 
 impl Display for Value {
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index ed040cf917..3e8509187b 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -187,6 +187,20 @@ impl VM {
                         self.ip += offset;
                     }
                 }
+
+                // These assertion operations error out if the stack
+                // top is not of the expected type. This is necessary
+                // to implement some specific behaviours of Nix
+                // exactly.
+                OpCode::OpAssertBool => {
+                    let val = self.peek(0);
+                    if !val.is_bool() {
+                        return Err(Error::TypeError {
+                            expected: "bool",
+                            actual: val.type_of(),
+                        });
+                    }
+                }
             }
 
             if self.ip == self.chunk.code.len() {