Rollup merge of #132760 - dianne:iter-into-iter, r=lcnr
Don't suggest `.into_iter()` on iterators This makes the the suggestion to call `.into_iter()` only consider unsatisfied `Iterator` bounds for the receiver type itself. That way, it ignores predicates generated by trying to auto-ref the receiver (the result of which usually won't implement `Iterator`). Fixes #127511 Unfortunately, the error in that case is still confusing: it labels `Iterator` as an unsatisfied bound because `&impl Iterator: Iterator` can't be satisfied, despite that not being required or helpful. I'd like to handle that in a separate PR. ~~I'm hoping fixing #124802 will fix it too.~~ It doesn't look connected to that issue. Still, I think it'd be clearest to visually distinguish unsatisfied predicates from different attempts at `pick_method`; I'll make a PR for that soon.
This commit is contained in:
commit
b598849941
@ -100,9 +100,9 @@ fn impl_into_iterator_should_be_iterator(
|
|||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
unsatisfied_predicates: &Vec<(
|
unsatisfied_predicates: &Vec<(
|
||||||
ty::Predicate<'_>,
|
ty::Predicate<'tcx>,
|
||||||
Option<ty::Predicate<'_>>,
|
Option<ty::Predicate<'tcx>>,
|
||||||
Option<ObligationCause<'_>>,
|
Option<ObligationCause<'tcx>>,
|
||||||
)>,
|
)>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
fn predicate_bounds_generic_param<'tcx>(
|
fn predicate_bounds_generic_param<'tcx>(
|
||||||
@ -131,15 +131,17 @@ fn predicate_bounds_generic_param<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_iterator_predicate(predicate: ty::Predicate<'_>, tcx: TyCtxt<'_>) -> bool {
|
let is_iterator_predicate = |predicate: ty::Predicate<'tcx>| -> bool {
|
||||||
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
|
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
|
||||||
predicate.kind().as_ref().skip_binder()
|
predicate.kind().as_ref().skip_binder()
|
||||||
{
|
{
|
||||||
tcx.is_diagnostic_item(sym::Iterator, trait_pred.trait_ref.def_id)
|
self.tcx.is_diagnostic_item(sym::Iterator, trait_pred.trait_ref.def_id)
|
||||||
|
// ignore unsatisfied predicates generated from trying to auto-ref ty (#127511)
|
||||||
|
&& trait_pred.trait_ref.self_ty() == ty
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Does the `ty` implement `IntoIterator`?
|
// Does the `ty` implement `IntoIterator`?
|
||||||
let Some(into_iterator_trait) = self.tcx.get_diagnostic_item(sym::IntoIterator) else {
|
let Some(into_iterator_trait) = self.tcx.get_diagnostic_item(sym::IntoIterator) else {
|
||||||
@ -164,7 +166,7 @@ fn is_iterator_predicate(predicate: ty::Predicate<'_>, tcx: TyCtxt<'_>) -> bool
|
|||||||
generics,
|
generics,
|
||||||
generic_param,
|
generic_param,
|
||||||
self.tcx,
|
self.tcx,
|
||||||
) && is_iterator_predicate(unsatisfied.0, self.tcx)
|
) && is_iterator_predicate(unsatisfied.0)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -172,7 +174,7 @@ fn is_iterator_predicate(predicate: ty::Predicate<'_>, tcx: TyCtxt<'_>) -> bool
|
|||||||
}
|
}
|
||||||
ty::Slice(..) | ty::Adt(..) | ty::Alias(ty::Opaque, _) => {
|
ty::Slice(..) | ty::Adt(..) | ty::Alias(ty::Opaque, _) => {
|
||||||
for unsatisfied in unsatisfied_predicates.iter() {
|
for unsatisfied in unsatisfied_predicates.iter() {
|
||||||
if is_iterator_predicate(unsatisfied.0, self.tcx) {
|
if is_iterator_predicate(unsatisfied.0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
tests/ui/iterators/iterator-does-not-need-into-iter.rs
Normal file
18
tests/ui/iterators/iterator-does-not-need-into-iter.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//! regression test for #127511: don't suggest `.into_iter()` on iterators
|
||||||
|
|
||||||
|
trait Missing {}
|
||||||
|
trait HasMethod {
|
||||||
|
fn foo(self);
|
||||||
|
}
|
||||||
|
impl<T: Iterator + Missing> HasMethod for T {
|
||||||
|
fn foo(self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_iter() -> impl Iterator {
|
||||||
|
core::iter::once(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
get_iter().foo();
|
||||||
|
//~^ ERROR the method `foo` exists for opaque type `impl Iterator`, but its trait bounds were not satisfied [E0599]
|
||||||
|
}
|
28
tests/ui/iterators/iterator-does-not-need-into-iter.stderr
Normal file
28
tests/ui/iterators/iterator-does-not-need-into-iter.stderr
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
error[E0599]: the method `foo` exists for opaque type `impl Iterator`, but its trait bounds were not satisfied
|
||||||
|
--> $DIR/iterator-does-not-need-into-iter.rs:16:16
|
||||||
|
|
|
||||||
|
LL | get_iter().foo();
|
||||||
|
| ^^^ method cannot be called on `impl Iterator` due to unsatisfied trait bounds
|
||||||
|
|
|
||||||
|
note: the following trait bounds were not satisfied:
|
||||||
|
`&impl Iterator: Iterator`
|
||||||
|
`&impl Iterator: Missing`
|
||||||
|
`&mut impl Iterator: Missing`
|
||||||
|
`impl Iterator: Missing`
|
||||||
|
--> $DIR/iterator-does-not-need-into-iter.rs:7:9
|
||||||
|
|
|
||||||
|
LL | impl<T: Iterator + Missing> HasMethod for T {
|
||||||
|
| ^^^^^^^^ ^^^^^^^ --------- -
|
||||||
|
| | |
|
||||||
|
| | unsatisfied trait bound introduced here
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
|
note: `HasMethod` defines an item `foo`, perhaps you need to implement it
|
||||||
|
--> $DIR/iterator-does-not-need-into-iter.rs:4:1
|
||||||
|
|
|
||||||
|
LL | trait HasMethod {
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0599`.
|
Loading…
Reference in New Issue
Block a user