about summary refs log tree commit diff
path: root/tvix
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-09-04T19·34+0300
committertazjin <tazjin@tvl.su>2022-09-09T21·14+0000
commit6deaa0d6cef081ea9399918611ba57142f7255b5 (patch)
treeee8e90a0d47df636e54ccd135803e787058f8e0d /tvix
parent0aeca647777d2f17e40290e76c37e993e23c64ce (diff)
fix(tvix/eval): force value passed to builtins.toString r/4782
This introduces a macro to do the forcing, but this solution isn't
very nice and also does not work in all cases yet.

Change-Id: Icd18862ec47edb82c0efc3af5835a6cb6126f629
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6456
Reviewed-by: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix')
-rw-r--r--tvix/eval/src/builtins/mod.rs28
-rw-r--r--tvix/eval/src/vm.rs2
2 files changed, 26 insertions, 4 deletions
diff --git a/tvix/eval/src/builtins/mod.rs b/tvix/eval/src/builtins/mod.rs
index 947854e6f00a..1fe5d4a83eb1 100644
--- a/tvix/eval/src/builtins/mod.rs
+++ b/tvix/eval/src/builtins/mod.rs
@@ -15,6 +15,27 @@ use crate::{
 
 use crate::arithmetic_op;
 
+/// Helper macro to ensure that a value has been forced. The structure
+/// of this is a little cumbersome as there are different reference
+/// types depending on whether the value is inside a thunk or not.
+macro_rules! force {
+    ( $vm:ident, $src:expr, $value:ident, $body:block ) => {
+        if let Value::Thunk(thunk) = $src {
+            thunk.force($vm)?;
+            let guard = thunk.value();
+            let $value: &Value = &guard;
+            $body
+        } else {
+            let $value: &Value = $src;
+            $body
+        }
+    };
+
+    ( $vm:ident, $value:ident, $body:block ) => {
+        force!($vm, &$value, $value, $body)
+    };
+}
+
 fn pure_builtins() -> Vec<Builtin> {
     vec![
         Builtin::new("add", 2, |mut args, _| {
@@ -96,9 +117,10 @@ fn pure_builtins() -> Vec<Builtin> {
                 args.pop().unwrap().to_str()?.as_str().to_owned(),
             ));
         }),
-        Builtin::new("toString", 1, |args, _| {
-            // TODO: toString is actually not the same as Display
-            Ok(Value::String(format!("{}", args[0]).into()))
+        Builtin::new("toString", 1, |args, vm| {
+            force!(vm, &args[0], value, {
+                Ok(Value::String(format!("{}", value).into()))
+            })
         }),
         Builtin::new("typeOf", 1, |args, _| {
             Ok(Value::String(args[0].type_of().into()))
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index 73a03263c864..b65a37582f43 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -66,7 +66,7 @@ macro_rules! arithmetic_op {
         $self.push(result);
     }};
 
-    ( $a:ident, $b:ident, $op:tt ) => {{
+    ( $a:expr, $b:expr, $op:tt ) => {{
         match ($a, $b) {
             (Value::Integer(i1), Value::Integer(i2)) => Ok(Value::Integer(i1 $op i2)),
             (Value::Float(f1), Value::Float(f2)) => Ok(Value::Float(f1 $op f2)),