From a30dd0905a08a78bb0573136064dd334a0567f6a Mon Sep 17 00:00:00 2001 From: sterni Date: Wed, 13 Dec 2023 14:06:38 +0100 Subject: fix(tvix/eval): determine meaning of `+` exprs based on first type 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 Reviewed-by: Adam Joseph --- tvix/eval/src/vm/mod.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'tvix') diff --git a/tvix/eval/src/vm/mod.rs b/tvix/eval/src/vm/mod.rs index fd71dbacf4..902121ebc7 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 { + // 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 { .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) -- cgit 1.4.1