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