Skip to content

Commit b868b6a

Browse files
authored
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 74edcac + 5c41409 commit b868b6a

9 files changed

+62
-52
lines changed

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

+21-37
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
540540

541541
let mut bound_spans: SortedMap<Span, Vec<String>> = Default::default();
542542
let mut restrict_type_params = false;
543+
let mut suggested_derive = false;
543544
let mut unsatisfied_bounds = false;
544545
if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
545546
let msg = "consider using `len` instead";
@@ -927,20 +928,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
927928
.enumerate()
928929
.collect::<Vec<(usize, String)>>();
929930

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

946949
bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
@@ -988,7 +991,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
988991
"the following trait bounds were not satisfied:\n{bound_list}"
989992
));
990993
}
991-
self.suggest_derive(&mut err, unsatisfied_predicates);
994+
suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates);
992995

993996
unsatisfied_bounds = true;
994997
}
@@ -1211,7 +1214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12111214
);
12121215
}
12131216

1214-
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
1217+
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive {
12151218
} else {
12161219
self.suggest_traits_to_import(
12171220
&mut err,
@@ -1221,7 +1224,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12211224
args.map(|args| args.len() + 1),
12221225
source,
12231226
no_match_data.out_of_scope_traits.clone(),
1224-
unsatisfied_predicates,
12251227
static_candidates,
12261228
unsatisfied_bounds,
12271229
expected.only_has_type(self),
@@ -2481,7 +2483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24812483
Option<ty::Predicate<'tcx>>,
24822484
Option<ObligationCause<'tcx>>,
24832485
)],
2484-
) {
2486+
) -> bool {
24852487
let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates);
24862488
derives.sort();
24872489
derives.dedup();
@@ -2506,6 +2508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25062508
Applicability::MaybeIncorrect,
25072509
);
25082510
}
2511+
!derives_grouped.is_empty()
25092512
}
25102513

25112514
fn note_derefed_ty_has_method(
@@ -2708,11 +2711,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27082711
inputs_len: Option<usize>,
27092712
source: SelfSource<'tcx>,
27102713
valid_out_of_scope_traits: Vec<DefId>,
2711-
unsatisfied_predicates: &[(
2712-
ty::Predicate<'tcx>,
2713-
Option<ty::Predicate<'tcx>>,
2714-
Option<ObligationCause<'tcx>>,
2715-
)],
27162714
static_candidates: &[CandidateSource],
27172715
unsatisfied_bounds: bool,
27182716
return_type: Option<Ty<'tcx>>,
@@ -2977,20 +2975,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
29772975
item.visibility(self.tcx).is_public() || info.def_id.is_local()
29782976
})
29792977
.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-
}))
29942978
})
29952979
.collect::<Vec<_>>();
29962980
for span in &arbitrary_rcvr {

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.stderr

+16-6
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@ LL | (&a).cmp(&b)
2727
which is required by `&mut &T: Iterator`
2828
`T: Iterator`
2929
which is required by `&mut T: Iterator`
30-
help: consider restricting the type parameters to satisfy the trait bounds
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:
3132
|
32-
LL | fn g<T>(a: T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord {
33-
| +++++++++++++++++++++++++
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+
| ++++++++++
3437

3538
error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied
3639
--> $DIR/method-on-unbounded-type-param.rs:8:7
@@ -45,10 +48,13 @@ LL | a.cmp(&b)
4548
which is required by `&mut &T: Iterator`
4649
`T: Iterator`
4750
which is required by `&mut T: Iterator`
48-
help: consider restricting the type parameters to satisfy the trait bounds
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:
4953
|
50-
LL | fn h<T>(a: &T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord {
51-
| +++++++++++++++++++++++++
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+
| ++++++++++
5258

5359
error[E0599]: the method `cmp` exists for struct `Box<dyn T>`, but its trait bounds were not satisfied
5460
--> $DIR/method-on-unbounded-type-param.rs:14:7
@@ -68,6 +74,10 @@ LL | x.cmp(&x);
6874
which is required by `&mut Box<dyn T>: Iterator`
6975
`dyn T: Iterator`
7076
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`
7181

7282
error: aborting due to 4 previous errors
7383

0 commit comments

Comments
 (0)