@@ -5,11 +5,14 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
5
5
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
6
6
use rustc_middle:: {
7
7
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
+ } ,
9
12
} ;
10
13
use rustc_span:: source_map:: DesugaringKind ;
11
14
use rustc_span:: symbol:: { kw, Symbol } ;
12
- use rustc_span:: Span ;
15
+ use rustc_span:: { BytePos , Span } ;
13
16
14
17
use crate :: borrow_check:: diagnostics:: BorrowedContentSource ;
15
18
use crate :: borrow_check:: MirBorrowckCtxt ;
@@ -241,13 +244,74 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
241
244
. map ( |l| mut_borrow_of_mutable_ref ( l, self . local_names [ local] ) )
242
245
. unwrap_or ( false ) =>
243
246
{
247
+ let decl = & self . body . local_decls [ local] ;
244
248
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
+ }
251
315
}
252
316
253
317
// We want to suggest users use `let mut` for local (user
0 commit comments