Don't suggest .into_iter() on iterators

This commit is contained in:
dianne 2024-11-08 13:47:36 -08:00
parent 59cec72a57
commit cea82ed162
3 changed files with 56 additions and 8 deletions

View File

@ -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;
} }
} }

View 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]
}

View 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`.