diff --git a/crates/compiler/can/src/expr.rs b/crates/compiler/can/src/expr.rs index d883461b80..8d7d3bde72 100644 --- a/crates/compiler/can/src/expr.rs +++ b/crates/compiler/can/src/expr.rs @@ -2600,10 +2600,38 @@ fn flatten_str_lines<'a>( fn desugar_str_segments(var_store: &mut VarStore, segments: Vec) -> Expr { use StrSegment::*; + let n = segments.len(); let mut iter = segments.into_iter().rev(); let mut loc_expr = match iter.next() { Some(Plaintext(string)) => Loc::at(Region::zero(), Expr::Str(string)), - Some(Interpolation(loc_expr)) => loc_expr, + Some(Interpolation(loc_expr)) => { + if n == 1 { + // We concat with the empty string to ensure a type error when loc_expr is not a string + let empty_string = Loc::at(Region::zero(), Expr::Str("".into())); + + let fn_expr = Loc::at( + Region::zero(), + Expr::Var(Symbol::STR_CONCAT, var_store.fresh()), + ); + let expr = Expr::Call( + Box::new(( + var_store.fresh(), + fn_expr, + var_store.fresh(), + var_store.fresh(), + )), + vec![ + (var_store.fresh(), empty_string), + (var_store.fresh(), loc_expr), + ], + CalledVia::StringInterpolation, + ); + + Loc::at(Region::zero(), expr) + } else { + loc_expr + } + } None => { // No segments? Empty string! diff --git a/crates/compiler/test_mono/generated/lambda_capture_niches_with_other_lambda_capture.txt b/crates/compiler/test_mono/generated/lambda_capture_niches_with_other_lambda_capture.txt index 143235362f..d608ea651b 100644 --- a/crates/compiler/test_mono/generated/lambda_capture_niches_with_other_lambda_capture.txt +++ b/crates/compiler/test_mono/generated/lambda_capture_niches_with_other_lambda_capture.txt @@ -1,10 +1,14 @@ +procedure Str.3 (#Attr.2, #Attr.3): + let Str.251 : Str = lowlevel StrConcat #Attr.2 #Attr.3; + ret Str.251; + procedure Test.1 (Test.5): let Test.16 : [C {}, C U64, C Str] = TagId(0) Test.5; ret Test.16; procedure Test.1 (Test.5): - let Test.30 : [C {}, C U64, C Str] = TagId(1) Test.5; - ret Test.30; + let Test.31 : [C {}, C U64, C Str] = TagId(1) Test.5; + ret Test.31; procedure Test.2 (Test.7): let Test.23 : [C {}, C U64, C Str] = TagId(2) Test.7; @@ -16,13 +20,16 @@ procedure Test.6 (Test.17, #Attr.12): ret Test.19; procedure Test.6 (Test.17, #Attr.12): - let Test.34 : U64 = UnionAtIndex (Id 1) (Index 0) #Attr.12; - let Test.33 : Str = ""; - ret Test.33; + let Test.35 : U64 = UnionAtIndex (Id 1) (Index 0) #Attr.12; + let Test.34 : Str = ""; + ret Test.34; procedure Test.8 (Test.24, #Attr.12): - let Test.27 : Str = UnionAtIndex (Id 2) (Index 0) #Attr.12; - ret Test.27; + let Test.28 : Str = UnionAtIndex (Id 2) (Index 0) #Attr.12; + let Test.27 : Str = ""; + let Test.26 : Str = CallByName Str.3 Test.27 Test.28; + dec Test.28; + ret Test.26; procedure Test.0 (): let Test.3 : U8 = 0u8; @@ -55,7 +62,7 @@ procedure Test.0 (): jump Test.13 Test.21; default: - let Test.29 : U64 = 1i64; - let Test.28 : [C {}, C U64, C Str] = CallByName Test.1 Test.29; - jump Test.13 Test.28; + let Test.30 : U64 = 1i64; + let Test.29 : [C {}, C U64, C Str] = CallByName Test.1 Test.30; + jump Test.13 Test.29; diff --git a/crates/repl_test/src/tests.rs b/crates/repl_test/src/tests.rs index 63472cbc43..892763aa5b 100644 --- a/crates/repl_test/src/tests.rs +++ b/crates/repl_test/src/tests.rs @@ -813,6 +813,32 @@ fn list_get_negative_index() { ); } +#[cfg(not(feature = "wasm"))] // TODO: mismatch is due to terminal control codes! +#[test] +fn invalid_string_interpolation() { + expect_failure( + "\"$(123)\"", + indoc!( + r#" + ── TYPE MISMATCH ─────────────────────────────────────────────────────────────── + + This argument to this string interpolation has an unexpected type: + + 4│ "$(123)" + ^^^ + + The argument is a number of type: + + Num * + + But this string interpolation needs its argument to be: + + Str + "# + ), + ); +} + #[test] fn issue_2149_i8_ok() { expect_success(r#"Str.toI8 "127""#, "Ok 127 : Result I8 [InvalidNumStr]");