@@ -24,14 +24,18 @@ use rustc_hir as hir;
2424use rustc_hir:: def_id:: { DefId , LocalDefId } ;
2525use rustc_hir:: intravisit:: { self , Visitor } ;
2626use rustc_hir:: { GenericParamKind , Node } ;
27+ use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
28+ use rustc_infer:: infer:: TyCtxtInferExt ;
2729use rustc_middle:: hir:: nested_filter;
2830use rustc_middle:: ty:: query:: Providers ;
2931use rustc_middle:: ty:: util:: { Discr , IntTypeExt } ;
3032use rustc_middle:: ty:: { self , AdtKind , Const , IsSuggestable , ToPredicate , Ty , TyCtxt } ;
3133use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
3234use rustc_span:: Span ;
3335use rustc_target:: spec:: abi;
36+ use rustc_trait_selection:: infer:: InferCtxtExt ;
3437use rustc_trait_selection:: traits:: error_reporting:: suggestions:: NextTypeParamName ;
38+ use rustc_trait_selection:: traits:: ObligationCtxt ;
3539use std:: iter;
3640
3741mod generics_of;
@@ -1224,7 +1228,17 @@ fn infer_return_ty_for_fn_sig<'tcx>(
12241228 // to prevent the user from getting a papercut while trying to use the unique closure
12251229 // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
12261230 diag. help ( "consider using an `Fn`, `FnMut`, or `FnOnce` trait bound" ) ;
1227- diag. note ( "for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html" ) ;
1231+ diag. note (
1232+ "for more information on `Fn` traits and closure types, see \
1233+ https://doc.rust-lang.org/book/ch13-01-closures.html",
1234+ ) ;
1235+ } else if let Some ( i_ty) = suggest_impl_iterator ( tcx, ret_ty, ty. span , hir_id, def_id) {
1236+ diag. span_suggestion (
1237+ ty. span ,
1238+ "replace with an appropriate return type" ,
1239+ format ! ( "impl Iterator<Item = {}>" , i_ty) ,
1240+ Applicability :: MachineApplicable ,
1241+ ) ;
12281242 }
12291243 diag. emit ( ) ;
12301244
@@ -1242,6 +1256,51 @@ fn infer_return_ty_for_fn_sig<'tcx>(
12421256 }
12431257}
12441258
1259+ fn suggest_impl_iterator < ' tcx > (
1260+ tcx : TyCtxt < ' tcx > ,
1261+ ret_ty : Ty < ' tcx > ,
1262+ span : Span ,
1263+ hir_id : hir:: HirId ,
1264+ def_id : LocalDefId ,
1265+ ) -> Option < Ty < ' tcx > > {
1266+ let Some ( iter_trait) = tcx. get_diagnostic_item ( sym:: Iterator ) else { return None ; } ;
1267+ let Some ( iterator_item) = tcx. get_diagnostic_item ( sym:: IteratorItem ) else { return None ; } ;
1268+ if !tcx
1269+ . infer_ctxt ( )
1270+ . build ( )
1271+ . type_implements_trait ( iter_trait, [ ret_ty] , tcx. param_env ( def_id) )
1272+ . must_apply_modulo_regions ( )
1273+ {
1274+ return None ;
1275+ }
1276+ let infcx = tcx. infer_ctxt ( ) . build ( ) ;
1277+ let ocx = ObligationCtxt :: new_in_snapshot ( & infcx) ;
1278+ // Find the type of `Iterator::Item`.
1279+ let origin = TypeVariableOrigin { kind : TypeVariableOriginKind :: TypeInference , span } ;
1280+ let ty_var = infcx. next_ty_var ( origin) ;
1281+ let projection = ty:: Binder :: dummy ( ty:: PredicateKind :: Clause ( ty:: Clause :: Projection (
1282+ ty:: ProjectionPredicate {
1283+ projection_ty : tcx. mk_alias_ty ( iterator_item, tcx. mk_substs ( [ ret_ty. into ( ) ] . iter ( ) ) ) ,
1284+ term : ty_var. into ( ) ,
1285+ } ,
1286+ ) ) ) ;
1287+ // Add `<ret_ty as Iterator>::Item = _` obligation.
1288+ ocx. register_obligation ( crate :: traits:: Obligation :: misc (
1289+ tcx,
1290+ span,
1291+ hir_id,
1292+ tcx. param_env ( def_id) ,
1293+ projection,
1294+ ) ) ;
1295+ if ocx. select_where_possible ( ) . is_empty ( )
1296+ && let item_ty = infcx. resolve_vars_if_possible ( ty_var)
1297+ && item_ty. is_suggestable ( tcx, false )
1298+ {
1299+ return Some ( item_ty) ;
1300+ }
1301+ None
1302+ }
1303+
12451304fn impl_trait_ref ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> Option < ty:: TraitRef < ' _ > > {
12461305 let icx = ItemCtxt :: new ( tcx, def_id) ;
12471306 let item = tcx. hir ( ) . expect_item ( def_id. expect_local ( ) ) ;
0 commit comments