Skip to content

Commit 4c12048

Browse files
authored
Unrolled build for rust-lang#120507
Rollup merge of rust-lang#120507 - estebank:issue-108428, r=davidtwco Account for non-overlapping unmet trait bounds in suggestion When a method not found on a type parameter could have been provided by any of multiple traits, suggest each trait individually, instead of a single suggestion to restrict the type parameter with *all* of them. Before: ``` 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 | LL | (&a).cmp(&b) | ^^^ method cannot be called on `&T` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `T: Ord` which is required by `&T: Ord` `&T: Iterator` which is required by `&mut &T: Iterator` `T: Iterator` which is required by `&mut T: Iterator` help: consider restricting the type parameters to satisfy the trait bounds | LL | fn g<T>(a: T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord { | +++++++++++++++++++++++++ ``` After: ``` 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 | LL | (&a).cmp(&b) | ^^^ method cannot be called on `&T` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `T: Ord` which is required by `&T: Ord` `&T: Iterator` which is required by `&mut &T: Iterator` `T: Iterator` which is required by `&mut T: Iterator` = 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 g<T: Ord>(a: T, b: T) -> std::cmp::Ordering { | +++++ LL | fn g<T: Iterator>(a: T, b: T) -> std::cmp::Ordering { | ++++++++++ ``` Fix rust-lang#108428. Follow up to rust-lang#120396, only last commit is relevant.
2 parents 256b6fb + 5c41409 commit 4c12048

10 files changed

+158
-46
lines changed

Diff for: compiler/rustc_hir_typeck/src/method/suggest.rs

+34-37
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
541541

542542
let mut bound_spans: SortedMap<Span, Vec<String>> = Default::default();
543543
let mut restrict_type_params = false;
544+
let mut suggested_derive = false;
544545
let mut unsatisfied_bounds = false;
545546
if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
546547
let msg = "consider using `len` instead";
@@ -555,6 +556,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
555556
"`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
556557
));
557558
}
559+
} else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) {
560+
// We special case the situation where we are looking for `_` in
561+
// `<TypeParam as _>::method` because otherwise the machinery will look for blanket
562+
// implementations that have unsatisfied trait bounds to suggest, leading us to claim
563+
// things like "we're looking for a trait with method `cmp`, both `Iterator` and `Ord`
564+
// have one, in order to implement `Ord` you need to restrict `TypeParam: FnPtr` so
565+
// that `impl<T: FnPtr> Ord for T` can apply", which is not what we want. We have a type
566+
// parameter, we want to directly say "`Ord::cmp` and `Iterator::cmp` exist, restrict
567+
// `TypeParam: Ord` or `TypeParam: Iterator`"". That is done further down when calling
568+
// `self.suggest_traits_to_import`, so we ignore the `unsatisfied_predicates`
569+
// suggestions.
558570
} else if !unsatisfied_predicates.is_empty() {
559571
let mut type_params = FxIndexMap::default();
560572

@@ -917,20 +929,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
917929
.enumerate()
918930
.collect::<Vec<(usize, String)>>();
919931

920-
for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
921-
restrict_type_params = true;
922-
// #74886: Sort here so that the output is always the same.
923-
let obligations = obligations.into_sorted_stable_ord();
924-
err.span_suggestion_verbose(
925-
span,
926-
format!(
927-
"consider restricting the type parameter{s} to satisfy the \
928-
trait bound{s}",
929-
s = pluralize!(obligations.len())
930-
),
931-
format!("{} {}", add_where_or_comma, obligations.join(", ")),
932-
Applicability::MaybeIncorrect,
933-
);
932+
if !matches!(rcvr_ty.peel_refs().kind(), ty::Param(_)) {
933+
for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
934+
restrict_type_params = true;
935+
// #74886: Sort here so that the output is always the same.
936+
let obligations = obligations.into_sorted_stable_ord();
937+
err.span_suggestion_verbose(
938+
span,
939+
format!(
940+
"consider restricting the type parameter{s} to satisfy the trait \
941+
bound{s}",
942+
s = pluralize!(obligations.len())
943+
),
944+
format!("{} {}", add_where_or_comma, obligations.join(", ")),
945+
Applicability::MaybeIncorrect,
946+
);
947+
}
934948
}
935949

936950
bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
@@ -978,7 +992,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
978992
"the following trait bounds were not satisfied:\n{bound_list}"
979993
));
980994
}
981-
self.suggest_derive(&mut err, unsatisfied_predicates);
995+
suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates);
982996

983997
unsatisfied_bounds = true;
984998
}
@@ -1201,7 +1215,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12011215
);
12021216
}
12031217

1204-
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
1218+
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive {
12051219
} else {
12061220
self.suggest_traits_to_import(
12071221
&mut err,
@@ -1211,7 +1225,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12111225
args.map(|args| args.len() + 1),
12121226
source,
12131227
no_match_data.out_of_scope_traits.clone(),
1214-
unsatisfied_predicates,
12151228
static_candidates,
12161229
unsatisfied_bounds,
12171230
expected.only_has_type(self),
@@ -1326,7 +1339,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13261339
}
13271340
}
13281341
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
1329-
return Some(err);
1342+
Some(err)
13301343
}
13311344

13321345
fn note_candidates_on_method_error(
@@ -2471,7 +2484,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24712484
Option<ty::Predicate<'tcx>>,
24722485
Option<ObligationCause<'tcx>>,
24732486
)],
2474-
) {
2487+
) -> bool {
24752488
let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates);
24762489
derives.sort();
24772490
derives.dedup();
@@ -2496,6 +2509,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24962509
Applicability::MaybeIncorrect,
24972510
);
24982511
}
2512+
!derives_grouped.is_empty()
24992513
}
25002514

25012515
fn note_derefed_ty_has_method(
@@ -2698,11 +2712,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26982712
inputs_len: Option<usize>,
26992713
source: SelfSource<'tcx>,
27002714
valid_out_of_scope_traits: Vec<DefId>,
2701-
unsatisfied_predicates: &[(
2702-
ty::Predicate<'tcx>,
2703-
Option<ty::Predicate<'tcx>>,
2704-
Option<ObligationCause<'tcx>>,
2705-
)],
27062715
static_candidates: &[CandidateSource],
27072716
unsatisfied_bounds: bool,
27082717
return_type: Option<Ty<'tcx>>,
@@ -2919,19 +2928,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
29192928
// this isn't perfect (that is, there are cases when
29202929
// implementing a trait would be legal but is rejected
29212930
// here).
2922-
unsatisfied_predicates.iter().all(|(p, _, _)| {
2923-
match p.kind().skip_binder() {
2924-
// Hide traits if they are present in predicates as they can be fixed without
2925-
// having to implement them.
2926-
ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => {
2927-
t.def_id() == info.def_id
2928-
}
2929-
ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => {
2930-
p.projection_ty.def_id == info.def_id
2931-
}
2932-
_ => false,
2933-
}
2934-
}) && (type_is_local || info.def_id.is_local())
2931+
(type_is_local || info.def_id.is_local())
29352932
&& !self.tcx.trait_is_auto(info.def_id)
29362933
&& self
29372934
.associated_value(info.def_id, item_name)

Diff for: tests/ui/box/unit/unique-object-noncopyable.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ LL | let _z = y.clone();
1212
which is required by `Box<dyn Foo>: Clone`
1313
`dyn Foo: Clone`
1414
which is required by `Box<dyn Foo>: Clone`
15+
= help: items from traits can only be used if the trait is implemented and in scope
16+
= note: the following trait defines an item `clone`, perhaps you need to implement it:
17+
candidate #1: `Clone`
1518

1619
error: aborting due to 1 previous error
1720

Diff for: tests/ui/box/unit/unique-pinned-nocopy.stderr

-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ LL | let _j = i.clone();
1010
= note: the following trait bounds were not satisfied:
1111
`R: Clone`
1212
which is required by `Box<R>: Clone`
13-
= help: items from traits can only be used if the trait is implemented and in scope
14-
= note: the following trait defines an item `clone`, perhaps you need to implement it:
15-
candidate #1: `Clone`
1613
help: consider annotating `R` with `#[derive(Clone)]`
1714
|
1815
LL + #[derive(Clone)]

Diff for: tests/ui/derives/derive-assoc-type-not-impl.stderr

-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ note: trait bound `NotClone: Clone` was not satisfied
1515
|
1616
LL | #[derive(Clone)]
1717
| ^^^^^ unsatisfied trait bound introduced in this `derive` macro
18-
= help: items from traits can only be used if the trait is implemented and in scope
19-
= note: the following trait defines an item `clone`, perhaps you need to implement it:
20-
candidate #1: `Clone`
2118
help: consider annotating `NotClone` with `#[derive(Clone)]`
2219
|
2320
LL + #[derive(Clone)]

Diff for: tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ trait X {
55
type Y<T>;
66
}
77

8-
trait M {
8+
trait M { //~ NOTE
99
fn f(&self) {}
1010
}
1111

Diff for: tests/ui/generic-associated-types/method-unsatisfied-assoc-type-predicate.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ LL | impl<T: X<Y<i32> = i32>> M for T {}
1414
| ^^^^^^^^^^^^ - -
1515
| |
1616
| unsatisfied trait bound introduced here
17+
= help: items from traits can only be used if the trait is implemented and in scope
18+
note: `M` defines an item `f`, perhaps you need to implement it
19+
--> $DIR/method-unsatisfied-assoc-type-predicate.rs:8:1
20+
|
21+
LL | trait M {
22+
| ^^^^^^^
1723

1824
error: aborting due to 1 previous error
1925

Diff for: tests/ui/higher-ranked/trait-bounds/issue-30786.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ note: the following trait bounds were not satisfied:
1515
|
1616
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
1717
| --------- - ^^^^^^ unsatisfied trait bound introduced here
18+
= help: items from traits can only be used if the trait is implemented and in scope
19+
note: `StreamExt` defines an item `filterx`, perhaps you need to implement it
20+
--> $DIR/issue-30786.rs:66:1
21+
|
22+
LL | pub trait StreamExt
23+
| ^^^^^^^^^^^^^^^^^^^
1824

1925
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, fn(&u64) -> &u64 {identity::<u64>}>, {closure@issue-30786.rs:131:30}>`, but its trait bounds were not satisfied
2026
--> $DIR/issue-30786.rs:132:24
@@ -33,6 +39,12 @@ note: the following trait bounds were not satisfied:
3339
|
3440
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
3541
| --------- - ^^^^^^ unsatisfied trait bound introduced here
42+
= help: items from traits can only be used if the trait is implemented and in scope
43+
note: `StreamExt` defines an item `countx`, perhaps you need to implement it
44+
--> $DIR/issue-30786.rs:66:1
45+
|
46+
LL | pub trait StreamExt
47+
| ^^^^^^^^^^^^^^^^^^^
3648

3749
error: aborting due to 2 previous errors
3850

Diff for: tests/ui/methods/method-call-err-msg.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,9 @@ LL | | .take()
6363
note: the trait `Iterator` must be implemented
6464
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
6565
= help: items from traits can only be used if the trait is implemented and in scope
66-
= note: the following trait defines an item `take`, perhaps you need to implement it:
67-
candidate #1: `Iterator`
66+
= note: the following traits define an item `take`, perhaps you need to implement one of them:
67+
candidate #1: `std::io::Read`
68+
candidate #2: `Iterator`
6869

6970
error[E0061]: this method takes 3 arguments but 0 arguments were supplied
7071
--> $DIR/method-call-err-msg.rs:21:7

Diff for: tests/ui/traits/method-on-unbounded-type-param.rs

+15
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+
}
+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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: items from traits can only be used if the type parameter is bounded by the trait
31+
help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them:
32+
|
33+
LL | fn g<T: Ord>(a: T, b: T) -> std::cmp::Ordering {
34+
| +++++
35+
LL | fn g<T: Iterator>(a: T, b: T) -> std::cmp::Ordering {
36+
| ++++++++++
37+
38+
error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied
39+
--> $DIR/method-on-unbounded-type-param.rs:8:7
40+
|
41+
LL | a.cmp(&b)
42+
| ^^^ method cannot be called on `&T` due to unsatisfied trait bounds
43+
|
44+
= note: the following trait bounds were not satisfied:
45+
`T: Ord`
46+
which is required by `&T: Ord`
47+
`&T: Iterator`
48+
which is required by `&mut &T: Iterator`
49+
`T: Iterator`
50+
which is required by `&mut T: Iterator`
51+
= help: items from traits can only be used if the type parameter is bounded by the trait
52+
help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them:
53+
|
54+
LL | fn h<T: Ord>(a: &T, b: T) -> std::cmp::Ordering {
55+
| +++++
56+
LL | fn h<T: Iterator>(a: &T, b: T) -> std::cmp::Ordering {
57+
| ++++++++++
58+
59+
error[E0599]: the method `cmp` exists for struct `Box<dyn T>`, but its trait bounds were not satisfied
60+
--> $DIR/method-on-unbounded-type-param.rs:14:7
61+
|
62+
LL | trait T {}
63+
| ------- doesn't satisfy `dyn T: Iterator` or `dyn T: Ord`
64+
...
65+
LL | x.cmp(&x);
66+
| ^^^ method cannot be called on `Box<dyn T>` due to unsatisfied trait bounds
67+
|
68+
= note: the following trait bounds were not satisfied:
69+
`dyn T: Iterator`
70+
which is required by `Box<dyn T>: Iterator`
71+
`dyn T: Ord`
72+
which is required by `Box<dyn T>: Ord`
73+
`Box<dyn T>: Iterator`
74+
which is required by `&mut Box<dyn T>: Iterator`
75+
`dyn T: Iterator`
76+
which is required by `&mut dyn T: Iterator`
77+
= help: items from traits can only be used if the trait is implemented and in scope
78+
= note: the following traits define an item `cmp`, perhaps you need to implement one of them:
79+
candidate #1: `Ord`
80+
candidate #2: `Iterator`
81+
82+
error: aborting due to 4 previous errors
83+
84+
For more information about this error, try `rustc --explain E0599`.

0 commit comments

Comments
 (0)