From 81ba427a7b15d614a74812ef3fd1467c85d4768d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 12 Jan 2023 21:48:07 +0000 Subject: [PATCH] Add tests --- tests/ui/traits/track-obligations.rs | 88 ++++++++++++++++++++++++ tests/ui/traits/track-obligations.stderr | 76 ++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 tests/ui/traits/track-obligations.rs create mode 100644 tests/ui/traits/track-obligations.stderr diff --git a/tests/ui/traits/track-obligations.rs b/tests/ui/traits/track-obligations.rs new file mode 100644 index 00000000000..77e753c13f7 --- /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 { + type Response; +} + +pub trait Layer { + type Service; +} + +// Any type will do here: + +pub struct Req; +pub struct Res; + +// This is encoding a trait alias. + +pub trait ParticularService: + Service { +} + +impl ParticularService for T +where + T: Service, +{ +} + +// This is also a trait alias. +// The weird = 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: + Layer>::Service> +{ + type Service: ParticularService; +} + +impl ParticularServiceLayer for T +where + T: Layer, + 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); +impl Layer for ALayer { + type Service = AService; +} + +struct AService; +impl Service 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); + +// The method and the free-standing function below both have the same bounds. + +impl Client +where + ALayer: ParticularServiceLayer, +{ + fn check(&self) {} +} + +fn check(_: C) where ALayer: ParticularServiceLayer {} + +// 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 index 00000000000..89477475970 --- /dev/null +++ b/tests/ui/traits/track-obligations.stderr @@ -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); + | ---------------- + | | + | doesn't satisfy `<_ as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` + | doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>` +... +LL | struct Client(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 ` as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` was not satisfied + --> $DIR/track-obligations.rs:35:14 + | +LL | pub trait ParticularServiceLayer: + | ---------------------- +LL | Layer>::Service> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here +note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied + --> $DIR/track-obligations.rs:71:16 + | +LL | impl Client + | --------- +LL | where +LL | ALayer: ParticularServiceLayer, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here +note: the trait `ParticularServiceLayer` must be implemented + --> $DIR/track-obligations.rs:34:1 + | +LL | / pub trait ParticularServiceLayer: +LL | | Layer>::Service> + | |____________________________________________________________________^ + +error[E0271]: type mismatch resolving `>::Response == Res` + --> $DIR/track-obligations.rs:87:11 + | +LL | check(()); + | ----- ^^ type mismatch resolving `>::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 ParticularService for T + | ^^^^^^^^^^^^^^^^^ ^ +LL | where +LL | T: Service, + | -------------- unsatisfied trait bound introduced here +note: required for `ALayer<_>` to implement `ParticularServiceLayer<_>` + --> $DIR/track-obligations.rs:40:12 + | +LL | impl ParticularServiceLayer 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) where ALayer: ParticularServiceLayer {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ 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`.