@@ -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