diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 9a84daf53db..cd2de3247cf 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -307,7 +307,7 @@ pub(super) fn report_mutability_error( let local_decl = &self.mir.local_decls[*local]; let suggestion = match local_decl.is_user_variable.as_ref().unwrap() { ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf) => { - Some(suggest_ampmut_self(local_decl)) + Some(suggest_ampmut_self(self.tcx, local_decl)) } ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { @@ -418,8 +418,22 @@ fn is_upvar(&self, place: &Place<'tcx>) -> bool { } } -fn suggest_ampmut_self<'cx, 'gcx, 'tcx>(local_decl: &mir::LocalDecl<'tcx>) -> (Span, String) { - (local_decl.source_info.span, "&mut self".to_string()) +fn suggest_ampmut_self<'cx, 'gcx, 'tcx>( + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + local_decl: &mir::LocalDecl<'tcx>, +) -> (Span, String) { + let sp = local_decl.source_info.span; + (sp, match tcx.sess.codemap().span_to_snippet(sp) { + Ok(snippet) => { + let lt_pos = snippet.find('\''); + if let Some(lt_pos) = lt_pos { + format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4]) + } else { + "&mut self".to_string() + } + } + _ => "&mut self".to_string() + }) } // When we want to suggest a user change a local variable to be a `&mut`, there @@ -447,9 +461,15 @@ fn suggest_ampmut<'cx, 'gcx, 'tcx>( let locations = mir.find_assignments(local); if locations.len() > 0 { let assignment_rhs_span = mir.source_info(locations[0]).span; - let snippet = tcx.sess.codemap().span_to_snippet(assignment_rhs_span); - if let Ok(src) = snippet { - if src.starts_with('&') { + if let Ok(src) = tcx.sess.codemap().span_to_snippet(assignment_rhs_span) { + if let (true, Some(ws_pos)) = ( + src.starts_with("&'"), + src.find(|c: char| -> bool { c.is_whitespace() }), + ) { + let lt_name = &src[1..ws_pos]; + let ty = &src[ws_pos..]; + return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty)); + } else if src.starts_with('&') { let borrowed_expr = src[1..].to_string(); return (assignment_rhs_span, format!("&mut {}", borrowed_expr)); } @@ -466,13 +486,25 @@ fn suggest_ampmut<'cx, 'gcx, 'tcx>( None => local_decl.source_info.span, }; + if let Ok(src) = tcx.sess.codemap().span_to_snippet(highlight_span) { + if let (true, Some(ws_pos)) = ( + src.starts_with("&'"), + src.find(|c: char| -> bool { c.is_whitespace() }), + ) { + let lt_name = &src[1..ws_pos]; + let ty = &src[ws_pos..]; + return (highlight_span, format!("&{} mut{}", lt_name, ty)); + } + } + let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); assert_eq!(ty_mut.mutbl, hir::MutImmutable); - if local_decl.ty.is_region_ptr() { - (highlight_span, format!("&mut {}", ty_mut.ty)) - } else { - (highlight_span, format!("*mut {}", ty_mut.ty)) - } + (highlight_span, + if local_decl.ty.is_region_ptr() { + format!("&mut {}", ty_mut.ty) + } else { + format!("*mut {}", ty_mut.ty) + }) } fn is_closure_or_generator(ty: ty::Ty) -> bool { diff --git a/src/test/ui/did_you_mean/issue-39544.nll.stderr b/src/test/ui/did_you_mean/issue-39544.nll.stderr index 00e4cc6b0c3..8c848b33241 100644 --- a/src/test/ui/did_you_mean/issue-39544.nll.stderr +++ b/src/test/ui/did_you_mean/issue-39544.nll.stderr @@ -10,7 +10,7 @@ error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:26:17 | LL | fn foo<'z>(&'z self) { - | -------- help: consider changing this to be a mutable reference: `&mut self` + | -------- help: consider changing this to be a mutable reference: `&'z mut self` LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -35,7 +35,7 @@ error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:35:17 | LL | fn foo2<'a>(&'a self, other: &Z) { - | -------- help: consider changing this to be a mutable reference: `&mut self` + | -------- help: consider changing this to be a mutable reference: `&'a mut self` LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -52,7 +52,7 @@ error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:40:17 | LL | fn foo3<'a>(self: &'a Self, other: &Z) { - | -------- help: consider changing this to be a mutable reference: `&mut Z` + | -------- help: consider changing this to be a mutable reference: `&'a mut Self` LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr index 366bfc8fa20..4a693a3b05d 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr @@ -26,7 +26,7 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:102:5 | LL | fn assign_field2<'a>(x: &'a Own) { - | -------------- help: consider changing this to be a mutable reference: `&mut Own` + | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` LL | x.y = 3; //~ ERROR cannot borrow | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -58,7 +58,7 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:143:6 | LL | fn assign_method2<'a>(x: &'a Own) { - | -------------- help: consider changing this to be a mutable reference: `&mut Own` + | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` LL | *x.y_mut() = 3; //~ ERROR cannot borrow | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr index 69bf246ff3f..44a5062cb4d 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr @@ -10,7 +10,7 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:51:11 | LL | fn deref_extend_mut1<'a>(x: &'a Own) -> &'a mut isize { - | -------------- help: consider changing this to be a mutable reference: `&mut Own` + | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` LL | &mut **x //~ ERROR cannot borrow | ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -26,7 +26,7 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:63:6 | LL | fn assign2<'a>(x: &'a Own) { - | -------------- help: consider changing this to be a mutable reference: `&mut Own` + | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` LL | **x = 3; //~ ERROR cannot borrow | ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable diff --git a/src/test/ui/span/mut-arg-hint.nll.stderr b/src/test/ui/span/mut-arg-hint.nll.stderr index f264ea1f916..f42cf6500e2 100644 --- a/src/test/ui/span/mut-arg-hint.nll.stderr +++ b/src/test/ui/span/mut-arg-hint.nll.stderr @@ -10,7 +10,7 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:18:5 | LL | pub fn foo<'a>(mut a: &'a String) { - | ---------- help: consider changing this to be a mutable reference: `&mut std::string::String` + | ---------- help: consider changing this to be a mutable reference: `&'a mut String` LL | a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable diff --git a/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.nll.stderr b/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.nll.stderr index 215faf6c73c..56897baeb4e 100644 --- a/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.nll.stderr +++ b/src/test/ui/trivial-bounds-inconsistent-copy-reborrow.nll.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:16:5 | LL | fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy { - | --------------- help: consider changing this to be a mutable reference: `&mut &mut i32` + | --------------- help: consider changing this to be a mutable reference: `&'a mut &'a mut i32` LL | *t //~ ERROR | ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -10,7 +10,7 @@ error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:20:6 | LL | fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy { - | --------------- help: consider changing this to be a mutable reference: `&mut &mut i32` + | --------------- help: consider changing this to be a mutable reference: `&'a mut &'a mut i32` LL | {*t} //~ ERROR | ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable