Skip to content

Commit dd95392

Browse files
Rollup merge of rust-lang#151661 - estebank:issue-68095, r=mati865
Suggest changing `iter`/`into_iter` when the other was meant When encountering a call to `iter` that should have been `into_iter` and vice-versa, provide a structured suggestion: ``` error[E0271]: type mismatch resolving `<IntoIter<{integer}, 3> as IntoIterator>::Item == &{integer}` --> $DIR/into_iter-when-iter-was-intended.rs:5:37 | LL | let _a = [0, 1, 2].iter().chain([3, 4, 5].into_iter()); | ----- ^^^^^^^^^^^^^^^^^^^^^ expected `&{integer}`, found integer | | | required by a bound introduced by this call | note: the method call chain might not have had the expected associated types --> $DIR/into_iter-when-iter-was-intended.rs:5:47 | LL | let _a = [0, 1, 2].iter().chain([3, 4, 5].into_iter()); | --------- ^^^^^^^^^^^ `IntoIterator::Item` is `{integer}` here | | | this expression has type `[{integer}; 3]` note: required by a bound in `std::iter::Iterator::chain` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL help: consider not consuming the `[{integer}, 3]` to construct the `Iterator` | LL - let _a = [0, 1, 2].iter().chain([3, 4, 5].into_iter()); LL + let _a = [0, 1, 2].iter().chain([3, 4, 5].iter()); | ``` Finish addressing the original case in rust-lang#68095. Only the case of chaining a `Vec` or `[]` is left unhandled.
2 parents abc45d8 + 2b32446 commit dd95392

File tree

6 files changed

+116
-3
lines changed

6 files changed

+116
-3
lines changed

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ symbols! {
270270
Into,
271271
IntoFuture,
272272
IntoIterator,
273+
IntoIteratorItem,
273274
IoBufRead,
274275
IoLines,
275276
IoRead,

compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4390,6 +4390,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
43904390
param_env: ty::ParamEnv<'tcx>,
43914391
path_segment: &hir::PathSegment<'_>,
43924392
args: &[hir::Expr<'_>],
4393+
prev_ty: Ty<'_>,
43934394
err: &mut Diag<'_, G>,
43944395
) {
43954396
let tcx = self.tcx;
@@ -4403,6 +4404,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
44034404
let TypeError::Sorts(expected_found) = diff else {
44044405
continue;
44054406
};
4407+
if tcx.is_diagnostic_item(sym::IntoIteratorItem, *def_id)
4408+
&& path_segment.ident.name == sym::iter
4409+
&& self.can_eq(
4410+
param_env,
4411+
Ty::new_ref(
4412+
tcx,
4413+
tcx.lifetimes.re_erased,
4414+
expected_found.found,
4415+
ty::Mutability::Not,
4416+
),
4417+
*ty,
4418+
)
4419+
&& let [] = args
4420+
{
4421+
// Used `.iter()` when `.into_iter()` was likely meant.
4422+
err.span_suggestion_verbose(
4423+
path_segment.ident.span,
4424+
format!("consider consuming the `{prev_ty}` to construct the `Iterator`"),
4425+
"into_iter".to_string(),
4426+
Applicability::MachineApplicable,
4427+
);
4428+
}
4429+
if tcx.is_diagnostic_item(sym::IntoIteratorItem, *def_id)
4430+
&& path_segment.ident.name == sym::into_iter
4431+
&& self.can_eq(
4432+
param_env,
4433+
expected_found.found,
4434+
Ty::new_ref(tcx, tcx.lifetimes.re_erased, *ty, ty::Mutability::Not),
4435+
)
4436+
&& let [] = args
4437+
{
4438+
// Used `.into_iter()` when `.iter()` was likely meant.
4439+
err.span_suggestion_verbose(
4440+
path_segment.ident.span,
4441+
format!(
4442+
"consider not consuming the `{prev_ty}` to construct the `Iterator`"
4443+
),
4444+
"iter".to_string(),
4445+
Applicability::MachineApplicable,
4446+
);
4447+
}
44064448
if tcx.is_diagnostic_item(sym::IteratorItem, *def_id)
44074449
&& path_segment.ident.name == sym::map
44084450
&& self.can_eq(param_env, expected_found.found, *ty)
@@ -4515,19 +4557,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
45154557
expr = rcvr_expr;
45164558
let assocs_in_this_method =
45174559
self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
4560+
prev_ty = self.resolve_vars_if_possible(
4561+
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
4562+
);
45184563
self.look_for_iterator_item_mistakes(
45194564
&assocs_in_this_method,
45204565
typeck_results,
45214566
&type_diffs,
45224567
param_env,
45234568
path_segment,
45244569
args,
4570+
prev_ty,
45254571
err,
45264572
);
45274573
assocs.push(assocs_in_this_method);
4528-
prev_ty = self.resolve_vars_if_possible(
4529-
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
4530-
);
45314574

45324575
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
45334576
&& let hir::Path { res: Res::Local(hir_id), .. } = path

library/core/src/iter/traits/collect.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ pub trait FromIterator<A>: Sized {
281281
#[stable(feature = "rust1", since = "1.0.0")]
282282
pub trait IntoIterator {
283283
/// The type of the elements being iterated over.
284+
#[rustc_diagnostic_item = "IntoIteratorItem"]
284285
#[stable(feature = "rust1", since = "1.0.0")]
285286
type Item;
286287

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@ run-rustfix
2+
//@ edition:2021
3+
// Suggest using the right `IntoIterator` method. #68095
4+
fn main() {
5+
let _a = [0, 1, 2].iter().chain([3, 4, 5].iter()); //~ ERROR E0271
6+
let _b = [0, 1, 2].into_iter().chain([3, 4, 5].into_iter()); //~ ERROR E0271
7+
// These don't have appropriate suggestions yet.
8+
// let c = [0, 1, 2].iter().chain([3, 4, 5]);
9+
// let d = [0, 1, 2].iter().chain(vec![3, 4, 5]);
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@ run-rustfix
2+
//@ edition:2021
3+
// Suggest using the right `IntoIterator` method. #68095
4+
fn main() {
5+
let _a = [0, 1, 2].iter().chain([3, 4, 5].into_iter()); //~ ERROR E0271
6+
let _b = [0, 1, 2].into_iter().chain([3, 4, 5].iter()); //~ ERROR E0271
7+
// These don't have appropriate suggestions yet.
8+
// let c = [0, 1, 2].iter().chain([3, 4, 5]);
9+
// let d = [0, 1, 2].iter().chain(vec![3, 4, 5]);
10+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
error[E0271]: type mismatch resolving `<IntoIter<{integer}, 3> as IntoIterator>::Item == &{integer}`
2+
--> $DIR/into_iter-when-iter-was-intended.rs:5:37
3+
|
4+
LL | let _a = [0, 1, 2].iter().chain([3, 4, 5].into_iter());
5+
| ----- ^^^^^^^^^^^^^^^^^^^^^ expected `&{integer}`, found integer
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
note: the method call chain might not have had the expected associated types
10+
--> $DIR/into_iter-when-iter-was-intended.rs:5:47
11+
|
12+
LL | let _a = [0, 1, 2].iter().chain([3, 4, 5].into_iter());
13+
| --------- ^^^^^^^^^^^ `IntoIterator::Item` is `{integer}` here
14+
| |
15+
| this expression has type `[{integer}; 3]`
16+
note: required by a bound in `std::iter::Iterator::chain`
17+
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
18+
help: consider not consuming the `[{integer}; 3]` to construct the `Iterator`
19+
|
20+
LL - let _a = [0, 1, 2].iter().chain([3, 4, 5].into_iter());
21+
LL + let _a = [0, 1, 2].iter().chain([3, 4, 5].iter());
22+
|
23+
24+
error[E0271]: type mismatch resolving `<Iter<'_, {integer}> as IntoIterator>::Item == {integer}`
25+
--> $DIR/into_iter-when-iter-was-intended.rs:6:42
26+
|
27+
LL | let _b = [0, 1, 2].into_iter().chain([3, 4, 5].iter());
28+
| ----- ^^^^^^^^^^^^^^^^ expected integer, found `&{integer}`
29+
| |
30+
| required by a bound introduced by this call
31+
|
32+
note: the method call chain might not have had the expected associated types
33+
--> $DIR/into_iter-when-iter-was-intended.rs:6:52
34+
|
35+
LL | let _b = [0, 1, 2].into_iter().chain([3, 4, 5].iter());
36+
| --------- ^^^^^^ `IntoIterator::Item` is `&{integer}` here
37+
| |
38+
| this expression has type `[{integer}; 3]`
39+
note: required by a bound in `std::iter::Iterator::chain`
40+
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
41+
help: consider consuming the `&[{integer}]` to construct the `Iterator`
42+
|
43+
LL | let _b = [0, 1, 2].into_iter().chain([3, 4, 5].into_iter());
44+
| +++++
45+
46+
error: aborting due to 2 previous errors
47+
48+
For more information about this error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)