Skip to content

Commit 81ba427

Browse files
committed
Add tests
1 parent 3d6b09e commit 81ba427

File tree

2 files changed

+164
-0
lines changed

2 files changed

+164
-0
lines changed

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+
}
+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
error[E0599]: the method `check` exists for struct `Client<()>`, but its trait bounds were not satisfied
2+
--> $DIR/track-obligations.rs:83:16
3+
|
4+
LL | struct ALayer<C>(C);
5+
| ----------------
6+
| |
7+
| doesn't satisfy `<_ as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service`
8+
| doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>`
9+
...
10+
LL | struct Client<C>(C);
11+
| ---------------- method `check` not found for this struct
12+
...
13+
LL | Client(()).check();
14+
| ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds
15+
|
16+
note: trait bound `<ALayer<()> as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service` was not satisfied
17+
--> $DIR/track-obligations.rs:35:14
18+
|
19+
LL | pub trait ParticularServiceLayer<C>:
20+
| ----------------------
21+
LL | Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
23+
note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied
24+
--> $DIR/track-obligations.rs:71:16
25+
|
26+
LL | impl<C> Client<C>
27+
| ---------
28+
LL | where
29+
LL | ALayer<C>: ParticularServiceLayer<C>,
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
31+
note: the trait `ParticularServiceLayer` must be implemented
32+
--> $DIR/track-obligations.rs:34:1
33+
|
34+
LL | / pub trait ParticularServiceLayer<C>:
35+
LL | | Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
36+
| |____________________________________________________________________^
37+
38+
error[E0271]: type mismatch resolving `<AService as Service<Req>>::Response == Res`
39+
--> $DIR/track-obligations.rs:87:11
40+
|
41+
LL | check(());
42+
| ----- ^^ type mismatch resolving `<AService as Service<Req>>::Response == Res`
43+
| |
44+
| required by a bound introduced by this call
45+
|
46+
note: expected this to be `Res`
47+
--> $DIR/track-obligations.rs:60:21
48+
|
49+
LL | type Response = bool;
50+
| ^^^^
51+
note: required for `AService` to implement `ParticularService`
52+
--> $DIR/track-obligations.rs:22:9
53+
|
54+
LL | impl<T> ParticularService for T
55+
| ^^^^^^^^^^^^^^^^^ ^
56+
LL | where
57+
LL | T: Service<Req, Response = Res>,
58+
| -------------- unsatisfied trait bound introduced here
59+
note: required for `ALayer<_>` to implement `ParticularServiceLayer<_>`
60+
--> $DIR/track-obligations.rs:40:12
61+
|
62+
LL | impl<T, C> ParticularServiceLayer<C> for T
63+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ ^
64+
...
65+
LL | T::Service: ParticularService,
66+
| ----------------- unsatisfied trait bound introduced here
67+
note: required by a bound in `check`
68+
--> $DIR/track-obligations.rs:76:36
69+
|
70+
LL | fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
71+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
72+
73+
error: aborting due to 2 previous errors
74+
75+
Some errors have detailed explanations: E0271, E0599.
76+
For more information about an error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)