Skip to content

Commit 31f5e75

Browse files
authored
Rollup merge of #106172 - estebank:suggest-impl-trait, r=compiler-errors
Suggest `impl Iterator` when possible for `_` return type Address #106096.
2 parents f33ea41 + b400bde commit 31f5e75

File tree

7 files changed

+101
-10
lines changed

7 files changed

+101
-10
lines changed

Diff for: compiler/rustc_hir_analysis/src/collect.rs

+60-1
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,18 @@ use rustc_hir as hir;
2424
use rustc_hir::def_id::{DefId, LocalDefId};
2525
use rustc_hir::intravisit::{self, Visitor};
2626
use rustc_hir::{GenericParamKind, Node};
27+
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
28+
use rustc_infer::infer::TyCtxtInferExt;
2729
use rustc_middle::hir::nested_filter;
2830
use rustc_middle::ty::query::Providers;
2931
use rustc_middle::ty::util::{Discr, IntTypeExt};
3032
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
3133
use rustc_span::symbol::{kw, sym, Ident, Symbol};
3234
use rustc_span::Span;
3335
use rustc_target::spec::abi;
36+
use rustc_trait_selection::infer::InferCtxtExt;
3437
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
38+
use rustc_trait_selection::traits::ObligationCtxt;
3539
use std::iter;
3640

3741
mod 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+
12451304
fn 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());

Diff for: compiler/rustc_hir_analysis/src/collect/type_of.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use rustc_hir::intravisit;
55
use rustc_hir::intravisit::Visitor;
66
use rustc_hir::{HirId, Node};
77
use rustc_middle::hir::nested_filter;
8+
use rustc_middle::ty::print::with_forced_trimmed_paths;
89
use rustc_middle::ty::subst::InternalSubsts;
910
use rustc_middle::ty::util::IntTypeExt;
1011
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
@@ -907,10 +908,10 @@ fn infer_placeholder_type<'a>(
907908
Applicability::MachineApplicable,
908909
);
909910
} else {
910-
err.span_note(
911+
with_forced_trimmed_paths!(err.span_note(
911912
tcx.hir().body(body_id).value.span,
912-
&format!("however, the inferred type `{}` cannot be named", ty),
913-
);
913+
&format!("however, the inferred type `{ty}` cannot be named"),
914+
));
914915
}
915916
}
916917

@@ -931,10 +932,10 @@ fn infer_placeholder_type<'a>(
931932
Applicability::MaybeIncorrect,
932933
);
933934
} else {
934-
diag.span_note(
935+
with_forced_trimmed_paths!(diag.span_note(
935936
tcx.hir().body(body_id).value.span,
936-
&format!("however, the inferred type `{}` cannot be named", ty),
937-
);
937+
&format!("however, the inferred type `{ty}` cannot be named"),
938+
));
938939
}
939940
}
940941

Diff for: compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ symbols! {
213213
Is,
214214
ItemContext,
215215
Iterator,
216+
IteratorItem,
216217
Layout,
217218
Left,
218219
LinkedList,

Diff for: library/core/src/iter/traits/iterator.rs

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
6666
#[must_use = "iterators are lazy and do nothing unless consumed"]
6767
pub trait Iterator {
6868
/// The type of the elements being iterated over.
69+
#[rustc_diagnostic_item = "IteratorItem"]
6970
#[stable(feature = "rust1", since = "1.0.0")]
7071
type Item;
7172

Diff for: src/test/ui/suggestions/unnamable-types.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures
1919
LL | const C: _ = || 42;
2020
| ^ not allowed in type signatures
2121
|
22-
note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:16]` cannot be named
22+
note: however, the inferred type `[closure@unnamable-types.rs:17:14]` cannot be named
2323
--> $DIR/unnamable-types.rs:17:14
2424
|
2525
LL | const C: _ = || 42;
@@ -31,7 +31,7 @@ error: missing type for `const` item
3131
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
3232
| ^
3333
|
34-
note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:45]>` cannot be named
34+
note: however, the inferred type `S<[closure@unnamable-types.rs:23:31]>` cannot be named
3535
--> $DIR/unnamable-types.rs:23:11
3636
|
3737
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };

Diff for: src/test/ui/typeck/typeck_type_placeholder_item.rs

+8
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,11 @@ fn value() -> Option<&'static _> {
220220

221221
const _: Option<_> = map(value);
222222
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
223+
224+
fn evens_squared(n: usize) -> _ {
225+
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
226+
(1..n).filter(|x| x % 2 == 0).map(|x| x * x)
227+
}
228+
229+
const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
230+
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants

Diff for: src/test/ui/typeck/typeck_type_placeholder_item.stderr

+22-1
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,27 @@ LL | const _: Option<_> = map(value);
428428
| not allowed in type signatures
429429
| help: replace with the correct type: `Option<u8>`
430430

431+
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
432+
--> $DIR/typeck_type_placeholder_item.rs:224:31
433+
|
434+
LL | fn evens_squared(n: usize) -> _ {
435+
| ^
436+
| |
437+
| not allowed in type signatures
438+
| help: replace with an appropriate return type: `impl Iterator<Item = usize>`
439+
440+
error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
441+
--> $DIR/typeck_type_placeholder_item.rs:229:10
442+
|
443+
LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
444+
| ^ not allowed in type signatures
445+
|
446+
note: however, the inferred type `Map<Filter<Range<i32>, [closure@typeck_type_placeholder_item.rs:229:29]>, [closure@typeck_type_placeholder_item.rs:229:49]>` cannot be named
447+
--> $DIR/typeck_type_placeholder_item.rs:229:14
448+
|
449+
LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
450+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
451+
431452
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
432453
--> $DIR/typeck_type_placeholder_item.rs:140:31
433454
|
@@ -636,7 +657,7 @@ LL | const D: _ = 42;
636657
| not allowed in type signatures
637658
| help: replace with the correct type: `i32`
638659

639-
error: aborting due to 69 previous errors
660+
error: aborting due to 71 previous errors
640661

641662
Some errors have detailed explanations: E0121, E0282, E0403.
642663
For more information about an error, try `rustc --explain E0121`.

0 commit comments

Comments
 (0)