@@ -109,6 +109,93 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
109109        self . autoderef ( span,  ty) . any ( |( ty,  _) | matches ! ( ty. kind( ) ,  ty:: Slice ( ..)  | ty:: Array ( ..) ) ) 
110110    } 
111111
112+     fn  impl_into_iterator_should_be_iterator ( 
113+         & self , 
114+         ty :  Ty < ' tcx > , 
115+         span :  Span , 
116+         unsatisfied_predicates :  & Vec < ( 
117+             ty:: Predicate < ' _ > , 
118+             Option < ty:: Predicate < ' _ > > , 
119+             Option < ObligationCause < ' _ > > , 
120+         ) > , 
121+     )  -> bool  { 
122+         fn  predicate_bounds_generic_param < ' tcx > ( 
123+             predicate :  ty:: Predicate < ' _ > , 
124+             generics :  & ' tcx  ty:: Generics , 
125+             generic_param :  & ty:: GenericParamDef , 
126+             tcx :  TyCtxt < ' tcx > , 
127+         )  -> bool  { 
128+             if  let  ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( trait_pred) )  =
129+                 predicate. kind ( ) . as_ref ( ) . skip_binder ( ) 
130+             { 
131+                 let  ty:: TraitPredicate  {  trait_ref :  ty:: TraitRef  {  args,  .. } ,  .. }  = trait_pred; 
132+                 if  args. is_empty ( )  { 
133+                     return  false ; 
134+                 } 
135+                 let  Some ( arg_ty)  = args[ 0 ] . as_type ( )  else  { 
136+                     return  false ; 
137+                 } ; 
138+                 let  ty:: Param ( param)  = arg_ty. kind ( )  else  { 
139+                     return  false ; 
140+                 } ; 
141+                 // Is `generic_param` the same as the arg for this trait predicate? 
142+                 generic_param. index  == generics. type_param ( & param,  tcx) . index 
143+             }  else  { 
144+                 false 
145+             } 
146+         } 
147+ 
148+         fn  is_iterator_predicate ( predicate :  ty:: Predicate < ' _ > ,  tcx :  TyCtxt < ' _ > )  -> bool  { 
149+             if  let  ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( trait_pred) )  =
150+                 predicate. kind ( ) . as_ref ( ) . skip_binder ( ) 
151+             { 
152+                 tcx. is_diagnostic_item ( sym:: Iterator ,  trait_pred. trait_ref . def_id ) 
153+             }  else  { 
154+                 false 
155+             } 
156+         } 
157+ 
158+         // Does the `ty` implement `IntoIterator`? 
159+         let  Some ( into_iterator_trait)  = self . tcx . get_diagnostic_item ( sym:: IntoIterator )  else  { 
160+             return  false ; 
161+         } ; 
162+         let  trait_ref = ty:: TraitRef :: new ( self . tcx ,  into_iterator_trait,  [ ty] ) ; 
163+         let  cause = ObligationCause :: new ( span,  self . body_id ,  ObligationCauseCode :: MiscObligation ) ; 
164+         let  obligation = Obligation :: new ( self . tcx ,  cause,  self . param_env ,  trait_ref) ; 
165+         if  !self . predicate_must_hold_modulo_regions ( & obligation)  { 
166+             return  false ; 
167+         } 
168+ 
169+         match  ty. kind ( )  { 
170+             ty:: Param ( param)  => { 
171+                 let  generics = self . tcx . generics_of ( self . body_id ) ; 
172+                 let  generic_param = generics. type_param ( & param,  self . tcx ) ; 
173+                 for  unsatisfied in  unsatisfied_predicates. iter ( )  { 
174+                     // The parameter implements `IntoIterator` 
175+                     // but it has called a method that requires it to implement `Iterator` 
176+                     if  predicate_bounds_generic_param ( 
177+                         unsatisfied. 0 , 
178+                         generics, 
179+                         generic_param, 
180+                         self . tcx , 
181+                     )  && is_iterator_predicate ( unsatisfied. 0 ,  self . tcx ) 
182+                     { 
183+                         return  true ; 
184+                     } 
185+                 } 
186+             } 
187+             ty:: Alias ( ty:: AliasKind :: Opaque ,  _)  => { 
188+                 for  unsatisfied in  unsatisfied_predicates. iter ( )  { 
189+                     if  is_iterator_predicate ( unsatisfied. 0 ,  self . tcx )  { 
190+                         return  true ; 
191+                     } 
192+                 } 
193+             } 
194+             _ => return  false , 
195+         } 
196+         false 
197+     } 
198+ 
112199    #[ instrument( level = "debug" ,  skip( self ) ) ]  
113200    pub  fn  report_method_error ( 
114201        & self , 
@@ -555,6 +642,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
555642                    "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement" 
556643                ) ) ; 
557644            } 
645+         }  else  if  self . impl_into_iterator_should_be_iterator ( rcvr_ty,  span,  unsatisfied_predicates) 
646+         { 
647+             err. span_label ( span,  format ! ( "`{rcvr_ty}` is not an iterator" ) ) ; 
648+             err. multipart_suggestion_verbose ( 
649+                 "call `.into_iter()` first" , 
650+                 vec ! [ ( span. shrink_to_lo( ) ,  format!( "into_iter()." ) ) ] , 
651+                 Applicability :: MaybeIncorrect , 
652+             ) ; 
653+             return  Some ( err) ; 
558654        }  else  if  !unsatisfied_predicates. is_empty ( )  && matches ! ( rcvr_ty. kind( ) ,  ty:: Param ( _) )  { 
559655            // We special case the situation where we are looking for `_` in 
560656            // `<TypeParam as _>::method` because otherwise the machinery will look for blanket 
0 commit comments