about summary refs log tree commit diff
path: root/tvix/eval/src/vm/macros.rs
diff options
context:
space:
mode:
authoredef <edef@edef.eu>2023-12-30T00·52+0000
committeredef <edef@edef.eu>2024-01-16T19·20+0000
commitb624edb2ae0df67f9d70a031563b83a33bb282ef (patch)
treebbf4a6e05f56ee593f6fa70565a3eecdc3b76942 /tvix/eval/src/vm/macros.rs
parent5ac9450395bf88c0716914dd407a5d13e23b49ed (diff)
fix(tvix/eval): lift VM ops over Catchable r/7395
We want to handle bottoms in a consistent fashion. Previously this was
handled by repetitive is_catchable checks, which were not consistently
present.

Change-Id: I9614c479cc6297d1f64efba22b620a26e2a96802
Reviewed-on: https://cl.tvl.fyi/c/depot/+/10485
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/eval/src/vm/macros.rs')
-rw-r--r--tvix/eval/src/vm/macros.rs49
1 files changed, 34 insertions, 15 deletions
diff --git a/tvix/eval/src/vm/macros.rs b/tvix/eval/src/vm/macros.rs
index eb386df92fa3..fdb812961172 100644
--- a/tvix/eval/src/vm/macros.rs
+++ b/tvix/eval/src/vm/macros.rs
@@ -36,24 +36,25 @@ macro_rules! arithmetic_op {
 #[macro_export]
 macro_rules! cmp_op {
     ( $vm:ident, $frame:ident, $span:ident, $op:tt ) => {{
-        let b = $vm.stack_pop();
-        let a = $vm.stack_pop();
+        lifted_pop! {
+            $vm(b, a) => {
+                async fn compare(a: Value, b: Value, co: GenCo) -> Result<Value, ErrorKind> {
+                    let a = generators::request_force(&co, a).await;
+                    let b = generators::request_force(&co, b).await;
+                    let span = generators::request_span(&co).await;
+                    let ordering = a.nix_cmp_ordering(b, co, span).await?;
+                    match ordering {
+                        Err(cek) => Ok(Value::Catchable(cek)),
+                        Ok(ordering) => Ok(Value::Bool(cmp_op!(@order $op ordering))),
+                    }
+                }
 
-        async fn compare(a: Value, b: Value, co: GenCo) -> Result<Value, ErrorKind> {
-            let a = generators::request_force(&co, a).await;
-            let b = generators::request_force(&co, b).await;
-            let span = generators::request_span(&co).await;
-            let ordering = a.nix_cmp_ordering(b, co, span).await?;
-            match ordering {
-                Err(cek) => Ok(Value::Catchable(cek)),
-                Ok(ordering) => Ok(Value::Bool(cmp_op!(@order $op ordering))),
+                let gen_span = $frame.current_light_span();
+                $vm.push_call_frame($span, $frame);
+                $vm.enqueue_generator("compare", gen_span, |co| compare(a, b, co));
+                return Ok(false);
             }
         }
-
-        let gen_span = $frame.current_light_span();
-        $vm.push_call_frame($span, $frame);
-        $vm.enqueue_generator("compare", gen_span, |co| compare(a, b, co));
-        return Ok(false);
     }};
 
     (@order < $ordering:expr) => {
@@ -72,3 +73,21 @@ macro_rules! cmp_op {
         matches!($ordering, Ordering::Equal | Ordering::Greater)
     };
 }
+
+#[macro_export]
+macro_rules! lifted_pop {
+    ($vm:ident ($($bind:ident),+) => $body:expr) => {
+        {
+            $(
+                let $bind = $vm.stack_pop();
+            )+
+            $(
+                if $bind.is_catchable() {
+                    $vm.stack.push($bind);
+                    continue;
+                }
+            )+
+            $body
+        }
+    }
+}