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 #108428.
This commit is contained in:
parent
9ccc77036a
commit
5c414094ac
9 changed files with 62 additions and 52 deletions
|
@ -540,6 +540,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
let mut bound_spans: SortedMap<Span, Vec<String>> = Default::default();
|
let mut bound_spans: SortedMap<Span, Vec<String>> = Default::default();
|
||||||
let mut restrict_type_params = false;
|
let mut restrict_type_params = false;
|
||||||
|
let mut suggested_derive = false;
|
||||||
let mut unsatisfied_bounds = false;
|
let mut unsatisfied_bounds = false;
|
||||||
if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
|
if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) {
|
||||||
let msg = "consider using `len` instead";
|
let msg = "consider using `len` instead";
|
||||||
|
@ -927,20 +928,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.collect::<Vec<(usize, String)>>();
|
.collect::<Vec<(usize, String)>>();
|
||||||
|
|
||||||
for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
|
if !matches!(rcvr_ty.peel_refs().kind(), ty::Param(_)) {
|
||||||
restrict_type_params = true;
|
for ((span, add_where_or_comma), obligations) in type_params.into_iter() {
|
||||||
// #74886: Sort here so that the output is always the same.
|
restrict_type_params = true;
|
||||||
let obligations = obligations.into_sorted_stable_ord();
|
// #74886: Sort here so that the output is always the same.
|
||||||
err.span_suggestion_verbose(
|
let obligations = obligations.into_sorted_stable_ord();
|
||||||
span,
|
err.span_suggestion_verbose(
|
||||||
format!(
|
span,
|
||||||
"consider restricting the type parameter{s} to satisfy the \
|
format!(
|
||||||
trait bound{s}",
|
"consider restricting the type parameter{s} to satisfy the trait \
|
||||||
s = pluralize!(obligations.len())
|
bound{s}",
|
||||||
),
|
s = pluralize!(obligations.len())
|
||||||
format!("{} {}", add_where_or_comma, obligations.join(", ")),
|
),
|
||||||
Applicability::MaybeIncorrect,
|
format!("{} {}", add_where_or_comma, obligations.join(", ")),
|
||||||
);
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
|
bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically.
|
||||||
|
@ -988,7 +991,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
"the following trait bounds were not satisfied:\n{bound_list}"
|
"the following trait bounds were not satisfied:\n{bound_list}"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
self.suggest_derive(&mut err, unsatisfied_predicates);
|
suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates);
|
||||||
|
|
||||||
unsatisfied_bounds = true;
|
unsatisfied_bounds = true;
|
||||||
}
|
}
|
||||||
|
@ -1211,7 +1214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
|
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive {
|
||||||
} else {
|
} else {
|
||||||
self.suggest_traits_to_import(
|
self.suggest_traits_to_import(
|
||||||
&mut err,
|
&mut err,
|
||||||
|
@ -1221,7 +1224,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
args.map(|args| args.len() + 1),
|
args.map(|args| args.len() + 1),
|
||||||
source,
|
source,
|
||||||
no_match_data.out_of_scope_traits.clone(),
|
no_match_data.out_of_scope_traits.clone(),
|
||||||
unsatisfied_predicates,
|
|
||||||
static_candidates,
|
static_candidates,
|
||||||
unsatisfied_bounds,
|
unsatisfied_bounds,
|
||||||
expected.only_has_type(self),
|
expected.only_has_type(self),
|
||||||
|
@ -2481,7 +2483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
Option<ty::Predicate<'tcx>>,
|
Option<ty::Predicate<'tcx>>,
|
||||||
Option<ObligationCause<'tcx>>,
|
Option<ObligationCause<'tcx>>,
|
||||||
)],
|
)],
|
||||||
) {
|
) -> bool {
|
||||||
let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates);
|
let mut derives = self.note_predicate_source_and_get_derives(err, unsatisfied_predicates);
|
||||||
derives.sort();
|
derives.sort();
|
||||||
derives.dedup();
|
derives.dedup();
|
||||||
|
@ -2506,6 +2508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
!derives_grouped.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn note_derefed_ty_has_method(
|
fn note_derefed_ty_has_method(
|
||||||
|
@ -2708,11 +2711,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
inputs_len: Option<usize>,
|
inputs_len: Option<usize>,
|
||||||
source: SelfSource<'tcx>,
|
source: SelfSource<'tcx>,
|
||||||
valid_out_of_scope_traits: Vec<DefId>,
|
valid_out_of_scope_traits: Vec<DefId>,
|
||||||
unsatisfied_predicates: &[(
|
|
||||||
ty::Predicate<'tcx>,
|
|
||||||
Option<ty::Predicate<'tcx>>,
|
|
||||||
Option<ObligationCause<'tcx>>,
|
|
||||||
)],
|
|
||||||
static_candidates: &[CandidateSource],
|
static_candidates: &[CandidateSource],
|
||||||
unsatisfied_bounds: bool,
|
unsatisfied_bounds: bool,
|
||||||
return_type: Option<Ty<'tcx>>,
|
return_type: Option<Ty<'tcx>>,
|
||||||
|
@ -2977,20 +2975,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
item.visibility(self.tcx).is_public() || info.def_id.is_local()
|
item.visibility(self.tcx).is_public() || info.def_id.is_local()
|
||||||
})
|
})
|
||||||
.is_some()
|
.is_some()
|
||||||
&& (matches!(rcvr_ty.kind(), ty::Param(_))
|
|
||||||
|| unsatisfied_predicates.iter().all(|(p, _, _)| {
|
|
||||||
match p.kind().skip_binder() {
|
|
||||||
// Hide traits if they are present in predicates as they can be fixed without
|
|
||||||
// having to implement them.
|
|
||||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => {
|
|
||||||
t.def_id() == info.def_id
|
|
||||||
}
|
|
||||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => {
|
|
||||||
p.projection_ty.def_id == info.def_id
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
for span in &arbitrary_rcvr {
|
for span in &arbitrary_rcvr {
|
||||||
|
|
|
@ -12,6 +12,9 @@ LL | let _z = y.clone();
|
||||||
which is required by `Box<dyn Foo>: Clone`
|
which is required by `Box<dyn Foo>: Clone`
|
||||||
`dyn Foo: Clone`
|
`dyn Foo: Clone`
|
||||||
which is required by `Box<dyn Foo>: Clone`
|
which is required by `Box<dyn Foo>: Clone`
|
||||||
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
|
= note: the following trait defines an item `clone`, perhaps you need to implement it:
|
||||||
|
candidate #1: `Clone`
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,6 @@ LL | let _j = i.clone();
|
||||||
= note: the following trait bounds were not satisfied:
|
= note: the following trait bounds were not satisfied:
|
||||||
`R: Clone`
|
`R: Clone`
|
||||||
which is required by `Box<R>: Clone`
|
which is required by `Box<R>: Clone`
|
||||||
= help: items from traits can only be used if the trait is implemented and in scope
|
|
||||||
= note: the following trait defines an item `clone`, perhaps you need to implement it:
|
|
||||||
candidate #1: `Clone`
|
|
||||||
help: consider annotating `R` with `#[derive(Clone)]`
|
help: consider annotating `R` with `#[derive(Clone)]`
|
||||||
|
|
|
|
||||||
LL + #[derive(Clone)]
|
LL + #[derive(Clone)]
|
||||||
|
|
|
@ -15,9 +15,6 @@ note: trait bound `NotClone: Clone` was not satisfied
|
||||||
|
|
|
|
||||||
LL | #[derive(Clone)]
|
LL | #[derive(Clone)]
|
||||||
| ^^^^^ unsatisfied trait bound introduced in this `derive` macro
|
| ^^^^^ unsatisfied trait bound introduced in this `derive` macro
|
||||||
= help: items from traits can only be used if the trait is implemented and in scope
|
|
||||||
= note: the following trait defines an item `clone`, perhaps you need to implement it:
|
|
||||||
candidate #1: `Clone`
|
|
||||||
help: consider annotating `NotClone` with `#[derive(Clone)]`
|
help: consider annotating `NotClone` with `#[derive(Clone)]`
|
||||||
|
|
|
|
||||||
LL + #[derive(Clone)]
|
LL + #[derive(Clone)]
|
||||||
|
|
|
@ -5,7 +5,7 @@ trait X {
|
||||||
type Y<T>;
|
type Y<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
trait M {
|
trait M { //~ NOTE
|
||||||
fn f(&self) {}
|
fn f(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,12 @@ LL | impl<T: X<Y<i32> = i32>> M for T {}
|
||||||
| ^^^^^^^^^^^^ - -
|
| ^^^^^^^^^^^^ - -
|
||||||
| |
|
| |
|
||||||
| unsatisfied trait bound introduced here
|
| unsatisfied trait bound introduced here
|
||||||
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
|
note: `M` defines an item `f`, perhaps you need to implement it
|
||||||
|
--> $DIR/method-unsatisfied-assoc-type-predicate.rs:8:1
|
||||||
|
|
|
||||||
|
LL | trait M {
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,12 @@ note: the following trait bounds were not satisfied:
|
||||||
|
|
|
|
||||||
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
||||||
| --------- - ^^^^^^ unsatisfied trait bound introduced here
|
| --------- - ^^^^^^ unsatisfied trait bound introduced here
|
||||||
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
|
note: `StreamExt` defines an item `filterx`, perhaps you need to implement it
|
||||||
|
--> $DIR/issue-30786.rs:66:1
|
||||||
|
|
|
||||||
|
LL | pub trait StreamExt
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
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
|
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
|
||||||
--> $DIR/issue-30786.rs:132:24
|
--> $DIR/issue-30786.rs:132:24
|
||||||
|
@ -33,6 +39,12 @@ note: the following trait bounds were not satisfied:
|
||||||
|
|
|
|
||||||
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
||||||
| --------- - ^^^^^^ unsatisfied trait bound introduced here
|
| --------- - ^^^^^^ unsatisfied trait bound introduced here
|
||||||
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
|
note: `StreamExt` defines an item `countx`, perhaps you need to implement it
|
||||||
|
--> $DIR/issue-30786.rs:66:1
|
||||||
|
|
|
||||||
|
LL | pub trait StreamExt
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -63,8 +63,9 @@ LL | | .take()
|
||||||
note: the trait `Iterator` must be implemented
|
note: the trait `Iterator` must be implemented
|
||||||
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
||||||
= help: items from traits can only be used if the trait is implemented and in scope
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
= note: the following trait defines an item `take`, perhaps you need to implement it:
|
= note: the following traits define an item `take`, perhaps you need to implement one of them:
|
||||||
candidate #1: `Iterator`
|
candidate #1: `std::io::Read`
|
||||||
|
candidate #2: `Iterator`
|
||||||
|
|
||||||
error[E0061]: this method takes 3 arguments but 0 arguments were supplied
|
error[E0061]: this method takes 3 arguments but 0 arguments were supplied
|
||||||
--> $DIR/method-call-err-msg.rs:21:7
|
--> $DIR/method-call-err-msg.rs:21:7
|
||||||
|
|
|
@ -27,10 +27,13 @@ LL | (&a).cmp(&b)
|
||||||
which is required by `&mut &T: Iterator`
|
which is required by `&mut &T: Iterator`
|
||||||
`T: Iterator`
|
`T: Iterator`
|
||||||
which is required by `&mut T: Iterator`
|
which is required by `&mut T: Iterator`
|
||||||
help: consider restricting the type parameters to satisfy the 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 g<T>(a: T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord {
|
LL | fn g<T: Ord>(a: T, b: T) -> std::cmp::Ordering {
|
||||||
| +++++++++++++++++++++++++
|
| +++++
|
||||||
|
LL | fn g<T: Iterator>(a: T, b: T) -> std::cmp::Ordering {
|
||||||
|
| ++++++++++
|
||||||
|
|
||||||
error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied
|
error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied
|
||||||
--> $DIR/method-on-unbounded-type-param.rs:8:7
|
--> $DIR/method-on-unbounded-type-param.rs:8:7
|
||||||
|
@ -45,10 +48,13 @@ LL | a.cmp(&b)
|
||||||
which is required by `&mut &T: Iterator`
|
which is required by `&mut &T: Iterator`
|
||||||
`T: Iterator`
|
`T: Iterator`
|
||||||
which is required by `&mut T: Iterator`
|
which is required by `&mut T: Iterator`
|
||||||
help: consider restricting the type parameters to satisfy the 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 h<T>(a: &T, b: T) -> std::cmp::Ordering where T: Iterator, T: Ord {
|
LL | fn h<T: Ord>(a: &T, b: T) -> std::cmp::Ordering {
|
||||||
| +++++++++++++++++++++++++
|
| +++++
|
||||||
|
LL | fn h<T: Iterator>(a: &T, b: T) -> std::cmp::Ordering {
|
||||||
|
| ++++++++++
|
||||||
|
|
||||||
error[E0599]: the method `cmp` exists for struct `Box<dyn T>`, but its trait bounds were not satisfied
|
error[E0599]: the method `cmp` exists for struct `Box<dyn T>`, but its trait bounds were not satisfied
|
||||||
--> $DIR/method-on-unbounded-type-param.rs:14:7
|
--> $DIR/method-on-unbounded-type-param.rs:14:7
|
||||||
|
@ -68,6 +74,10 @@ LL | x.cmp(&x);
|
||||||
which is required by `&mut Box<dyn T>: Iterator`
|
which is required by `&mut Box<dyn T>: Iterator`
|
||||||
`dyn T: Iterator`
|
`dyn T: Iterator`
|
||||||
which is required by `&mut dyn T: Iterator`
|
which is required by `&mut dyn T: Iterator`
|
||||||
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
|
= note: the following traits define an item `cmp`, perhaps you need to implement one of them:
|
||||||
|
candidate #1: `Ord`
|
||||||
|
candidate #2: `Iterator`
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue