@@ -225,17 +225,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
225225 }
226226 if suggest {
227227 borrow_spans. var_subdiag (
228- None ,
229- & mut err,
230- Some ( mir:: BorrowKind :: Mut { kind : mir:: MutBorrowKind :: Default } ) ,
231- |_kind, var_span| {
232- let place = self . describe_any_place ( access_place. as_ref ( ) ) ;
233- crate :: session_diagnostics:: CaptureVarCause :: MutableBorrowUsePlaceClosure {
234- place,
235- var_span,
236- }
237- } ,
238- ) ;
228+ None ,
229+ & mut err,
230+ Some ( mir:: BorrowKind :: Mut { kind : mir:: MutBorrowKind :: Default } ) ,
231+ |_kind, var_span| {
232+ let place = self . describe_any_place ( access_place. as_ref ( ) ) ;
233+ crate :: session_diagnostics:: CaptureVarCause :: MutableBorrowUsePlaceClosure {
234+ place,
235+ var_span,
236+ }
237+ } ,
238+ ) ;
239239 }
240240 borrow_span
241241 }
@@ -262,11 +262,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
262262 } => {
263263 err. span_label ( span, format ! ( "cannot {act}" ) ) ;
264264
265- if let Some ( span) = get_mut_span_in_struct_field (
266- self . infcx . tcx ,
267- Place :: ty_from ( local, proj_base, self . body , self . infcx . tcx ) . ty ,
268- * field,
269- ) {
265+ let place = Place :: ty_from ( local, proj_base, self . body , self . infcx . tcx ) ;
266+ if let Some ( span) = get_mut_span_in_struct_field ( self . infcx . tcx , place. ty , * field) {
270267 err. span_suggestion_verbose (
271268 span,
272269 "consider changing this to be mutable" ,
@@ -781,83 +778,88 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
781778
782779 // Attempt to search similar mutable associated items for suggestion.
783780 // In the future, attempt in all path but initially for RHS of for_loop
784- fn suggest_similar_mut_method_for_for_loop ( & self , err : & mut Diagnostic ) {
781+ fn suggest_similar_mut_method_for_for_loop ( & self , err : & mut Diagnostic , span : Span ) {
785782 use hir:: {
786- Expr ,
787- ExprKind :: { Block , Call , DropTemps , Match , MethodCall } ,
783+ BorrowKind , Expr ,
784+ ExprKind :: { AddrOf , Block , Call , MethodCall } ,
788785 } ;
789786
790787 let hir_map = self . infcx . tcx . hir ( ) ;
791- if let Some ( body_id) = hir_map. maybe_body_owned_by ( self . mir_def_id ( ) ) {
792- if let Block (
793- hir:: Block {
794- expr :
795- Some ( Expr {
796- kind :
797- DropTemps ( Expr {
798- kind :
799- Match (
800- Expr {
801- kind :
802- Call (
803- _,
804- [
805- Expr {
806- kind :
807- MethodCall ( path_segment, _, _, span) ,
808- hir_id,
809- ..
810- } ,
811- ..,
812- ] ,
813- ) ,
814- ..
815- } ,
816- ..,
817- ) ,
818- ..
819- } ) ,
820- ..
821- } ) ,
822- ..
823- } ,
824- _,
825- ) = hir_map. body ( body_id) . value . kind
826- {
827- let opt_suggestions = self
828- . infcx
829- . tcx
830- . typeck ( path_segment. hir_id . owner . def_id )
831- . type_dependent_def_id ( * hir_id)
832- . and_then ( |def_id| self . infcx . tcx . impl_of_method ( def_id) )
833- . map ( |def_id| self . infcx . tcx . associated_items ( def_id) )
834- . map ( |assoc_items| {
835- assoc_items
836- . in_definition_order ( )
837- . map ( |assoc_item_def| assoc_item_def. ident ( self . infcx . tcx ) )
838- . filter ( |& ident| {
839- let original_method_ident = path_segment. ident ;
840- original_method_ident != ident
841- && ident
842- . as_str ( )
843- . starts_with ( & original_method_ident. name . to_string ( ) )
844- } )
845- . map ( |ident| format ! ( "{ident}()" ) )
846- . peekable ( )
847- } ) ;
788+ struct Finder < ' tcx > {
789+ span : Span ,
790+ expr : Option < & ' tcx Expr < ' tcx > > ,
791+ }
848792
849- if let Some ( mut suggestions) = opt_suggestions
850- && suggestions. peek ( ) . is_some ( )
851- {
852- err. span_suggestions (
853- * span,
854- "use mutable method" ,
855- suggestions,
856- Applicability :: MaybeIncorrect ,
857- ) ;
793+ impl < ' tcx > Visitor < ' tcx > for Finder < ' tcx > {
794+ fn visit_expr ( & mut self , e : & ' tcx hir:: Expr < ' tcx > ) {
795+ if e. span == self . span && self . expr . is_none ( ) {
796+ self . expr = Some ( e) ;
858797 }
798+ hir:: intravisit:: walk_expr ( self , e) ;
859799 }
860- } ;
800+ }
801+ if let Some ( body_id) = hir_map. maybe_body_owned_by ( self . mir_def_id ( ) )
802+ && let Block ( block, _) = hir_map. body ( body_id) . value . kind
803+ {
804+ // `span` corresponds to the expression being iterated, find the `for`-loop desugared
805+ // expression with that span in order to identify potential fixes when encountering a
806+ // read-only iterator that should be mutable.
807+ let mut v = Finder {
808+ span,
809+ expr : None ,
810+ } ;
811+ v. visit_block ( block) ;
812+ if let Some ( expr) = v. expr && let Call ( _, [ expr] ) = expr. kind {
813+ match expr. kind {
814+ MethodCall ( path_segment, _, _, span) => {
815+ // We have `for _ in iter.read_only_iter()`, try to
816+ // suggest `for _ in iter.mutable_iter()` instead.
817+ let opt_suggestions = self
818+ . infcx
819+ . tcx
820+ . typeck ( path_segment. hir_id . owner . def_id )
821+ . type_dependent_def_id ( expr. hir_id )
822+ . and_then ( |def_id| self . infcx . tcx . impl_of_method ( def_id) )
823+ . map ( |def_id| self . infcx . tcx . associated_items ( def_id) )
824+ . map ( |assoc_items| {
825+ assoc_items
826+ . in_definition_order ( )
827+ . map ( |assoc_item_def| assoc_item_def. ident ( self . infcx . tcx ) )
828+ . filter ( |& ident| {
829+ let original_method_ident = path_segment. ident ;
830+ original_method_ident != ident
831+ && ident. as_str ( ) . starts_with (
832+ & original_method_ident. name . to_string ( ) ,
833+ )
834+ } )
835+ . map ( |ident| format ! ( "{ident}()" ) )
836+ . peekable ( )
837+ } ) ;
838+
839+ if let Some ( mut suggestions) = opt_suggestions
840+ && suggestions. peek ( ) . is_some ( )
841+ {
842+ err. span_suggestions (
843+ span,
844+ "use mutable method" ,
845+ suggestions,
846+ Applicability :: MaybeIncorrect ,
847+ ) ;
848+ }
849+ }
850+ AddrOf ( BorrowKind :: Ref , Mutability :: Not , expr) => {
851+ // We have `for _ in &i`, suggest `for _ in &mut i`.
852+ err. span_suggestion_verbose (
853+ expr. span . shrink_to_lo ( ) ,
854+ "use a mutable iterator instead" ,
855+ "mut " . to_string ( ) ,
856+ Applicability :: MachineApplicable ,
857+ ) ;
858+ }
859+ _ => { }
860+ }
861+ }
862+ }
861863 }
862864
863865 /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
@@ -1003,9 +1005,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
10031005 match opt_assignment_rhs_span. and_then ( |s| s. desugaring_kind ( ) ) {
10041006 // on for loops, RHS points to the iterator part
10051007 Some ( DesugaringKind :: ForLoop ) => {
1006- self . suggest_similar_mut_method_for_for_loop ( err) ;
1008+ let span = opt_assignment_rhs_span. unwrap ( ) ;
1009+ self . suggest_similar_mut_method_for_for_loop ( err, span) ;
10071010 err. span_label (
1008- opt_assignment_rhs_span . unwrap ( ) ,
1011+ span ,
10091012 format ! ( "this iterator yields `{pointer_sigil}` {pointer_desc}s" , ) ,
10101013 ) ;
10111014 None
0 commit comments