@@ -24,14 +24,18 @@ use rustc_hir as hir;
24
24
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
25
25
use rustc_hir:: intravisit:: { self , Visitor } ;
26
26
use rustc_hir:: { GenericParamKind , Node } ;
27
+ use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
28
+ use rustc_infer:: infer:: TyCtxtInferExt ;
27
29
use rustc_middle:: hir:: nested_filter;
28
30
use rustc_middle:: ty:: query:: Providers ;
29
31
use rustc_middle:: ty:: util:: { Discr , IntTypeExt } ;
30
32
use rustc_middle:: ty:: { self , AdtKind , Const , IsSuggestable , ToPredicate , Ty , TyCtxt } ;
31
33
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
32
34
use rustc_span:: Span ;
33
35
use rustc_target:: spec:: abi;
36
+ use rustc_trait_selection:: infer:: InferCtxtExt ;
34
37
use rustc_trait_selection:: traits:: error_reporting:: suggestions:: NextTypeParamName ;
38
+ use rustc_trait_selection:: traits:: ObligationCtxt ;
35
39
use std:: iter;
36
40
37
41
mod generics_of;
@@ -1224,7 +1228,17 @@ fn infer_return_ty_for_fn_sig<'tcx>(
1224
1228
// to prevent the user from getting a papercut while trying to use the unique closure
1225
1229
// syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
1226
1230
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
+ ) ;
1228
1242
}
1229
1243
diag. emit ( ) ;
1230
1244
@@ -1242,6 +1256,51 @@ fn infer_return_ty_for_fn_sig<'tcx>(
1242
1256
}
1243
1257
}
1244
1258
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
+
1245
1304
fn impl_trait_ref ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> Option < ty:: TraitRef < ' _ > > {
1246
1305
let icx = ItemCtxt :: new ( tcx, def_id) ;
1247
1306
let item = tcx. hir ( ) . expect_item ( def_id. expect_local ( ) ) ;
0 commit comments