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());
|
```
This commit is contained in:
parent
38c71295e8
commit
2b32446c7c
6 changed files with 116 additions and 3 deletions
|
|
@ -270,6 +270,7 @@ symbols! {
|
|||
Into,
|
||||
IntoFuture,
|
||||
IntoIterator,
|
||||
IntoIteratorItem,
|
||||
IoBufRead,
|
||||
IoLines,
|
||||
IoRead,
|
||||
|
|
|
|||
|
|
@ -4390,6 +4390,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
path_segment: &hir::PathSegment<'_>,
|
||||
args: &[hir::Expr<'_>],
|
||||
prev_ty: Ty<'_>,
|
||||
err: &mut Diag<'_, G>,
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
|
|
@ -4403,6 +4404,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
let TypeError::Sorts(expected_found) = diff else {
|
||||
continue;
|
||||
};
|
||||
if tcx.is_diagnostic_item(sym::IntoIteratorItem, *def_id)
|
||||
&& path_segment.ident.name == sym::iter
|
||||
&& self.can_eq(
|
||||
param_env,
|
||||
Ty::new_ref(
|
||||
tcx,
|
||||
tcx.lifetimes.re_erased,
|
||||
expected_found.found,
|
||||
ty::Mutability::Not,
|
||||
),
|
||||
*ty,
|
||||
)
|
||||
&& let [] = args
|
||||
{
|
||||
// Used `.iter()` when `.into_iter()` was likely meant.
|
||||
err.span_suggestion_verbose(
|
||||
path_segment.ident.span,
|
||||
format!("consider consuming the `{prev_ty}` to construct the `Iterator`"),
|
||||
"into_iter".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
if tcx.is_diagnostic_item(sym::IntoIteratorItem, *def_id)
|
||||
&& path_segment.ident.name == sym::into_iter
|
||||
&& self.can_eq(
|
||||
param_env,
|
||||
expected_found.found,
|
||||
Ty::new_ref(tcx, tcx.lifetimes.re_erased, *ty, ty::Mutability::Not),
|
||||
)
|
||||
&& let [] = args
|
||||
{
|
||||
// Used `.into_iter()` when `.iter()` was likely meant.
|
||||
err.span_suggestion_verbose(
|
||||
path_segment.ident.span,
|
||||
format!(
|
||||
"consider not consuming the `{prev_ty}` to construct the `Iterator`"
|
||||
),
|
||||
"iter".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
if tcx.is_diagnostic_item(sym::IteratorItem, *def_id)
|
||||
&& path_segment.ident.name == sym::map
|
||||
&& self.can_eq(param_env, expected_found.found, *ty)
|
||||
|
|
@ -4515,6 +4557,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
expr = rcvr_expr;
|
||||
let assocs_in_this_method =
|
||||
self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
|
||||
prev_ty = self.resolve_vars_if_possible(
|
||||
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
|
||||
);
|
||||
self.look_for_iterator_item_mistakes(
|
||||
&assocs_in_this_method,
|
||||
typeck_results,
|
||||
|
|
@ -4522,12 +4567,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
param_env,
|
||||
path_segment,
|
||||
args,
|
||||
prev_ty,
|
||||
err,
|
||||
);
|
||||
assocs.push(assocs_in_this_method);
|
||||
prev_ty = self.resolve_vars_if_possible(
|
||||
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
|
||||
);
|
||||
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
|
||||
&& let hir::Path { res: Res::Local(hir_id), .. } = path
|
||||
|
|
|
|||
|
|
@ -281,6 +281,7 @@ pub trait FromIterator<A>: Sized {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait IntoIterator {
|
||||
/// The type of the elements being iterated over.
|
||||
#[rustc_diagnostic_item = "IntoIteratorItem"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
type Item;
|
||||
|
||||
|
|
|
|||
10
tests/ui/iterators/into_iter-when-iter-was-intended.fixed
Normal file
10
tests/ui/iterators/into_iter-when-iter-was-intended.fixed
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
//@ run-rustfix
|
||||
//@ edition:2021
|
||||
// Suggest using the right `IntoIterator` method. #68095
|
||||
fn main() {
|
||||
let _a = [0, 1, 2].iter().chain([3, 4, 5].iter()); //~ ERROR E0271
|
||||
let _b = [0, 1, 2].into_iter().chain([3, 4, 5].into_iter()); //~ ERROR E0271
|
||||
// These don't have appropriate suggestions yet.
|
||||
// let c = [0, 1, 2].iter().chain([3, 4, 5]);
|
||||
// let d = [0, 1, 2].iter().chain(vec![3, 4, 5]);
|
||||
}
|
||||
10
tests/ui/iterators/into_iter-when-iter-was-intended.rs
Normal file
10
tests/ui/iterators/into_iter-when-iter-was-intended.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
//@ run-rustfix
|
||||
//@ edition:2021
|
||||
// Suggest using the right `IntoIterator` method. #68095
|
||||
fn main() {
|
||||
let _a = [0, 1, 2].iter().chain([3, 4, 5].into_iter()); //~ ERROR E0271
|
||||
let _b = [0, 1, 2].into_iter().chain([3, 4, 5].iter()); //~ ERROR E0271
|
||||
// These don't have appropriate suggestions yet.
|
||||
// let c = [0, 1, 2].iter().chain([3, 4, 5]);
|
||||
// let d = [0, 1, 2].iter().chain(vec![3, 4, 5]);
|
||||
}
|
||||
48
tests/ui/iterators/into_iter-when-iter-was-intended.stderr
Normal file
48
tests/ui/iterators/into_iter-when-iter-was-intended.stderr
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
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());
|
||||
|
|
||||
|
||||
error[E0271]: type mismatch resolving `<Iter<'_, {integer}> as IntoIterator>::Item == {integer}`
|
||||
--> $DIR/into_iter-when-iter-was-intended.rs:6:42
|
||||
|
|
||||
LL | let _b = [0, 1, 2].into_iter().chain([3, 4, 5].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:6:52
|
||||
|
|
||||
LL | let _b = [0, 1, 2].into_iter().chain([3, 4, 5].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 consuming the `&[{integer}]` to construct the `Iterator`
|
||||
|
|
||||
LL | let _b = [0, 1, 2].into_iter().chain([3, 4, 5].into_iter());
|
||||
| +++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0271`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue