From: Esteban Küber Date: Fri, 17 May 2019 02:29:02 +0000 (-0700) Subject: Handle more string addition cases with appropriate suggestions X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=234adf84bd834146c76b98dd4328e05a4bf7900b;p=rust.git Handle more string addition cases with appropriate suggestions --- diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index d1ca0578093..1913850c94c 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -502,6 +502,11 @@ fn add_type_neq_err_label( 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 @@ fn check_str_addition( 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 6dbc8d39976..a3b1d1d8179 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 a5b91f090d2..2f48abcaf33 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 61ebcfdefc3..17d9475b9c0 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