Rollup merge of #106788 - estebank:elaborate_pred_E0599, r=compiler-errors
Tweak E0599 and elaborate_predicates CC https://github.com/rust-lang/rust/issues/86377.
This commit is contained in:
commit
8c538f7d83
@ -1587,11 +1587,29 @@ fn consider_probe(
|
||||
let o = self.resolve_vars_if_possible(o);
|
||||
if !self.predicate_may_hold(&o) {
|
||||
result = ProbeResult::NoMatch;
|
||||
possibly_unsatisfied_predicates.push((
|
||||
o.predicate,
|
||||
None,
|
||||
Some(o.cause),
|
||||
));
|
||||
let parent_o = o.clone();
|
||||
let implied_obligations =
|
||||
traits::elaborate_obligations(self.tcx, vec![o]);
|
||||
for o in implied_obligations {
|
||||
let parent = if o == parent_o {
|
||||
None
|
||||
} else {
|
||||
if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id())
|
||||
== self.tcx.lang_items().sized_trait()
|
||||
{
|
||||
// We don't care to talk about implicit `Sized` bounds.
|
||||
continue;
|
||||
}
|
||||
Some(parent_o.predicate)
|
||||
};
|
||||
if !self.predicate_may_hold(&o) {
|
||||
possibly_unsatisfied_predicates.push((
|
||||
o.predicate,
|
||||
parent,
|
||||
Some(o.cause),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -505,19 +505,21 @@ pub fn report_no_match_method_error(
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
|
||||
if let Some(g) = kind.generics() {
|
||||
let key = (
|
||||
g.tail_span_for_predicate_suggestion(),
|
||||
g.add_where_or_trailing_comma(),
|
||||
);
|
||||
type_params
|
||||
.entry(key)
|
||||
.or_insert_with(FxHashSet::default)
|
||||
.insert(obligation.to_owned());
|
||||
}
|
||||
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node
|
||||
&& let Some(g) = kind.generics()
|
||||
{
|
||||
let key = (
|
||||
g.tail_span_for_predicate_suggestion(),
|
||||
g.add_where_or_trailing_comma(),
|
||||
);
|
||||
type_params
|
||||
.entry(key)
|
||||
.or_insert_with(FxHashSet::default)
|
||||
.insert(obligation.to_owned());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
|
||||
let msg = format!(
|
||||
@ -692,7 +694,20 @@ pub fn report_no_match_method_error(
|
||||
"auto trait is invoked with no method error, but no error reported?",
|
||||
);
|
||||
}
|
||||
Some(_) => unreachable!(),
|
||||
Some(Node::Item(hir::Item {
|
||||
ident, kind: hir::ItemKind::Trait(..), ..
|
||||
})) => {
|
||||
skip_list.insert(p);
|
||||
let entry = spanned_predicates.entry(ident.span);
|
||||
let entry = entry.or_insert_with(|| {
|
||||
(FxHashSet::default(), FxHashSet::default(), Vec::new())
|
||||
});
|
||||
entry.0.insert(cause.span);
|
||||
entry.1.insert((ident.span, ""));
|
||||
entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
|
||||
entry.2.push(p);
|
||||
}
|
||||
Some(node) => unreachable!("encountered `{node:?}`"),
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
@ -719,19 +734,39 @@ pub fn report_no_match_method_error(
|
||||
unsatisfied_bounds = true;
|
||||
}
|
||||
|
||||
let mut suggested_bounds = FxHashSet::default();
|
||||
// The requirements that didn't have an `impl` span to show.
|
||||
let mut bound_list = unsatisfied_predicates
|
||||
.iter()
|
||||
.filter_map(|(pred, parent_pred, _cause)| {
|
||||
let mut suggested = false;
|
||||
format_pred(*pred).map(|(p, self_ty)| {
|
||||
collect_type_param_suggestions(self_ty, *pred, &p);
|
||||
if let Some(parent) = parent_pred && suggested_bounds.contains(parent) {
|
||||
// We don't suggest `PartialEq` when we already suggest `Eq`.
|
||||
} else if !suggested_bounds.contains(pred) {
|
||||
if collect_type_param_suggestions(self_ty, *pred, &p) {
|
||||
suggested = true;
|
||||
suggested_bounds.insert(pred);
|
||||
}
|
||||
}
|
||||
(
|
||||
match parent_pred {
|
||||
None => format!("`{}`", &p),
|
||||
Some(parent_pred) => match format_pred(*parent_pred) {
|
||||
None => format!("`{}`", &p),
|
||||
Some((parent_p, _)) => {
|
||||
collect_type_param_suggestions(self_ty, *parent_pred, &p);
|
||||
if !suggested
|
||||
&& !suggested_bounds.contains(pred)
|
||||
&& !suggested_bounds.contains(parent_pred)
|
||||
{
|
||||
if collect_type_param_suggestions(
|
||||
self_ty,
|
||||
*parent_pred,
|
||||
&p,
|
||||
) {
|
||||
suggested_bounds.insert(pred);
|
||||
}
|
||||
}
|
||||
format!("`{}`\nwhich is required by `{}`", p, parent_p)
|
||||
}
|
||||
},
|
||||
|
@ -1,7 +1,7 @@
|
||||
use smallvec::smallvec;
|
||||
|
||||
use crate::infer::outlives::components::{push_outlives_components, Component};
|
||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
|
||||
use crate::traits::{self, Obligation, ObligationCause, PredicateObligation};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||
use rustc_middle::ty::{self, ToPredicate, TyCtxt};
|
||||
use rustc_span::symbol::Ident;
|
||||
@ -145,16 +145,28 @@ fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
|
||||
// Get predicates declared on the trait.
|
||||
let predicates = tcx.super_predicates_of(data.def_id());
|
||||
|
||||
let obligations = predicates.predicates.iter().map(|&(mut pred, _)| {
|
||||
let obligations = predicates.predicates.iter().map(|&(mut pred, span)| {
|
||||
// when parent predicate is non-const, elaborate it to non-const predicates.
|
||||
if data.constness == ty::BoundConstness::NotConst {
|
||||
pred = pred.without_const(tcx);
|
||||
}
|
||||
|
||||
let cause = obligation.cause.clone().derived_cause(
|
||||
bound_predicate.rebind(data),
|
||||
|derived| {
|
||||
traits::ImplDerivedObligation(Box::new(
|
||||
traits::ImplDerivedObligationCause {
|
||||
derived,
|
||||
impl_def_id: data.def_id(),
|
||||
span,
|
||||
},
|
||||
))
|
||||
},
|
||||
);
|
||||
predicate_obligation(
|
||||
pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
cause,
|
||||
)
|
||||
});
|
||||
debug!(?data, ?obligations, "super_predicates");
|
||||
|
@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
|
||||
LL | type Assoc = T;
|
||||
| ^ the trait `Copy` is not implemented for `T`
|
||||
|
|
||||
note: required for `<T as Complete>::Assoc` to implement `Partial<T>`
|
||||
--> $DIR/issue-43784-associated-type.rs:1:11
|
||||
|
|
||||
LL | pub trait Partial<X: ?Sized>: Copy {
|
||||
| ^^^^^^^
|
||||
note: required by a bound in `Complete::Assoc`
|
||||
--> $DIR/issue-43784-associated-type.rs:5:17
|
||||
|
|
||||
|
@ -6,12 +6,15 @@ LL | struct Value(u32);
|
||||
| |
|
||||
| doesn't satisfy `Value: Eq`
|
||||
| doesn't satisfy `Value: Hash`
|
||||
| doesn't satisfy `Value: PartialEq`
|
||||
...
|
||||
LL | hs.insert(Value(0));
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`Value: Eq`
|
||||
`Value: PartialEq`
|
||||
which is required by `Value: Eq`
|
||||
`Value: Hash`
|
||||
help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]`
|
||||
|
|
||||
@ -22,7 +25,10 @@ error[E0599]: the method `use_eq` exists for struct `Object<NoDerives>`, but its
|
||||
--> $DIR/issue-91550.rs:26:9
|
||||
|
|
||||
LL | pub struct NoDerives;
|
||||
| -------------------- doesn't satisfy `NoDerives: Eq`
|
||||
| --------------------
|
||||
| |
|
||||
| doesn't satisfy `NoDerives: Eq`
|
||||
| doesn't satisfy `NoDerives: PartialEq`
|
||||
LL |
|
||||
LL | struct Object<T>(T);
|
||||
| ---------------- method `use_eq` not found for this struct
|
||||
@ -37,6 +43,9 @@ LL | impl<T: Eq> Object<T> {
|
||||
| ^^ ---------
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`NoDerives: PartialEq`
|
||||
which is required by `NoDerives: Eq`
|
||||
help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]`
|
||||
|
|
||||
LL | #[derive(Eq, PartialEq)]
|
||||
@ -46,7 +55,12 @@ error[E0599]: the method `use_ord` exists for struct `Object<NoDerives>`, but it
|
||||
--> $DIR/issue-91550.rs:27:9
|
||||
|
|
||||
LL | pub struct NoDerives;
|
||||
| -------------------- doesn't satisfy `NoDerives: Ord`
|
||||
| --------------------
|
||||
| |
|
||||
| doesn't satisfy `NoDerives: Eq`
|
||||
| doesn't satisfy `NoDerives: Ord`
|
||||
| doesn't satisfy `NoDerives: PartialEq`
|
||||
| doesn't satisfy `NoDerives: PartialOrd`
|
||||
LL |
|
||||
LL | struct Object<T>(T);
|
||||
| ---------------- method `use_ord` not found for this struct
|
||||
@ -61,6 +75,13 @@ LL | impl<T: Ord> Object<T> {
|
||||
| ^^^ ---------
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`NoDerives: PartialOrd`
|
||||
which is required by `NoDerives: Ord`
|
||||
`NoDerives: PartialEq`
|
||||
which is required by `NoDerives: Ord`
|
||||
`NoDerives: Eq`
|
||||
which is required by `NoDerives: Ord`
|
||||
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
|
||||
|
|
||||
LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
|
||||
@ -72,7 +93,9 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object<NoD
|
||||
LL | pub struct NoDerives;
|
||||
| --------------------
|
||||
| |
|
||||
| doesn't satisfy `NoDerives: Eq`
|
||||
| doesn't satisfy `NoDerives: Ord`
|
||||
| doesn't satisfy `NoDerives: PartialEq`
|
||||
| doesn't satisfy `NoDerives: PartialOrd`
|
||||
LL |
|
||||
LL | struct Object<T>(T);
|
||||
@ -91,6 +114,13 @@ LL | impl<T: Ord + PartialOrd> Object<T> {
|
||||
| | |
|
||||
| | unsatisfied trait bound introduced here
|
||||
| unsatisfied trait bound introduced here
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`NoDerives: PartialEq`
|
||||
which is required by `NoDerives: Ord`
|
||||
`NoDerives: Eq`
|
||||
which is required by `NoDerives: Ord`
|
||||
`NoDerives: PartialEq`
|
||||
which is required by `NoDerives: PartialOrd`
|
||||
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
|
||||
|
|
||||
LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
|
||||
|
@ -17,6 +17,7 @@ LL | type Copy<T>: Copy = Box<T>;
|
||||
| ^^^^^^ the trait `Clone` is not implemented for `T`
|
||||
|
|
||||
= note: required for `Box<T>` to implement `Clone`
|
||||
= note: required for `<Self as UnsafeCopy>::Copy<T>` to implement `Copy`
|
||||
note: required by a bound in `UnsafeCopy::Copy`
|
||||
--> $DIR/issue-74824.rs:6:19
|
||||
|
|
||||
|
@ -6,6 +6,8 @@ LL | this.is_subset(other)
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`T: Eq`
|
||||
`T: PartialEq`
|
||||
which is required by `T: Eq`
|
||||
`T: Hash`
|
||||
help: consider restricting the type parameters to satisfy the trait bounds
|
||||
|
|
||||
|
@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
|
||||
LL | impl<T> Complete for T {}
|
||||
| ^ the trait `Copy` is not implemented for `T`
|
||||
|
|
||||
note: required for `T` to implement `Partial`
|
||||
--> $DIR/issue-43784-supertrait.rs:1:11
|
||||
|
|
||||
LL | pub trait Partial: Copy {
|
||||
| ^^^^^^^
|
||||
note: required by a bound in `Complete`
|
||||
--> $DIR/issue-43784-supertrait.rs:4:21
|
||||
|
|
||||
|
88
tests/ui/traits/track-obligations.rs
Normal file
88
tests/ui/traits/track-obligations.rs
Normal file
@ -0,0 +1,88 @@
|
||||
// These are simplifications of the tower traits by the same name:
|
||||
|
||||
pub trait Service<Request> {
|
||||
type Response;
|
||||
}
|
||||
|
||||
pub trait Layer<C> {
|
||||
type Service;
|
||||
}
|
||||
|
||||
// Any type will do here:
|
||||
|
||||
pub struct Req;
|
||||
pub struct Res;
|
||||
|
||||
// This is encoding a trait alias.
|
||||
|
||||
pub trait ParticularService:
|
||||
Service<Req, Response = Res> {
|
||||
}
|
||||
|
||||
impl<T> ParticularService for T
|
||||
where
|
||||
T: Service<Req, Response = Res>,
|
||||
{
|
||||
}
|
||||
|
||||
// This is also a trait alias.
|
||||
// The weird = <Self as ...> bound is there so that users of the trait do not
|
||||
// need to repeat the bounds. See https://github.com/rust-lang/rust/issues/20671
|
||||
// for context, and in particular the workaround in:
|
||||
// https://github.com/rust-lang/rust/issues/20671#issuecomment-529752828
|
||||
|
||||
pub trait ParticularServiceLayer<C>:
|
||||
Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
|
||||
{
|
||||
type Service: ParticularService;
|
||||
}
|
||||
|
||||
impl<T, C> ParticularServiceLayer<C> for T
|
||||
where
|
||||
T: Layer<C>,
|
||||
T::Service: ParticularService,
|
||||
{
|
||||
type Service = T::Service;
|
||||
}
|
||||
|
||||
// These are types that implement the traits that the trait aliases refer to.
|
||||
// They should also implement the alias traits due to the blanket impls.
|
||||
|
||||
struct ALayer<C>(C);
|
||||
impl<C> Layer<C> for ALayer<C> {
|
||||
type Service = AService;
|
||||
}
|
||||
|
||||
struct AService;
|
||||
impl Service<Req> for AService {
|
||||
// However, AService does _not_ meet the blanket implementation,
|
||||
// since its Response type is bool, not Res as it should be.
|
||||
type Response = bool;
|
||||
}
|
||||
|
||||
// This is a wrapper type around ALayer that uses the trait alias
|
||||
// as a way to communicate the requirements of the provided types.
|
||||
struct Client<C>(C);
|
||||
|
||||
// The method and the free-standing function below both have the same bounds.
|
||||
|
||||
impl<C> Client<C>
|
||||
where
|
||||
ALayer<C>: ParticularServiceLayer<C>,
|
||||
{
|
||||
fn check(&self) {}
|
||||
}
|
||||
|
||||
fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
|
||||
|
||||
// But, they give very different error messages.
|
||||
|
||||
fn main() {
|
||||
// This gives a very poor error message that does nothing to point the user
|
||||
// at the underlying cause of why the types involved do not meet the bounds.
|
||||
Client(()).check(); //~ ERROR E0599
|
||||
|
||||
// This gives a good(ish) error message that points the user at _why_ the
|
||||
// bound isn't met, and thus how they might fix it.
|
||||
check(()); //~ ERROR E0271
|
||||
}
|
76
tests/ui/traits/track-obligations.stderr
Normal file
76
tests/ui/traits/track-obligations.stderr
Normal file
@ -0,0 +1,76 @@
|
||||
error[E0599]: the method `check` exists for struct `Client<()>`, but its trait bounds were not satisfied
|
||||
--> $DIR/track-obligations.rs:83:16
|
||||
|
|
||||
LL | struct ALayer<C>(C);
|
||||
| ----------------
|
||||
| |
|
||||
| doesn't satisfy `<_ as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service`
|
||||
| doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>`
|
||||
...
|
||||
LL | struct Client<C>(C);
|
||||
| ---------------- method `check` not found for this struct
|
||||
...
|
||||
LL | Client(()).check();
|
||||
| ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds
|
||||
|
|
||||
note: trait bound `<ALayer<()> as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service` was not satisfied
|
||||
--> $DIR/track-obligations.rs:35:14
|
||||
|
|
||||
LL | pub trait ParticularServiceLayer<C>:
|
||||
| ----------------------
|
||||
LL | Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
|
||||
note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied
|
||||
--> $DIR/track-obligations.rs:71:16
|
||||
|
|
||||
LL | impl<C> Client<C>
|
||||
| ---------
|
||||
LL | where
|
||||
LL | ALayer<C>: ParticularServiceLayer<C>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
|
||||
note: the trait `ParticularServiceLayer` must be implemented
|
||||
--> $DIR/track-obligations.rs:34:1
|
||||
|
|
||||
LL | / pub trait ParticularServiceLayer<C>:
|
||||
LL | | Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
|
||||
| |____________________________________________________________________^
|
||||
|
||||
error[E0271]: type mismatch resolving `<AService as Service<Req>>::Response == Res`
|
||||
--> $DIR/track-obligations.rs:87:11
|
||||
|
|
||||
LL | check(());
|
||||
| ----- ^^ type mismatch resolving `<AService as Service<Req>>::Response == Res`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: expected this to be `Res`
|
||||
--> $DIR/track-obligations.rs:60:21
|
||||
|
|
||||
LL | type Response = bool;
|
||||
| ^^^^
|
||||
note: required for `AService` to implement `ParticularService`
|
||||
--> $DIR/track-obligations.rs:22:9
|
||||
|
|
||||
LL | impl<T> ParticularService for T
|
||||
| ^^^^^^^^^^^^^^^^^ ^
|
||||
LL | where
|
||||
LL | T: Service<Req, Response = Res>,
|
||||
| -------------- unsatisfied trait bound introduced here
|
||||
note: required for `ALayer<_>` to implement `ParticularServiceLayer<_>`
|
||||
--> $DIR/track-obligations.rs:40:12
|
||||
|
|
||||
LL | impl<T, C> ParticularServiceLayer<C> for T
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ ^
|
||||
...
|
||||
LL | T::Service: ParticularService,
|
||||
| ----------------- unsatisfied trait bound introduced here
|
||||
note: required by a bound in `check`
|
||||
--> $DIR/track-obligations.rs:76:36
|
||||
|
|
||||
LL | fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0271, E0599.
|
||||
For more information about an error, try `rustc --explain E0271`.
|
Loading…
Reference in New Issue
Block a user