about summary refs log tree commit diff
path: root/tvix/eval/src/vm
diff options
context:
space:
mode:
authorsterni <sternenseemann@systemli.org>2023-12-13T13·06+0100
committerclbot <clbot@tvl.fyi>2023-12-14T02·59+0000
commita30dd0905a08a78bb0573136064dd334a0567f6a (patch)
treed13087c5144d46b14f81949e7ade7f43e2ad704c /tvix/eval/src/vm
parent8b0047e2773586baba37cc2e45c4a3b73c41c50a (diff)
fix(tvix/eval): determine meaning of `+` exprs based on first type r/7217
This matches the behavior of C++ Nix more closely where the decision is
made based on the first type based to ExprConcatStrings:
https://github.com/NixOS/nix/blob/1f93fa2ed29ff0ba92bfa58995232668187fb0d0/src/libexpr/eval.cc#L1967-L2025

Note that this doesn't make a difference in any successful
evaluation (at least to my knowledge), but ensures that our error
messages will match C++ Nix more closely, e.g. in the case of
`1 + "string"`.

Change-Id: I8059930788f9c8d98baf98e3d93d8a060ef961f2
Reviewed-on: https://cl.tvl.fyi/c/depot/+/10360
Tested-by: BuildkiteCI
Autosubmit: sterni <sternenseemann@systemli.org>
Reviewed-by: Adam Joseph <adam@westernsemico.com>
Diffstat (limited to 'tvix/eval/src/vm')
-rw-r--r--tvix/eval/src/vm/mod.rs16
1 files changed, 11 insertions, 5 deletions
diff --git a/tvix/eval/src/vm/mod.rs b/tvix/eval/src/vm/mod.rs
index fd71dbacf480..902121ebc727 100644
--- a/tvix/eval/src/vm/mod.rs
+++ b/tvix/eval/src/vm/mod.rs
@@ -1202,6 +1202,7 @@ async fn resolve_with(
 
 // TODO(amjoseph): de-asyncify this
 async fn add_values(co: GenCo, a: Value, b: Value) -> Result<Value, ErrorKind> {
+    // What we try to do is solely determined by the type of the first value!
     let result = match (a, b) {
         (Value::Path(p), v) => {
             let mut path = p.to_string_lossy().into_owned();
@@ -1218,11 +1219,16 @@ async fn add_values(co: GenCo, a: Value, b: Value) -> Result<Value, ErrorKind> {
             .await
             .map(|s2| Value::String(s1.concat(&s2)))
             .into(),
-        (v, Value::String(s2)) => generators::request_string_coerce(&co, v, CoercionKind::Weak)
-            .await
-            .map(|s1| Value::String(s1.concat(&s2)))
-            .into(),
-        (a, b) => arithmetic_op!(&a, &b, +)?,
+        (a @ Value::Integer(_), b) | (a @ Value::Float(_), b) => arithmetic_op!(&a, &b, +)?,
+        (a, b) => {
+            let r1 = generators::request_string_coerce(&co, a, CoercionKind::Weak).await;
+            let r2 = generators::request_string_coerce(&co, b, CoercionKind::Weak).await;
+            match (r1, r2) {
+                (Ok(s1), Ok(s2)) => Value::String(s1.concat(&s2)),
+                (Err(c), _) => return Ok(Value::Catchable(c)),
+                (_, Err(c)) => return Ok(Value::Catchable(c)),
+            }
+        }
     };
 
     Ok(result)