Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Poor diagnostics for associated type mismatch on inherent method. #86377

Open
jonhoo opened this issue Jun 16, 2021 · 3 comments
Open

Poor diagnostics for associated type mismatch on inherent method. #86377

jonhoo opened this issue Jun 16, 2021 · 3 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@jonhoo
Copy link
Contributor

jonhoo commented Jun 16, 2021

Given the following code (playground):

// 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.

#[allow(dead_code)]
fn test() {
    // 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();
    
    // 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(());
}

The current output (for the indicated bad case) is:

error[E0599]: the method `check` exists for struct `Client<()>`, but its trait bounds were not satisfied
  --> src/lib.rs:82:16
   |
49 | struct ALayer<C>(C);
   | -------------------- doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>`
...
63 | struct Client<C>(C);
   | -------------------- method `check` not found for this
...
82 |     Client(()).check();
   |                ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `ALayer<()>: ParticularServiceLayer<()>`

Ideally the output should look like (the current nightly output for the indicated good case):

error[E0271]: type mismatch resolving `<AService as Service<Req>>::Response == Res`
  --> src/lib.rs:82:5
   |
69 |     ALayer<C>: ParticularServiceLayer<C>,
   |     ------------------------------------ required by this bound in `impl<C> Client<C>`
...
82 |     Client(()).check();
   |                ^^^^^^^ expected struct `Res`, found `bool`
   |
note: required because of the requirements on the impl of `ParticularService` for `AService`
  --> src/lib.rs:22:9
   |
22 | impl<T> ParticularService for T
   |         ^^^^^^^^^^^^^^^^^     ^
note: required because of the requirements on the impl of `ParticularServiceLayer<_>` for `ALayer<_>`
  --> src/lib.rs:38:12
   |
38 | impl<T, C> ParticularServiceLayer<C> for T
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^     ^

Actually pointing at the associated type and where the requirement that it be Res comes from would also be helpful to make it perfect.

@jonhoo jonhoo added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 16, 2021
@JohnTitor JohnTitor added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jul 1, 2021
@estebank
Copy link
Contributor

Current output:

error[E0599]: the method `check` exists for struct `Client<()>`, but its trait bounds were not satisfied
  --> src/lib.rs:82:16
   |
49 | struct ALayer<C>(C);
   | ---------------- doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>`
...
63 | struct Client<C>(C);
   | ---------------- method `check` not found for this struct
...
82 |     Client(()).check();
   |                ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `ALayer<()>: ParticularServiceLayer<()>`
note: the trait `ParticularServiceLayer` must be implemented
  --> src/lib.rs:34:1
   |
34 | pub trait ParticularServiceLayer<C>: Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0271]: type mismatch resolving `<AService as Service<Req>>::Response == Res`
  --> src/lib.rs:86:11
   |
86 |     check(());
   |     ----- ^^ type mismatch resolving `<AService as Service<Req>>::Response == Res`
   |     |
   |     required by a bound introduced by this call
   |
note: expected this to be `Res`
  --> src/lib.rs:58:21
   |
58 |     type Response = bool;
   |                     ^^^^
note: required for `AService` to implement `ParticularService`
  --> src/lib.rs:22:9
   |
22 | impl<T> ParticularService for T
   |         ^^^^^^^^^^^^^^^^^     ^
note: required for `ALayer<_>` to implement `ParticularServiceLayer<_>`
  --> src/lib.rs:38:12
   |
38 | impl<T, C> ParticularServiceLayer<C> for T
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^     ^
note: required by a bound in `check`
  --> src/lib.rs:74:36
   |
74 | fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`

@estebank
Copy link
Contributor

With #106702, the first case is now

error[E0599]: the method `check` exists for struct `Client<()>`, but its trait bounds were not satisfied
  --> f9.rs:81:16
   |
49 | struct ALayer<C>(C);
   | ---------------- doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>`
...
63 | struct Client<C>(C);
   | ---------------- method `check` not found for this struct
...
81 |     Client(()).check(); //~ ERROR E0599
   |                ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds
   |
note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied
  --> f9.rs:69:16
   |
67 | impl<C> Client<C>
   |         ---------
68 | where
69 |     ALayer<C>: ParticularServiceLayer<C>,
   |                ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
note: the trait `ParticularServiceLayer` must be implemented
  --> f9.rs:34:1
   |
34 | pub trait ParticularServiceLayer<C>: Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

@estebank
Copy link
Contributor

With #106703, the second case is now

error[E0271]: type mismatch resolving `<AService as Service<Req>>::Response == Res`
  --> f9.rs:85:11
   |
85 |     check(()); //~ ERROR E0271
   |     ----- ^^ type mismatch resolving `<AService as Service<Req>>::Response == Res`
   |     |
   |     required by a bound introduced by this call
   |
note: expected this to be `Res`
  --> f9.rs:58:21
   |
58 |     type Response = bool;
   |                     ^^^^
note: required for `AService` to implement `ParticularService`
  --> f9.rs:22:9
   |
22 | impl<T> ParticularService for T
   |         ^^^^^^^^^^^^^^^^^     ^
23 | where
24 |     T: Service<Req, Response = Res>,
   |                     -------------- unsatisfied trait bound introduced here
note: required for `ALayer<_>` to implement `ParticularServiceLayer<_>`
  --> f9.rs:38:12
   |
38 | impl<T, C> ParticularServiceLayer<C> for T
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^     ^
...
41 |     T::Service: ParticularService,
   |                 ----------------- unsatisfied trait bound introduced here
note: required by a bound in `check`
  --> f9.rs:74:36
   |
74 | fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`

estebank added a commit to estebank/rust that referenced this issue Jan 11, 2023
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jan 12, 2023
…errors

Conserve cause of `ImplDerivedObligation` in E0599

CC rust-lang#86377.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jan 14, 2023
…ompiler-errors

Tweak E0599 and elaborate_predicates

CC rust-lang#86377.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jan 14, 2023
…ompiler-errors

Tweak E0599 and elaborate_predicates

CC rust-lang#86377.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jan 14, 2023
…ompiler-errors

Tweak E0599 and elaborate_predicates

CC rust-lang#86377.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants