@@ -370,12 +370,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
370
370
err. span_label ( span, format ! ( "cannot {act}" ) ) ;
371
371
}
372
372
if suggest {
373
- err. span_suggestion_verbose (
374
- local_decl. source_info . span . shrink_to_lo ( ) ,
375
- "consider changing this to be mutable" ,
376
- "mut " ,
377
- Applicability :: MachineApplicable ,
378
- ) ;
373
+ self . construct_mut_suggestion_for_local_binding_patterns ( & mut err, local) ;
379
374
let tcx = self . infcx . tcx ;
380
375
if let ty:: Closure ( id, _) = * the_place_err. ty ( self . body , tcx) . ty . kind ( ) {
381
376
self . show_mutating_upvar ( tcx, id. expect_local ( ) , the_place_err, & mut err) ;
@@ -710,6 +705,83 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
710
705
)
711
706
}
712
707
708
+ fn construct_mut_suggestion_for_local_binding_patterns (
709
+ & self ,
710
+ err : & mut DiagnosticBuilder < ' _ , ErrorGuaranteed > ,
711
+ local : Local ,
712
+ ) {
713
+ let local_decl = & self . body . local_decls [ local] ;
714
+ debug ! ( "local_decl: {:?}" , local_decl) ;
715
+ let pat_span = match * local_decl. local_info ( ) {
716
+ LocalInfo :: User ( BindingForm :: Var ( mir:: VarBindingForm {
717
+ binding_mode : ty:: BindingMode :: BindByValue ( Mutability :: Not ) ,
718
+ opt_ty_info : _,
719
+ opt_match_place : _,
720
+ pat_span,
721
+ } ) ) => pat_span,
722
+ _ => local_decl. source_info . span ,
723
+ } ;
724
+
725
+ struct BindingFinder {
726
+ span : Span ,
727
+ hir_id : Option < hir:: HirId > ,
728
+ }
729
+
730
+ impl < ' tcx > Visitor < ' tcx > for BindingFinder {
731
+ fn visit_stmt ( & mut self , s : & ' tcx hir:: Stmt < ' tcx > ) {
732
+ if let hir:: StmtKind :: Local ( local) = s. kind {
733
+ if local. pat . span == self . span {
734
+ self . hir_id = Some ( local. hir_id ) ;
735
+ }
736
+ }
737
+ hir:: intravisit:: walk_stmt ( self , s) ;
738
+ }
739
+ }
740
+
741
+ let hir_map = self . infcx . tcx . hir ( ) ;
742
+ let def_id = self . body . source . def_id ( ) ;
743
+ let hir_id = if let Some ( local_def_id) = def_id. as_local ( )
744
+ && let Some ( body_id) = hir_map. maybe_body_owned_by ( local_def_id)
745
+ {
746
+ let body = hir_map. body ( body_id) ;
747
+ let mut v = BindingFinder {
748
+ span : pat_span,
749
+ hir_id : None ,
750
+ } ;
751
+ v. visit_body ( body) ;
752
+ v. hir_id
753
+ } else {
754
+ None
755
+ } ;
756
+
757
+ // With ref-binding patterns, the mutability suggestion has to apply to
758
+ // the binding, not the reference (which would be a type error):
759
+ //
760
+ // `let &b = a;` -> `let &(mut b) = a;`
761
+ if let Some ( hir_id) = hir_id
762
+ && let Some ( hir:: Node :: Local ( hir:: Local {
763
+ pat : hir:: Pat { kind : hir:: PatKind :: Ref ( _, _) , .. } ,
764
+ ..
765
+ } ) ) = hir_map. find ( hir_id)
766
+ && let Ok ( name) = self . infcx . tcx . sess . source_map ( ) . span_to_snippet ( local_decl. source_info . span )
767
+ {
768
+ err. span_suggestion (
769
+ pat_span,
770
+ "consider changing this to be mutable" ,
771
+ format ! ( "&(mut {name})" ) ,
772
+ Applicability :: MachineApplicable ,
773
+ ) ;
774
+ return ;
775
+ }
776
+
777
+ err. span_suggestion_verbose (
778
+ local_decl. source_info . span . shrink_to_lo ( ) ,
779
+ "consider changing this to be mutable" ,
780
+ "mut " ,
781
+ Applicability :: MachineApplicable ,
782
+ ) ;
783
+ }
784
+
713
785
// point to span of upvar making closure call require mutable borrow
714
786
fn show_mutating_upvar (
715
787
& self ,
0 commit comments