Skip to content

Commit 6253081

Browse files
Rollup merge of rust-lang#120396 - estebank:method-on-unbounded-type-param, r=nnethercote
Account for unbounded type param receiver in suggestions When encountering ```rust fn f<T>(a: T, b: T) -> std::cmp::Ordering { a.cmp(&b) //~ ERROR E0599 } ``` output ``` 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<T>(a: T, b: T) -> std::cmp::Ordering { | - method `cmp` not found for this type parameter LL | a.cmp(&b) | ^^^ method cannot be called on `T` due to unsatisfied trait bounds | = 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<T: Ord>(a: T, b: T) -> std::cmp::Ordering { | +++++ LL | fn f<T: Iterator>(a: T, b: T) -> std::cmp::Ordering { | ++++++++++ ``` Fix rust-lang#120186.
2 parents c77bb26 + 9ccc770 commit 6253081

File tree

3 files changed

+116
-14
lines changed

3 files changed

+116
-14
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+27-14
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
554554
"`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
555555
));
556556
}
557+
} else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) {
558+
// We special case the situation where we are looking for `_` in
559+
// `<TypeParam as _>::method` because otherwise the machinery will look for blanket
560+
// implementations that have unsatisfied trait bounds to suggest, leading us to claim
561+
// things like "we're looking for a trait with method `cmp`, both `Iterator` and `Ord`
562+
// have one, in order to implement `Ord` you need to restrict `TypeParam: FnPtr` so
563+
// that `impl<T: FnPtr> Ord for T` can apply", which is not what we want. We have a type
564+
// parameter, we want to directly say "`Ord::cmp` and `Iterator::cmp` exist, restrict
565+
// `TypeParam: Ord` or `TypeParam: Iterator`"". That is done further down when calling
566+
// `self.suggest_traits_to_import`, so we ignore the `unsatisfied_predicates`
567+
// suggestions.
557568
} else if !unsatisfied_predicates.is_empty() {
558569
let mut type_params = FxIndexMap::default();
559570

@@ -1325,7 +1336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13251336
}
13261337
}
13271338
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
1328-
return Some(err);
1339+
Some(err)
13291340
}
13301341

13311342
fn note_candidates_on_method_error(
@@ -2918,19 +2929,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
29182929
// this isn't perfect (that is, there are cases when
29192930
// implementing a trait would be legal but is rejected
29202931
// here).
2921-
unsatisfied_predicates.iter().all(|(p, _, _)| {
2922-
match p.kind().skip_binder() {
2923-
// Hide traits if they are present in predicates as they can be fixed without
2924-
// having to implement them.
2925-
ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => {
2926-
t.def_id() == info.def_id
2927-
}
2928-
ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => {
2929-
p.projection_ty.def_id == info.def_id
2930-
}
2931-
_ => false,
2932-
}
2933-
}) && (type_is_local || info.def_id.is_local())
2932+
(type_is_local || info.def_id.is_local())
29342933
&& !self.tcx.trait_is_auto(info.def_id)
29352934
&& self
29362935
.associated_value(info.def_id, item_name)
@@ -2978,6 +2977,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
29782977
item.visibility(self.tcx).is_public() || info.def_id.is_local()
29792978
})
29802979
.is_some()
2980+
&& (matches!(rcvr_ty.kind(), ty::Param(_))
2981+
|| unsatisfied_predicates.iter().all(|(p, _, _)| {
2982+
match p.kind().skip_binder() {
2983+
// Hide traits if they are present in predicates as they can be fixed without
2984+
// having to implement them.
2985+
ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => {
2986+
t.def_id() == info.def_id
2987+
}
2988+
ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => {
2989+
p.projection_ty.def_id == info.def_id
2990+
}
2991+
_ => false,
2992+
}
2993+
}))
29812994
})
29822995
.collect::<Vec<_>>();
29832996
for span in &arbitrary_rcvr {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
fn f<T>(a: T, b: T) -> std::cmp::Ordering {
2+
a.cmp(&b) //~ ERROR E0599
3+
}
4+
fn g<T>(a: T, b: T) -> std::cmp::Ordering {
5+
(&a).cmp(&b) //~ ERROR E0599
6+
}
7+
fn h<T>(a: &T, b: T) -> std::cmp::Ordering {
8+
a.cmp(&b) //~ ERROR E0599
9+
}
10+
trait T {}
11+
impl<X: std::cmp::Ord> T for X {}
12+
fn main() {
13+
let x: Box<dyn T> = Box::new(0);
14+
x.cmp(&x); //~ ERROR E0599
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
error[E0599]: no method named `cmp` found for type parameter `T` in the current scope
2+
--> $DIR/method-on-unbounded-type-param.rs:2:7
3+
|
4+
LL | fn f<T>(a: T, b: T) -> std::cmp::Ordering {
5+
| - method `cmp` not found for this type parameter
6+
LL | a.cmp(&b)
7+
| ^^^ method cannot be called on `T` due to unsatisfied trait bounds
8+
|
9+
= help: items from traits can only be used if the type parameter is bounded by the trait
10+
help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them:
11+
|
12+
LL | fn f<T: Ord>(a: T, b: T) -> std::cmp::Ordering {
13+
| +++++
14+
LL | fn f<T: Iterator>(a: T, b: T) -> std::cmp::Ordering {
15+
| ++++++++++
16+
17+
error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied
18+
--> $DIR/method-on-unbounded-type-param.rs:5:10
19+
|
20+
LL | (&a).cmp(&b)
21+
| ^^^ method cannot be called on `&T` due to unsatisfied trait bounds
22+
|
23+
= note: the following trait bounds were not satisfied:
24+
`T: Ord`
25+
which is required by `&T: Ord`
26+
`&T: Iterator`
27+
which is required by `&mut &T: Iterator`
28+
`T: Iterator`
29+
which is required by `&mut T: Iterator`
30+
help: consider restricting the type parameters to satisfy the trait bounds
31+
|
32+
LL | fn g<T>(a: T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord {
33+
| +++++++++++++++++++++++++
34+
35+
error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied
36+
--> $DIR/method-on-unbounded-type-param.rs:8:7
37+
|
38+
LL | a.cmp(&b)
39+
| ^^^ method cannot be called on `&T` due to unsatisfied trait bounds
40+
|
41+
= note: the following trait bounds were not satisfied:
42+
`T: Ord`
43+
which is required by `&T: Ord`
44+
`&T: Iterator`
45+
which is required by `&mut &T: Iterator`
46+
`T: Iterator`
47+
which is required by `&mut T: Iterator`
48+
help: consider restricting the type parameters to satisfy the trait bounds
49+
|
50+
LL | fn h<T>(a: &T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord {
51+
| +++++++++++++++++++++++++
52+
53+
error[E0599]: the method `cmp` exists for struct `Box<dyn T>`, but its trait bounds were not satisfied
54+
--> $DIR/method-on-unbounded-type-param.rs:14:7
55+
|
56+
LL | trait T {}
57+
| ------- doesn't satisfy `dyn T: Iterator` or `dyn T: Ord`
58+
...
59+
LL | x.cmp(&x);
60+
| ^^^ method cannot be called on `Box<dyn T>` due to unsatisfied trait bounds
61+
|
62+
= note: the following trait bounds were not satisfied:
63+
`dyn T: Iterator`
64+
which is required by `Box<dyn T>: Iterator`
65+
`dyn T: Ord`
66+
which is required by `Box<dyn T>: Ord`
67+
`Box<dyn T>: Iterator`
68+
which is required by `&mut Box<dyn T>: Iterator`
69+
`dyn T: Iterator`
70+
which is required by `&mut dyn T: Iterator`
71+
72+
error: aborting due to 4 previous errors
73+
74+
For more information about this error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)