@@ -376,15 +376,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
376376 opt_assignment_rhs_span. and_then ( |span| span. desugaring_kind ( ) ) ;
377377 match opt_desugaring_kind {
378378 // on for loops, RHS points to the iterator part
379- Some ( DesugaringKind :: ForLoop ( _) ) => Some ( (
380- false ,
381- opt_assignment_rhs_span. unwrap ( ) ,
382- format ! (
383- "this iterator yields `{SIGIL}` {DESC}s" ,
384- SIGIL = pointer_sigil,
385- DESC = pointer_desc
386- ) ,
387- ) ) ,
379+ Some ( DesugaringKind :: ForLoop ( _) ) => {
380+ self . suggest_similar_mut_method_for_for_loop ( & mut err) ;
381+ Some ( (
382+ false ,
383+ opt_assignment_rhs_span. unwrap ( ) ,
384+ format ! (
385+ "this iterator yields `{SIGIL}` {DESC}s" ,
386+ SIGIL = pointer_sigil,
387+ DESC = pointer_desc
388+ ) ,
389+ ) )
390+ }
388391 // don't create labels for compiler-generated spans
389392 Some ( _) => None ,
390393 None => {
@@ -537,6 +540,79 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
537540 ) ;
538541 }
539542
543+ // Attempt to search similar mutable assosiated items for suggestion.
544+ // In the future, attempt in all path but initially for RHS of for_loop
545+ fn suggest_similar_mut_method_for_for_loop ( & self , err : & mut DiagnosticBuilder < ' _ > ) {
546+ let hir = self . infcx . tcx . hir ( ) ;
547+ let node = hir. item ( self . mir_hir_id ( ) ) ;
548+ use hir:: {
549+ Expr ,
550+ ExprKind :: { Block , Call , DropTemps , Match , MethodCall } ,
551+ } ;
552+ if let hir:: ItemKind :: Fn ( _, _, body_id) = node. kind {
553+ if let Block (
554+ hir:: Block {
555+ expr :
556+ Some ( Expr {
557+ kind :
558+ DropTemps ( Expr {
559+ kind :
560+ Match (
561+ Expr {
562+ kind :
563+ Call (
564+ _,
565+ [ Expr {
566+ kind : MethodCall ( path_segment, ..) ,
567+ hir_id,
568+ ..
569+ } , ..] ,
570+ ) ,
571+ ..
572+ } ,
573+ ..,
574+ ) ,
575+ ..
576+ } ) ,
577+ ..
578+ } ) ,
579+ ..
580+ } ,
581+ _,
582+ ) = hir. body ( body_id) . value . kind
583+ {
584+ let opt_suggestions = path_segment
585+ . hir_id
586+ . map ( |path_hir_id| self . infcx . tcx . typeck ( path_hir_id. owner ) )
587+ . and_then ( |typeck| typeck. type_dependent_def_id ( * hir_id) )
588+ . and_then ( |def_id| self . infcx . tcx . impl_of_method ( def_id) )
589+ . map ( |def_id| self . infcx . tcx . associated_items ( def_id) )
590+ . map ( |assoc_items| {
591+ assoc_items
592+ . in_definition_order ( )
593+ . map ( |assoc_item_def| assoc_item_def. ident )
594+ . filter ( |& ident| {
595+ let original_method_ident = path_segment. ident ;
596+ original_method_ident != ident
597+ && ident
598+ . as_str ( )
599+ . starts_with ( & original_method_ident. name . to_string ( ) )
600+ } )
601+ . map ( |ident| format ! ( "{}()" , ident) )
602+ } ) ;
603+
604+ if let Some ( suggestions) = opt_suggestions {
605+ err. span_suggestions (
606+ path_segment. ident . span ,
607+ & format ! ( "use mutable method" ) ,
608+ suggestions,
609+ Applicability :: MaybeIncorrect ,
610+ ) ;
611+ }
612+ }
613+ } ;
614+ }
615+
540616 /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
541617 fn expected_fn_found_fn_mut_call ( & self , err : & mut DiagnosticBuilder < ' _ > , sp : Span , act : & str ) {
542618 err. span_label ( sp, format ! ( "cannot {}" , act) ) ;
0 commit comments