@@ -5,11 +5,14 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
55use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
66use rustc_middle:: {
77 hir:: place:: PlaceBase ,
8- mir:: { self , ClearCrossCrate , Local , LocalDecl , LocalInfo , LocalKind , Location } ,
8+ mir:: {
9+ self , BindingForm , ClearCrossCrate , ImplicitSelfKind , Local , LocalDecl , LocalInfo ,
10+ LocalKind , Location ,
11+ } ,
912} ;
1013use rustc_span:: source_map:: DesugaringKind ;
1114use rustc_span:: symbol:: { kw, Symbol } ;
12- use rustc_span:: Span ;
15+ use rustc_span:: { BytePos , Span } ;
1316
1417use crate :: borrow_check:: diagnostics:: BorrowedContentSource ;
1518use crate :: borrow_check:: MirBorrowckCtxt ;
@@ -241,13 +244,74 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
241244 . map ( |l| mut_borrow_of_mutable_ref ( l, self . local_names [ local] ) )
242245 . unwrap_or ( false ) =>
243246 {
247+ let decl = & self . body . local_decls [ local] ;
244248 err. span_label ( span, format ! ( "cannot {ACT}" , ACT = act) ) ;
245- err. span_suggestion (
246- span,
247- "try removing `&mut` here" ,
248- String :: new ( ) ,
249- Applicability :: MaybeIncorrect ,
250- ) ;
249+ if let Some ( mir:: Statement {
250+ source_info,
251+ kind :
252+ mir:: StatementKind :: Assign ( box (
253+ _,
254+ mir:: Rvalue :: Ref (
255+ _,
256+ mir:: BorrowKind :: Mut { allow_two_phase_borrow : false } ,
257+ _,
258+ ) ,
259+ ) ) ,
260+ ..
261+ } ) = & self . body [ location. block ] . statements . get ( location. statement_index )
262+ {
263+ match decl. local_info {
264+ Some ( box LocalInfo :: User ( ClearCrossCrate :: Set ( BindingForm :: Var (
265+ mir:: VarBindingForm {
266+ binding_mode : ty:: BindingMode :: BindByValue ( Mutability :: Not ) ,
267+ opt_ty_info : Some ( sp) ,
268+ opt_match_place : _,
269+ pat_span : _,
270+ } ,
271+ ) ) ) ) => {
272+ err. span_note ( sp, "the binding is already a mutable borrow" ) ;
273+ }
274+ _ => {
275+ err. span_note (
276+ decl. source_info . span ,
277+ "the binding is already a mutable borrow" ,
278+ ) ;
279+ }
280+ }
281+ if let Ok ( snippet) =
282+ self . infcx . tcx . sess . source_map ( ) . span_to_snippet ( source_info. span )
283+ {
284+ if snippet. starts_with ( "&mut " ) {
285+ // We don't have access to the HIR to get accurate spans, but we can
286+ // give a best effort structured suggestion.
287+ err. span_suggestion_verbose (
288+ source_info. span . with_hi ( source_info. span . lo ( ) + BytePos ( 5 ) ) ,
289+ "try removing `&mut` here" ,
290+ String :: new ( ) ,
291+ Applicability :: MachineApplicable ,
292+ ) ;
293+ } else {
294+ // This can occur with things like `(&mut self).foo()`.
295+ err. span_help ( source_info. span , "try removing `&mut` here" ) ;
296+ }
297+ } else {
298+ err. span_help ( source_info. span , "try removing `&mut` here" ) ;
299+ }
300+ } else if decl. mutability == Mutability :: Not
301+ && !matches ! (
302+ decl. local_info,
303+ Some ( box LocalInfo :: User ( ClearCrossCrate :: Set ( BindingForm :: ImplicitSelf (
304+ ImplicitSelfKind :: MutRef
305+ ) ) ) )
306+ )
307+ {
308+ err. span_suggestion_verbose (
309+ decl. source_info . span . shrink_to_lo ( ) ,
310+ "consider making the binding mutable" ,
311+ "mut " . to_string ( ) ,
312+ Applicability :: MachineApplicable ,
313+ ) ;
314+ }
251315 }
252316
253317 // We want to suggest users use `let mut` for local (user
0 commit comments