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