Skip to content

Commit 8c538f7

Browse files
authored
Rollup merge of #106788 - estebank:elaborate_pred_E0599, r=compiler-errors
Tweak E0599 and elaborate_predicates CC #86377.
2 parents 108b5f4 + 22a0e4f commit 8c538f7

File tree

10 files changed

+296
-24
lines changed

10 files changed

+296
-24
lines changed

compiler/rustc_hir_typeck/src/method/probe.rs

+23-5
Original file line numberDiff line numberDiff line change
@@ -1587,11 +1587,29 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
15871587
let o = self.resolve_vars_if_possible(o);
15881588
if !self.predicate_may_hold(&o) {
15891589
result = ProbeResult::NoMatch;
1590-
possibly_unsatisfied_predicates.push((
1591-
o.predicate,
1592-
None,
1593-
Some(o.cause),
1594-
));
1590+
let parent_o = o.clone();
1591+
let implied_obligations =
1592+
traits::elaborate_obligations(self.tcx, vec![o]);
1593+
for o in implied_obligations {
1594+
let parent = if o == parent_o {
1595+
None
1596+
} else {
1597+
if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id())
1598+
== self.tcx.lang_items().sized_trait()
1599+
{
1600+
// We don't care to talk about implicit `Sized` bounds.
1601+
continue;
1602+
}
1603+
Some(parent_o.predicate)
1604+
};
1605+
if !self.predicate_may_hold(&o) {
1606+
possibly_unsatisfied_predicates.push((
1607+
o.predicate,
1608+
parent,
1609+
Some(o.cause),
1610+
));
1611+
}
1612+
}
15951613
}
15961614
}
15971615
}

compiler/rustc_hir_typeck/src/method/suggest.rs

+49-14
Original file line numberDiff line numberDiff line change
@@ -505,19 +505,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
505505
}
506506
_ => None,
507507
};
508-
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
509-
if let Some(g) = kind.generics() {
510-
let key = (
511-
g.tail_span_for_predicate_suggestion(),
512-
g.add_where_or_trailing_comma(),
513-
);
514-
type_params
515-
.entry(key)
516-
.or_insert_with(FxHashSet::default)
517-
.insert(obligation.to_owned());
518-
}
508+
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node
509+
&& let Some(g) = kind.generics()
510+
{
511+
let key = (
512+
g.tail_span_for_predicate_suggestion(),
513+
g.add_where_or_trailing_comma(),
514+
);
515+
type_params
516+
.entry(key)
517+
.or_insert_with(FxHashSet::default)
518+
.insert(obligation.to_owned());
519+
return true;
519520
}
520521
}
522+
false
521523
};
522524
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
523525
let msg = format!(
@@ -692,7 +694,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
692694
"auto trait is invoked with no method error, but no error reported?",
693695
);
694696
}
695-
Some(_) => unreachable!(),
697+
Some(Node::Item(hir::Item {
698+
ident, kind: hir::ItemKind::Trait(..), ..
699+
})) => {
700+
skip_list.insert(p);
701+
let entry = spanned_predicates.entry(ident.span);
702+
let entry = entry.or_insert_with(|| {
703+
(FxHashSet::default(), FxHashSet::default(), Vec::new())
704+
});
705+
entry.0.insert(cause.span);
706+
entry.1.insert((ident.span, ""));
707+
entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
708+
entry.2.push(p);
709+
}
710+
Some(node) => unreachable!("encountered `{node:?}`"),
696711
None => (),
697712
}
698713
}
@@ -719,19 +734,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
719734
unsatisfied_bounds = true;
720735
}
721736

737+
let mut suggested_bounds = FxHashSet::default();
722738
// The requirements that didn't have an `impl` span to show.
723739
let mut bound_list = unsatisfied_predicates
724740
.iter()
725741
.filter_map(|(pred, parent_pred, _cause)| {
742+
let mut suggested = false;
726743
format_pred(*pred).map(|(p, self_ty)| {
727-
collect_type_param_suggestions(self_ty, *pred, &p);
744+
if let Some(parent) = parent_pred && suggested_bounds.contains(parent) {
745+
// We don't suggest `PartialEq` when we already suggest `Eq`.
746+
} else if !suggested_bounds.contains(pred) {
747+
if collect_type_param_suggestions(self_ty, *pred, &p) {
748+
suggested = true;
749+
suggested_bounds.insert(pred);
750+
}
751+
}
728752
(
729753
match parent_pred {
730754
None => format!("`{}`", &p),
731755
Some(parent_pred) => match format_pred(*parent_pred) {
732756
None => format!("`{}`", &p),
733757
Some((parent_p, _)) => {
734-
collect_type_param_suggestions(self_ty, *parent_pred, &p);
758+
if !suggested
759+
&& !suggested_bounds.contains(pred)
760+
&& !suggested_bounds.contains(parent_pred)
761+
{
762+
if collect_type_param_suggestions(
763+
self_ty,
764+
*parent_pred,
765+
&p,
766+
) {
767+
suggested_bounds.insert(pred);
768+
}
769+
}
735770
format!("`{}`\nwhich is required by `{}`", p, parent_p)
736771
}
737772
},

compiler/rustc_infer/src/traits/util.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use smallvec::smallvec;
22

33
use crate::infer::outlives::components::{push_outlives_components, Component};
4-
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
4+
use crate::traits::{self, Obligation, ObligationCause, PredicateObligation};
55
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
66
use rustc_middle::ty::{self, ToPredicate, TyCtxt};
77
use rustc_span::symbol::Ident;
@@ -145,16 +145,28 @@ impl<'tcx> Elaborator<'tcx> {
145145
// Get predicates declared on the trait.
146146
let predicates = tcx.super_predicates_of(data.def_id());
147147

148-
let obligations = predicates.predicates.iter().map(|&(mut pred, _)| {
148+
let obligations = predicates.predicates.iter().map(|&(mut pred, span)| {
149149
// when parent predicate is non-const, elaborate it to non-const predicates.
150150
if data.constness == ty::BoundConstness::NotConst {
151151
pred = pred.without_const(tcx);
152152
}
153153

154+
let cause = obligation.cause.clone().derived_cause(
155+
bound_predicate.rebind(data),
156+
|derived| {
157+
traits::ImplDerivedObligation(Box::new(
158+
traits::ImplDerivedObligationCause {
159+
derived,
160+
impl_def_id: data.def_id(),
161+
span,
162+
},
163+
))
164+
},
165+
);
154166
predicate_obligation(
155167
pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
156168
obligation.param_env,
157-
obligation.cause.clone(),
169+
cause,
158170
)
159171
});
160172
debug!(?data, ?obligations, "super_predicates");

tests/ui/associated-types/issue-43784-associated-type.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
44
LL | type Assoc = T;
55
| ^ the trait `Copy` is not implemented for `T`
66
|
7+
note: required for `<T as Complete>::Assoc` to implement `Partial<T>`
8+
--> $DIR/issue-43784-associated-type.rs:1:11
9+
|
10+
LL | pub trait Partial<X: ?Sized>: Copy {
11+
| ^^^^^^^
712
note: required by a bound in `Complete::Assoc`
813
--> $DIR/issue-43784-associated-type.rs:5:17
914
|

tests/ui/derives/issue-91550.stderr

+32-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ LL | struct Value(u32);
66
| |
77
| doesn't satisfy `Value: Eq`
88
| doesn't satisfy `Value: Hash`
9+
| doesn't satisfy `Value: PartialEq`
910
...
1011
LL | hs.insert(Value(0));
1112
| ^^^^^^
1213
|
1314
= note: the following trait bounds were not satisfied:
1415
`Value: Eq`
16+
`Value: PartialEq`
17+
which is required by `Value: Eq`
1518
`Value: Hash`
1619
help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]`
1720
|
@@ -22,7 +25,10 @@ error[E0599]: the method `use_eq` exists for struct `Object<NoDerives>`, but its
2225
--> $DIR/issue-91550.rs:26:9
2326
|
2427
LL | pub struct NoDerives;
25-
| -------------------- doesn't satisfy `NoDerives: Eq`
28+
| --------------------
29+
| |
30+
| doesn't satisfy `NoDerives: Eq`
31+
| doesn't satisfy `NoDerives: PartialEq`
2632
LL |
2733
LL | struct Object<T>(T);
2834
| ---------------- method `use_eq` not found for this struct
@@ -37,6 +43,9 @@ LL | impl<T: Eq> Object<T> {
3743
| ^^ ---------
3844
| |
3945
| unsatisfied trait bound introduced here
46+
= note: the following trait bounds were not satisfied:
47+
`NoDerives: PartialEq`
48+
which is required by `NoDerives: Eq`
4049
help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]`
4150
|
4251
LL | #[derive(Eq, PartialEq)]
@@ -46,7 +55,12 @@ error[E0599]: the method `use_ord` exists for struct `Object<NoDerives>`, but it
4655
--> $DIR/issue-91550.rs:27:9
4756
|
4857
LL | pub struct NoDerives;
49-
| -------------------- doesn't satisfy `NoDerives: Ord`
58+
| --------------------
59+
| |
60+
| doesn't satisfy `NoDerives: Eq`
61+
| doesn't satisfy `NoDerives: Ord`
62+
| doesn't satisfy `NoDerives: PartialEq`
63+
| doesn't satisfy `NoDerives: PartialOrd`
5064
LL |
5165
LL | struct Object<T>(T);
5266
| ---------------- method `use_ord` not found for this struct
@@ -61,6 +75,13 @@ LL | impl<T: Ord> Object<T> {
6175
| ^^^ ---------
6276
| |
6377
| unsatisfied trait bound introduced here
78+
= note: the following trait bounds were not satisfied:
79+
`NoDerives: PartialOrd`
80+
which is required by `NoDerives: Ord`
81+
`NoDerives: PartialEq`
82+
which is required by `NoDerives: Ord`
83+
`NoDerives: Eq`
84+
which is required by `NoDerives: Ord`
6485
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
6586
|
6687
LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
@@ -72,7 +93,9 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object<NoD
7293
LL | pub struct NoDerives;
7394
| --------------------
7495
| |
96+
| doesn't satisfy `NoDerives: Eq`
7597
| doesn't satisfy `NoDerives: Ord`
98+
| doesn't satisfy `NoDerives: PartialEq`
7699
| doesn't satisfy `NoDerives: PartialOrd`
77100
LL |
78101
LL | struct Object<T>(T);
@@ -91,6 +114,13 @@ LL | impl<T: Ord + PartialOrd> Object<T> {
91114
| | |
92115
| | unsatisfied trait bound introduced here
93116
| unsatisfied trait bound introduced here
117+
= note: the following trait bounds were not satisfied:
118+
`NoDerives: PartialEq`
119+
which is required by `NoDerives: Ord`
120+
`NoDerives: Eq`
121+
which is required by `NoDerives: Ord`
122+
`NoDerives: PartialEq`
123+
which is required by `NoDerives: PartialOrd`
94124
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
95125
|
96126
LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]

tests/ui/generic-associated-types/issue-74824.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ LL | type Copy<T>: Copy = Box<T>;
1717
| ^^^^^^ the trait `Clone` is not implemented for `T`
1818
|
1919
= note: required for `Box<T>` to implement `Clone`
20+
= note: required for `<Self as UnsafeCopy>::Copy<T>` to implement `Copy`
2021
note: required by a bound in `UnsafeCopy::Copy`
2122
--> $DIR/issue-74824.rs:6:19
2223
|

tests/ui/missing-trait-bounds/issue-35677.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ LL | this.is_subset(other)
66
|
77
= note: the following trait bounds were not satisfied:
88
`T: Eq`
9+
`T: PartialEq`
10+
which is required by `T: Eq`
911
`T: Hash`
1012
help: consider restricting the type parameters to satisfy the trait bounds
1113
|

tests/ui/traits/issue-43784-supertrait.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
44
LL | impl<T> Complete for T {}
55
| ^ the trait `Copy` is not implemented for `T`
66
|
7+
note: required for `T` to implement `Partial`
8+
--> $DIR/issue-43784-supertrait.rs:1:11
9+
|
10+
LL | pub trait Partial: Copy {
11+
| ^^^^^^^
712
note: required by a bound in `Complete`
813
--> $DIR/issue-43784-supertrait.rs:4:21
914
|

tests/ui/traits/track-obligations.rs

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// These are simplifications of the tower traits by the same name:
2+
3+
pub trait Service<Request> {
4+
type Response;
5+
}
6+
7+
pub trait Layer<C> {
8+
type Service;
9+
}
10+
11+
// Any type will do here:
12+
13+
pub struct Req;
14+
pub struct Res;
15+
16+
// This is encoding a trait alias.
17+
18+
pub trait ParticularService:
19+
Service<Req, Response = Res> {
20+
}
21+
22+
impl<T> ParticularService for T
23+
where
24+
T: Service<Req, Response = Res>,
25+
{
26+
}
27+
28+
// This is also a trait alias.
29+
// The weird = <Self as ...> bound is there so that users of the trait do not
30+
// need to repeat the bounds. See https://github.com/rust-lang/rust/issues/20671
31+
// for context, and in particular the workaround in:
32+
// https://github.com/rust-lang/rust/issues/20671#issuecomment-529752828
33+
34+
pub trait ParticularServiceLayer<C>:
35+
Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
36+
{
37+
type Service: ParticularService;
38+
}
39+
40+
impl<T, C> ParticularServiceLayer<C> for T
41+
where
42+
T: Layer<C>,
43+
T::Service: ParticularService,
44+
{
45+
type Service = T::Service;
46+
}
47+
48+
// These are types that implement the traits that the trait aliases refer to.
49+
// They should also implement the alias traits due to the blanket impls.
50+
51+
struct ALayer<C>(C);
52+
impl<C> Layer<C> for ALayer<C> {
53+
type Service = AService;
54+
}
55+
56+
struct AService;
57+
impl Service<Req> for AService {
58+
// However, AService does _not_ meet the blanket implementation,
59+
// since its Response type is bool, not Res as it should be.
60+
type Response = bool;
61+
}
62+
63+
// This is a wrapper type around ALayer that uses the trait alias
64+
// as a way to communicate the requirements of the provided types.
65+
struct Client<C>(C);
66+
67+
// The method and the free-standing function below both have the same bounds.
68+
69+
impl<C> Client<C>
70+
where
71+
ALayer<C>: ParticularServiceLayer<C>,
72+
{
73+
fn check(&self) {}
74+
}
75+
76+
fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
77+
78+
// But, they give very different error messages.
79+
80+
fn main() {
81+
// This gives a very poor error message that does nothing to point the user
82+
// at the underlying cause of why the types involved do not meet the bounds.
83+
Client(()).check(); //~ ERROR E0599
84+
85+
// This gives a good(ish) error message that points the user at _why_ the
86+
// bound isn't met, and thus how they might fix it.
87+
check(()); //~ ERROR E0271
88+
}

0 commit comments

Comments
 (0)