summaryrefslogtreecommitdiffstats
path: root/tests/ui/traits/track-obligations.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/ui/traits/track-obligations.rs88
1 files changed, 88 insertions, 0 deletions
diff --git a/tests/ui/traits/track-obligations.rs b/tests/ui/traits/track-obligations.rs
new file mode 100644
index 000000000..77e753c13
--- /dev/null
+++ b/tests/ui/traits/track-obligations.rs
@@ -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
+}