|
13 | 13 | use super::{FnCtxt, Needs};
|
14 | 14 | use super::method::MethodCallee;
|
15 | 15 | use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
|
16 |
| -use rustc::ty::TypeVariants::{TyStr, TyRef}; |
| 16 | +use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt}; |
17 | 17 | use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
|
18 | 18 | use rustc::infer::type_variable::TypeVariableOrigin;
|
19 | 19 | use errors;
|
@@ -299,7 +299,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
299 | 299 |
|
300 | 300 | if let Some(missing_trait) = missing_trait {
|
301 | 301 | if missing_trait == "std::ops::Add" &&
|
302 |
| - self.check_str_addition(expr, lhs_expr, lhs_ty, |
| 302 | + self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, |
303 | 303 | rhs_ty, &mut err) {
|
304 | 304 | // This has nothing here because it means we did string
|
305 | 305 | // concatenation (e.g. "Hello " + "World!"). This means
|
@@ -328,37 +328,54 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
328 | 328 | fn check_str_addition(&self,
|
329 | 329 | expr: &'gcx hir::Expr,
|
330 | 330 | lhs_expr: &'gcx hir::Expr,
|
| 331 | + rhs_expr: &'gcx hir::Expr, |
331 | 332 | lhs_ty: Ty<'tcx>,
|
332 | 333 | rhs_ty: Ty<'tcx>,
|
333 | 334 | err: &mut errors::DiagnosticBuilder) -> bool {
|
| 335 | + let codemap = self.tcx.sess.codemap(); |
| 336 | + let msg = "`to_owned()` can be used to create an owned `String` \ |
| 337 | + from a string reference. String concatenation \ |
| 338 | + appends the string on the right to the string \ |
| 339 | + on the left and may require reallocation. This \ |
| 340 | + requires ownership of the string on the left"; |
334 | 341 | // If this function returns true it means a note was printed, so we don't need
|
335 | 342 | // to print the normal "implementation of `std::ops::Add` might be missing" note
|
336 |
| - let mut is_string_addition = false; |
337 |
| - if let TyRef(_, l_ty) = lhs_ty.sty { |
338 |
| - if let TyRef(_, r_ty) = rhs_ty.sty { |
339 |
| - if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr { |
340 |
| - err.span_label(expr.span, |
341 |
| - "`+` can't be used to concatenate two `&str` strings"); |
342 |
| - let codemap = self.tcx.sess.codemap(); |
343 |
| - let suggestion = |
344 |
| - match codemap.span_to_snippet(lhs_expr.span) { |
345 |
| - Ok(lstring) => format!("{}.to_owned()", lstring), |
346 |
| - _ => format!("<expression>") |
347 |
| - }; |
348 |
| - err.span_suggestion(lhs_expr.span, |
349 |
| - &format!("`to_owned()` can be used to create an owned `String` \ |
350 |
| - from a string reference. String concatenation \ |
351 |
| - appends the string on the right to the string \ |
352 |
| - on the left and may require reallocation. This \ |
353 |
| - requires ownership of the string on the left"), suggestion); |
354 |
| - is_string_addition = true; |
355 |
| - } |
356 |
| - |
| 343 | + match (&lhs_ty.sty, &rhs_ty.sty) { |
| 344 | + (&TyRef(_, ref l_ty), &TyRef(_, ref r_ty)) |
| 345 | + if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr => { |
| 346 | + err.span_label(expr.span, |
| 347 | + "`+` can't be used to concatenate two `&str` strings"); |
| 348 | + match codemap.span_to_snippet(lhs_expr.span) { |
| 349 | + Ok(lstring) => err.span_suggestion(lhs_expr.span, |
| 350 | + msg, |
| 351 | + format!("{}.to_owned()", lstring)), |
| 352 | + _ => err.help(msg), |
| 353 | + }; |
| 354 | + true |
357 | 355 | }
|
358 |
| - |
| 356 | + (&TyRef(_, ref l_ty), &TyAdt(..)) |
| 357 | + if l_ty.ty.sty == TyStr && &format!("{:?}", rhs_ty) == "std::string::String" => { |
| 358 | + err.span_label(expr.span, |
| 359 | + "`+` can't be used to concatenate a `&str` with a `String`"); |
| 360 | + match codemap.span_to_snippet(lhs_expr.span) { |
| 361 | + Ok(lstring) => err.span_suggestion(lhs_expr.span, |
| 362 | + msg, |
| 363 | + format!("{}.to_owned()", lstring)), |
| 364 | + _ => err.help(msg), |
| 365 | + }; |
| 366 | + match codemap.span_to_snippet(rhs_expr.span) { |
| 367 | + Ok(rstring) => { |
| 368 | + err.span_suggestion(rhs_expr.span, |
| 369 | + "you also need to borrow the `String` on the right to \ |
| 370 | + get a `&str`", |
| 371 | + format!("&{}", rstring)); |
| 372 | + } |
| 373 | + _ => {} |
| 374 | + }; |
| 375 | + true |
| 376 | + } |
| 377 | + _ => false, |
359 | 378 | }
|
360 |
| - |
361 |
| - is_string_addition |
362 | 379 | }
|
363 | 380 |
|
364 | 381 | pub fn check_user_unop(&self,
|
|
0 commit comments