Skip to content

Commit 9f0a002

Browse files
committed
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.
1 parent 11dbd30 commit 9f0a002

File tree

4 files changed

+36
-30
lines changed

4 files changed

+36
-30
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+24-18
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
549549

550550
let mut bound_spans = vec![];
551551
let mut restrict_type_params = false;
552+
let mut suggested_derive = false;
552553
let mut unsatisfied_bounds = false;
553554
if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
554555
let msg = "consider using `len` instead";
@@ -932,20 +933,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
932933
.enumerate()
933934
.collect::<Vec<(usize, String)>>();
934935

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

951956
bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
@@ -993,7 +998,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
993998
"the following trait bounds were not satisfied:\n{bound_list}"
994999
));
9951000
}
996-
self.suggest_derive(&mut err, unsatisfied_predicates);
1001+
suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates);
9971002

9981003
unsatisfied_bounds = true;
9991004
}
@@ -1187,7 +1192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11871192
err.span_label(span, msg);
11881193
}
11891194

1190-
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
1195+
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive {
11911196
} else {
11921197
self.suggest_traits_to_import(
11931198
&mut err,
@@ -2447,7 +2452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24472452
Option<ty::Predicate<'tcx>>,
24482453
Option<ObligationCause<'tcx>>,
24492454
)],
2450-
) {
2455+
) -> bool {
24512456
let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates);
24522457
derives.sort();
24532458
derives.dedup();
@@ -2472,6 +2477,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24722477
Applicability::MaybeIncorrect,
24732478
);
24742479
}
2480+
!derives_grouped.is_empty()
24752481
}
24762482

24772483
fn note_derefed_ty_has_method(
@@ -2943,7 +2949,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
29432949
item.visibility(self.tcx).is_public() || info.def_id.is_local()
29442950
})
29452951
.is_some()
2946-
&& (matches!(rcvr_ty.kind(), ty::Param(_))
2952+
&& (matches!(rcvr_ty.peel_refs().kind(), ty::Param(_))
29472953
|| unsatisfied_predicates.iter().all(|(p, _, _)| {
29482954
match p.kind().skip_binder() {
29492955
// Hide traits if they are present in predicates as they can be fixed without

tests/ui/box/unit/unique-pinned-nocopy.stderr

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

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

-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ note: trait bound `NotClone: Clone` was not satisfied
1818
|
1919
LL | #[derive(Clone)]
2020
| ^^^^^ unsatisfied trait bound introduced in this `derive` macro
21-
= help: items from traits can only be used if the trait is implemented and in scope
22-
= note: the following trait defines an item `clone`, perhaps you need to implement it:
23-
candidate #1: `Clone`
2421
help: consider annotating `NotClone` with `#[derive(Clone)]`
2522
|
2623
LL + #[derive(Clone)]

tests/ui/traits/method-on-unbounded-type-param.stderr

+12-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

0 commit comments

Comments
 (0)