diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 0b8a25eedafad..27583cca3b5b5 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -563,6 +563,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement" )); } + } else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) { + // We special case the situation where we are looking for `_` in + // `::method` because otherwise the machinery will look for blanket + // implementations that have unsatisfied trait bounds to suggest, leading us to claim + // things like "we're looking for a trait with method `cmp`, both `Iterator` and `Ord` + // have one, in order to implement `Ord` you need to restrict `TypeParam: FnPtr` so + // that `impl Ord for T` can apply", which is not what we want. We have a type + // parameter, we want to directly say "`Ord::cmp` and `Iterator::cmp` exist, restrict + // `TypeParam: Ord` or `TypeParam: Iterator`"". That is done further down when calling + // `self.suggest_traits_to_import`, so we ignore the `unsatisfied_predicates` + // suggestions. } else if !unsatisfied_predicates.is_empty() { let mut type_params = FxIndexMap::default(); @@ -1301,7 +1312,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected); - return Some(err); + Some(err) } fn note_candidates_on_method_error( @@ -2884,19 +2895,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this isn't perfect (that is, there are cases when // implementing a trait would be legal but is rejected // here). - unsatisfied_predicates.iter().all(|(p, _, _)| { - match p.kind().skip_binder() { - // Hide traits if they are present in predicates as they can be fixed without - // having to implement them. - ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { - t.def_id() == info.def_id - } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { - p.projection_ty.def_id == info.def_id - } - _ => false, - } - }) && (type_is_local || info.def_id.is_local()) + (type_is_local || info.def_id.is_local()) && !self.tcx.trait_is_auto(info.def_id) && self .associated_value(info.def_id, item_name) @@ -2944,6 +2943,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item.visibility(self.tcx).is_public() || info.def_id.is_local() }) .is_some() + && (matches!(rcvr_ty.kind(), ty::Param(_)) + || unsatisfied_predicates.iter().all(|(p, _, _)| { + match p.kind().skip_binder() { + // Hide traits if they are present in predicates as they can be fixed without + // having to implement them. + ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { + t.def_id() == info.def_id + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => { + p.projection_ty.def_id == info.def_id + } + _ => false, + } + })) }) .collect::>(); for span in &arbitrary_rcvr { diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr index 0b650995de5c5..f12b4d6cabdaf 100644 --- a/tests/ui/traits/method-on-unbounded-type-param.stderr +++ b/tests/ui/traits/method-on-unbounded-type-param.stderr @@ -1,18 +1,18 @@ -error[E0599]: `T` is not an iterator +error[E0599]: no method named `cmp` found for type parameter `T` in the current scope --> $DIR/method-on-unbounded-type-param.rs:2:7 | LL | fn f(a: T, b: T) -> std::cmp::Ordering { | - method `cmp` not found for this type parameter LL | a.cmp(&b) - | ^^^ `T` is not an iterator + | ^^^ method cannot be called on `T` due to unsatisfied trait bounds | - = note: the following trait bounds were not satisfied: - `T: Iterator` - which is required by `&mut T: Iterator` -help: consider restricting the type parameter to satisfy the trait bound + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them: | -LL | fn f(a: T, b: T) -> std::cmp::Ordering where T: Iterator { - | +++++++++++++++++ +LL | fn f(a: T, b: T) -> std::cmp::Ordering { + | +++++ +LL | fn f(a: T, b: T) -> std::cmp::Ordering { + | ++++++++++ error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied --> $DIR/method-on-unbounded-type-param.rs:5:10