Skip to content

Commit af99946

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 59ba802 + 5c41409 commit af99946

9 files changed

+62
-52
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+21-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";
@@ -928,20 +929,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
928929
.enumerate()
929930
.collect::<Vec<(usize, String)>>();
930931

931-
for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
932-
restrict_type_params = true;
933-
// #74886: Sort here so that the output is always the same.
934-
let obligations = obligations.into_sorted_stable_ord();
935-
err.span_suggestion_verbose(
936-
span,
937-
format!(
938-
"consider restricting the type parameter{s} to satisfy the \
939-
trait bound{s}",
940-
s = pluralize!(obligations.len())
941-
),
942-
format!("{} {}", add_where_or_comma, obligations.join(", ")),
943-
Applicability::MaybeIncorrect,
944-
);
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+
}
945948
}
946949

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

994997
unsatisfied_bounds = true;
995998
}
@@ -1212,7 +1215,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12121215
);
12131216
}
12141217

1215-
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 {
12161219
} else {
12171220
self.suggest_traits_to_import(
12181221
&mut err,
@@ -1222,7 +1225,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12221225
args.map(|args| args.len() + 1),
12231226
source,
12241227
no_match_data.out_of_scope_traits.clone(),
1225-
unsatisfied_predicates,
12261228
static_candidates,
12271229
unsatisfied_bounds,
12281230
expected.only_has_type(self),
@@ -2482,7 +2484,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24822484
Option<ty::Predicate<'tcx>>,
24832485
Option<ObligationCause<'tcx>>,
24842486
)],
2485-
) {
2487+
) -> bool {
24862488
let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates);
24872489
derives.sort();
24882490
derives.dedup();
@@ -2507,6 +2509,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25072509
Applicability::MaybeIncorrect,
25082510
);
25092511
}
2512+
!derives_grouped.is_empty()
25102513
}
25112514

25122515
fn note_derefed_ty_has_method(
@@ -2709,11 +2712,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
27092712
inputs_len: Option<usize>,
27102713
source: SelfSource<'tcx>,
27112714
valid_out_of_scope_traits: Vec<DefId>,
2712-
unsatisfied_predicates: &[(
2713-
ty::Predicate<'tcx>,
2714-
Option<ty::Predicate<'tcx>>,
2715-
Option<ObligationCause<'tcx>>,
2716-
)],
27172715
static_candidates: &[CandidateSource],
27182716
unsatisfied_bounds: bool,
27192717
return_type: Option<Ty<'tcx>>,
@@ -2978,20 +2976,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
29782976
item.visibility(self.tcx).is_public() || info.def_id.is_local()
29792977
})
29802978
.is_some()
2981-
&& (matches!(rcvr_ty.kind(), ty::Param(_))
2982-
|| unsatisfied_predicates.iter().all(|(p, _, _)| {
2983-
match p.kind().skip_binder() {
2984-
// Hide traits if they are present in predicates as they can be fixed without
2985-
// having to implement them.
2986-
ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => {
2987-
t.def_id() == info.def_id
2988-
}
2989-
ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => {
2990-
p.projection_ty.def_id == info.def_id
2991-
}
2992-
_ => false,
2993-
}
2994-
}))
29952979
})
29962980
.collect::<Vec<_>>();
29972981
for span in &arbitrary_rcvr {

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

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)]

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)]

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

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

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>}>, {[email protected]: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

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

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)