@@ -370,12 +370,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
370370 err. span_label ( span, format ! ( "cannot {act}" ) ) ;
371371 }
372372 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) ;
379374 let tcx = self . infcx . tcx ;
380375 if let ty:: Closure ( id, _) = * the_place_err. ty ( self . body , tcx) . ty . kind ( ) {
381376 self . show_mutating_upvar ( tcx, id. expect_local ( ) , the_place_err, & mut err) ;
@@ -710,6 +705,83 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
710705 )
711706 }
712707
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+
713785 // point to span of upvar making closure call require mutable borrow
714786 fn show_mutating_upvar (
715787 & self ,
0 commit comments