From 234adf84bd834146c76b98dd4328e05a4bf7900b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 May 2019 19:29:02 -0700 Subject: [PATCH 1/4] Handle more string addition cases with appropriate suggestions --- src/librustc_typeck/check/op.rs | 57 +++++-- src/test/ui/span/issue-39018.rs | 20 +++ src/test/ui/span/issue-39018.stderr | 143 +++++++++++++++++- .../ui/str/str-concat-on-double-ref.stderr | 7 +- 4 files changed, 209 insertions(+), 18 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index d1ca05780930a..1913850c94c7e 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -502,6 +502,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { false } + /// Provide actionable suggestions when trying to add two strings with incorrect types, + /// like `&str + &str`, `String + String` and `&str + &String`. + /// + /// If this function returns `true` it means a note was printed, so we don't need + /// to print the normal "implementation of `std::ops::Add` might be missing" note fn check_str_addition( &self, expr: &'gcx hir::Expr, @@ -514,33 +519,57 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { op: hir::BinOp, ) -> bool { let source_map = self.tcx.sess.source_map(); + let remove_borrow_msg = "String concatenation appends the string on the right to the \ + string on the left and may require reallocation. This \ + requires ownership of the string on the left"; + let msg = "`to_owned()` can be used to create an owned `String` \ from a string reference. String concatenation \ appends the string on the right to the string \ on the left and may require reallocation. This \ requires ownership of the string on the left"; - // If this function returns true it means a note was printed, so we don't need - // to print the normal "implementation of `std::ops::Add` might be missing" note + debug!("check_str_addition: {:?} + {:?}", lhs_ty, rhs_ty); match (&lhs_ty.sty, &rhs_ty.sty) { - (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) - if l_ty.sty == Str && r_ty.sty == Str => { + (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str + if (l_ty.sty == Str || &format!("{:?}", l_ty) == "std::string::String") && ( + r_ty.sty == Str || + &format!("{:?}", r_ty) == "std::string::String" || + &format!("{:?}", rhs_ty) == "&&str" + ) => + { if !is_assign { - err.span_label(op.span, - "`+` can't be used to concatenate two `&str` strings"); + err.span_label( + op.span, + "`+` can't be used to concatenate two `&str` strings", + ); match source_map.span_to_snippet(lhs_expr.span) { - Ok(lstring) => err.span_suggestion( - lhs_expr.span, - msg, - format!("{}.to_owned()", lstring), - Applicability::MachineApplicable, - ), + Ok(lstring) => { + err.span_suggestion( + lhs_expr.span, + if lstring.starts_with("&") { + remove_borrow_msg + } else { + msg + }, + if lstring.starts_with("&") { + // let a = String::new(); + // let _ = &a + "bar"; + format!("{}", &lstring[1..]) + } else { + format!("{}.to_owned()", lstring) + }, + Applicability::MachineApplicable, + ) + } _ => err.help(msg), }; } true } - (&Ref(_, l_ty, _), &Adt(..)) - if l_ty.sty == Str && &format!("{:?}", rhs_ty) == "std::string::String" => { + (&Ref(_, l_ty, _), &Adt(..)) // Handle `&str` & `&String` + `String` + if (l_ty.sty == Str || &format!("{:?}", l_ty) == "std::string::String") && + &format!("{:?}", rhs_ty) == "std::string::String" => + { err.span_label(expr.span, "`+` can't be used to concatenate a `&str` with a `String`"); match ( diff --git a/src/test/ui/span/issue-39018.rs b/src/test/ui/span/issue-39018.rs index 6dbc8d39976ad..a3b1d1d81799f 100644 --- a/src/test/ui/span/issue-39018.rs +++ b/src/test/ui/span/issue-39018.rs @@ -16,3 +16,23 @@ enum World { Hello, Goodbye, } + +fn foo() { + let a = String::new(); + let b = String::new(); + let c = ""; + let d = ""; + let e = &a; + let _ = &a + &b; //~ ERROR binary operation + let _ = &a + b; //~ ERROR binary operation + let _ = a + &b; // ok + let _ = a + b; //~ ERROR mismatched types + let _ = e + b; //~ ERROR binary operation + let _ = e + &b; //~ ERROR binary operation + let _ = e + d; //~ ERROR binary operation + let _ = e + &d; //~ ERROR binary operation + let _ = &c + &d; //~ ERROR binary operation + let _ = &c + d; //~ ERROR binary operation + let _ = c + &d; //~ ERROR binary operation + let _ = c + d; //~ ERROR binary operation +} diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index a5b91f090d2c0..2f48abcaf3339 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -35,6 +35,145 @@ help: `to_owned()` can be used to create an owned `String` from a string referen LL | let x = "Hello ".to_owned() + &"World!".to_owned(); | ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:26:16 + | +LL | let _ = &a + &b; + | -- ^ -- &std::string::String + | | | + | | `+` can't be used to concatenate two `&str` strings + | &std::string::String +help: String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = a + &b; + | ^ + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:27:16 + | +LL | let _ = &a + b; + | ---^-- + | | | + | | std::string::String + | &std::string::String + | `+` can't be used to concatenate a `&str` with a `String` +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = &a.to_owned() + &b; + | ^^^^^^^^^^^^^ ^^ + +error[E0308]: mismatched types + --> $DIR/issue-39018.rs:29:17 + | +LL | let _ = a + b; + | ^ + | | + | expected &str, found struct `std::string::String` + | help: consider borrowing here: `&b` + | + = note: expected type `&str` + found type `std::string::String` + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:30:15 + | +LL | let _ = e + b; + | --^-- + | | | + | | std::string::String + | &std::string::String + | `+` can't be used to concatenate a `&str` with a `String` +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = e.to_owned() + &b; + | ^^^^^^^^^^^^ ^^ + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:31:15 + | +LL | let _ = e + &b; + | - ^ -- &std::string::String + | | | + | | `+` can't be used to concatenate two `&str` strings + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = e.to_owned() + &b; + | ^^^^^^^^^^^^ + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:32:15 + | +LL | let _ = e + d; + | - ^ - &str + | | | + | | `+` can't be used to concatenate two `&str` strings + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = e.to_owned() + d; + | ^^^^^^^^^^^^ + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:33:15 + | +LL | let _ = e + &d; + | - ^ -- &&str + | | | + | | `+` can't be used to concatenate two `&str` strings + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = e.to_owned() + &d; + | ^^^^^^^^^^^^ + +error[E0369]: binary operation `+` cannot be applied to type `&&str` + --> $DIR/issue-39018.rs:34:16 + | +LL | let _ = &c + &d; + | -- ^ -- &&str + | | + | &&str + | + = note: an implementation of `std::ops::Add` might be missing for `&&str` + +error[E0369]: binary operation `+` cannot be applied to type `&&str` + --> $DIR/issue-39018.rs:35:16 + | +LL | let _ = &c + d; + | -- ^ - &str + | | + | &&str + | + = note: an implementation of `std::ops::Add` might be missing for `&&str` + +error[E0369]: binary operation `+` cannot be applied to type `&str` + --> $DIR/issue-39018.rs:36:15 + | +LL | let _ = c + &d; + | - ^ -- &&str + | | | + | | `+` can't be used to concatenate two `&str` strings + | &str +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = c.to_owned() + &d; + | ^^^^^^^^^^^^ + +error[E0369]: binary operation `+` cannot be applied to type `&str` + --> $DIR/issue-39018.rs:37:15 + | +LL | let _ = c + d; + | - ^ - &str + | | | + | | `+` can't be used to concatenate two `&str` strings + | &str +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = c.to_owned() + d; + | ^^^^^^^^^^^^ + +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0369`. +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/str/str-concat-on-double-ref.stderr b/src/test/ui/str/str-concat-on-double-ref.stderr index 61ebcfdefc316..17d9475b9c07d 100644 --- a/src/test/ui/str/str-concat-on-double-ref.stderr +++ b/src/test/ui/str/str-concat-on-double-ref.stderr @@ -3,10 +3,13 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::Stri | LL | let c = a + b; | - ^ - &str - | | + | | | + | | `+` can't be used to concatenate two `&str` strings | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | - = note: an implementation of `std::ops::Add` might be missing for `&std::string::String` +LL | let c = a.to_owned() + b; + | ^^^^^^^^^^^^ error: aborting due to previous error From 2cb91816f24a096a0760a49b6b4095309098e7f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 May 2019 19:56:11 -0700 Subject: [PATCH 2/4] Fix binop span --- src/librustc_typeck/check/op.rs | 17 +++++++++-------- src/libsyntax/parse/parser.rs | 3 +-- src/test/ui/span/issue-39018.stderr | 21 +++++++++------------ 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 1913850c94c7e..619900b6ad903 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -305,8 +305,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(missing_trait) = missing_trait { if op.node == hir::BinOpKind::Add && - self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, - rhs_ty, &mut err, true, op) { + self.check_str_addition( + lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, true, op) { // This has nothing here because it means we did string // concatenation (e.g., "Hello " += "World!"). This means // we don't want the note in the else clause to be emitted @@ -400,8 +400,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(missing_trait) = missing_trait { if op.node == hir::BinOpKind::Add && - self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, - rhs_ty, &mut err, false, op) { + self.check_str_addition( + lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, false, op) { // This has nothing here because it means we did string // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted @@ -509,7 +509,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// to print the normal "implementation of `std::ops::Add` might be missing" note fn check_str_addition( &self, - expr: &'gcx hir::Expr, lhs_expr: &'gcx hir::Expr, rhs_expr: &'gcx hir::Expr, lhs_ty: Ty<'tcx>, @@ -537,7 +536,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &format!("{:?}", rhs_ty) == "&&str" ) => { - if !is_assign { + if !is_assign { // Do not supply this message if `&str += &str` err.span_label( op.span, "`+` can't be used to concatenate two `&str` strings", @@ -570,8 +569,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if (l_ty.sty == Str || &format!("{:?}", l_ty) == "std::string::String") && &format!("{:?}", rhs_ty) == "std::string::String" => { - err.span_label(expr.span, - "`+` can't be used to concatenate a `&str` with a `String`"); + err.span_label( + op.span, + "`+` can't be used to concatenate a `&str` with a `String`", + ); match ( source_map.span_to_snippet(lhs_expr.span), source_map.span_to_snippet(rhs_expr.span), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 99e8db9d8e6d2..a80fe4b2fd8e5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3540,8 +3540,7 @@ impl<'a> Parser<'a> { let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs); self.mk_expr(span, binary, ThinVec::new()) } - AssocOp::Assign => - self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), + AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), AssocOp::ObsoleteInPlace => self.mk_expr(span, ExprKind::ObsoleteInPlace(lhs, rhs), ThinVec::new()), AssocOp::AssignOp(k) => { diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index 2f48abcaf3339..b174e95c8a1d4 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -25,11 +25,10 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` --> $DIR/issue-39018.rs:11:22 | LL | let x = "Hello " + "World!".to_owned(); - | ---------^-------------------- - | | | - | | std::string::String + | -------- ^ ------------------- std::string::String + | | | + | | `+` can't be used to concatenate a `&str` with a `String` | &str - | `+` can't be used to concatenate a `&str` with a `String` help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let x = "Hello ".to_owned() + &"World!".to_owned(); @@ -52,11 +51,10 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::Stri --> $DIR/issue-39018.rs:27:16 | LL | let _ = &a + b; - | ---^-- - | | | - | | std::string::String + | -- ^ - std::string::String + | | | + | | `+` can't be used to concatenate a `&str` with a `String` | &std::string::String - | `+` can't be used to concatenate a `&str` with a `String` help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let _ = &a.to_owned() + &b; @@ -78,11 +76,10 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::Stri --> $DIR/issue-39018.rs:30:15 | LL | let _ = e + b; - | --^-- - | | | - | | std::string::String + | - ^ - std::string::String + | | | + | | `+` can't be used to concatenate a `&str` with a `String` | &std::string::String - | `+` can't be used to concatenate a `&str` with a `String` help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let _ = e.to_owned() + &b; From ee0bf5e6aa7a964bb5c776adba0faad087a6a425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 May 2019 20:05:00 -0700 Subject: [PATCH 3/4] review comments --- src/librustc_typeck/check/op.rs | 20 +++++++++---------- src/test/ui/issues/issue-47377.stderr | 2 +- src/test/ui/issues/issue-47380.stderr | 2 +- src/test/ui/span/issue-39018.stderr | 20 +++++++++---------- .../ui/str/str-concat-on-double-ref.stderr | 2 +- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 619900b6ad903..26a5bdfef7d66 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -527,19 +527,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { appends the string on the right to the string \ on the left and may require reallocation. This \ requires ownership of the string on the left"; - debug!("check_str_addition: {:?} + {:?}", lhs_ty, rhs_ty); + + let is_std_string = |ty| &format!("{:?}", ty) == "std::string::String"; + match (&lhs_ty.sty, &rhs_ty.sty) { (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str - if (l_ty.sty == Str || &format!("{:?}", l_ty) == "std::string::String") && ( - r_ty.sty == Str || - &format!("{:?}", r_ty) == "std::string::String" || - &format!("{:?}", rhs_ty) == "&&str" - ) => + if (l_ty.sty == Str || is_std_string(l_ty)) && ( + r_ty.sty == Str || is_std_string(r_ty) || + &format!("{:?}", rhs_ty) == "&&str" + ) => { if !is_assign { // Do not supply this message if `&str += &str` err.span_label( op.span, - "`+` can't be used to concatenate two `&str` strings", + "`+` cannot be used to concatenate two `&str` strings", ); match source_map.span_to_snippet(lhs_expr.span) { Ok(lstring) => { @@ -566,12 +567,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { true } (&Ref(_, l_ty, _), &Adt(..)) // Handle `&str` & `&String` + `String` - if (l_ty.sty == Str || &format!("{:?}", l_ty) == "std::string::String") && - &format!("{:?}", rhs_ty) == "std::string::String" => + if (l_ty.sty == Str || is_std_string(l_ty)) && is_std_string(rhs_ty) => { err.span_label( op.span, - "`+` can't be used to concatenate a `&str` with a `String`", + "`+` cannot be used to concatenate a `&str` with a `String`", ); match ( source_map.span_to_snippet(lhs_expr.span), diff --git a/src/test/ui/issues/issue-47377.stderr b/src/test/ui/issues/issue-47377.stderr index 88466131e3144..7d11a8c802128 100644 --- a/src/test/ui/issues/issue-47377.stderr +++ b/src/test/ui/issues/issue-47377.stderr @@ -4,7 +4,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` LL | let _a = b + ", World!"; | - ^ ---------- &str | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | diff --git a/src/test/ui/issues/issue-47380.stderr b/src/test/ui/issues/issue-47380.stderr index d69101eab4c46..89a154c5109d8 100644 --- a/src/test/ui/issues/issue-47380.stderr +++ b/src/test/ui/issues/issue-47380.stderr @@ -4,7 +4,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` LL | println!("🦀🦀🦀🦀🦀"); let _a = b + ", World!"; | - ^ ---------- &str | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index b174e95c8a1d4..cdb9c1168d8e7 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -4,7 +4,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` LL | let x = "Hello " + "World!"; | -------- ^ -------- &str | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | @@ -27,7 +27,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` LL | let x = "Hello " + "World!".to_owned(); | -------- ^ ------------------- std::string::String | | | - | | `+` can't be used to concatenate a `&str` with a `String` + | | `+` cannot be used to concatenate a `&str` with a `String` | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | @@ -40,7 +40,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::Stri LL | let _ = &a + &b; | -- ^ -- &std::string::String | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &std::string::String help: String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | @@ -53,7 +53,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::Stri LL | let _ = &a + b; | -- ^ - std::string::String | | | - | | `+` can't be used to concatenate a `&str` with a `String` + | | `+` cannot be used to concatenate a `&str` with a `String` | &std::string::String help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | @@ -78,7 +78,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::Stri LL | let _ = e + b; | - ^ - std::string::String | | | - | | `+` can't be used to concatenate a `&str` with a `String` + | | `+` cannot be used to concatenate a `&str` with a `String` | &std::string::String help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | @@ -91,7 +91,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::Stri LL | let _ = e + &b; | - ^ -- &std::string::String | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &std::string::String help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | @@ -104,7 +104,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::Stri LL | let _ = e + d; | - ^ - &str | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &std::string::String help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | @@ -117,7 +117,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::Stri LL | let _ = e + &d; | - ^ -- &&str | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &std::string::String help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | @@ -150,7 +150,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` LL | let _ = c + &d; | - ^ -- &&str | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | @@ -163,7 +163,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` LL | let _ = c + d; | - ^ - &str | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | diff --git a/src/test/ui/str/str-concat-on-double-ref.stderr b/src/test/ui/str/str-concat-on-double-ref.stderr index 17d9475b9c07d..3e53cdc4d98ca 100644 --- a/src/test/ui/str/str-concat-on-double-ref.stderr +++ b/src/test/ui/str/str-concat-on-double-ref.stderr @@ -4,7 +4,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::Stri LL | let c = a + b; | - ^ - &str | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &std::string::String help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | From 8895fb945d0ea0ce124923aadc16adb68c74f3e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 17 May 2019 10:45:54 -0700 Subject: [PATCH 4/4] Account for &String + String --- src/librustc_typeck/check/op.rs | 9 ++++++++- src/test/ui/span/issue-39018.stderr | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 26a5bdfef7d66..cd207478f8f6f 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -579,10 +579,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { is_assign, ) { (Ok(l), Ok(r), false) => { + let to_string = if l.starts_with("&") { + // let a = String::new(); let b = String::new(); + // let _ = &a + b; + format!("{}", &l[1..]) + } else { + format!("{}.to_owned()", l) + }; err.multipart_suggestion( msg, vec![ - (lhs_expr.span, format!("{}.to_owned()", l)), + (lhs_expr.span, to_string), (rhs_expr.span, format!("&{}", r)), ], Applicability::MachineApplicable, diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index cdb9c1168d8e7..d8fbf841b6157 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -57,8 +57,8 @@ LL | let _ = &a + b; | &std::string::String help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | -LL | let _ = &a.to_owned() + &b; - | ^^^^^^^^^^^^^ ^^ +LL | let _ = a + &b; + | ^ ^^ error[E0308]: mismatched types --> $DIR/issue-39018.rs:29:17