]> git.lizzy.rs Git - rust.git/commitdiff
Add tests
authorEsteban Küber <esteban@kuber.com.ar>
Thu, 12 Jan 2023 21:48:07 +0000 (21:48 +0000)
committerEsteban Küber <esteban@kuber.com.ar>
Fri, 13 Jan 2023 18:20:24 +0000 (18:20 +0000)
tests/ui/traits/track-obligations.rs [new file with mode: 0644]
tests/ui/traits/track-obligations.stderr [new file with mode: 0644]

diff --git a/tests/ui/traits/track-obligations.rs b/tests/ui/traits/track-obligations.rs
new file mode 100644 (file)
index 0000000..77e753c
--- /dev/null
@@ -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
+}
diff --git a/tests/ui/traits/track-obligations.stderr b/tests/ui/traits/track-obligations.stderr
new file mode 100644 (file)
index 0000000..8947747
--- /dev/null
@@ -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`.