|
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