Skip to content

Use supertrait as the suggested bound for a blanket impl instead of the bounds from a different blanket impl #118415

Open
@sfleener

Description

@sfleener

Code

trait A: B {
    fn a();
}

trait B {
    fn b();
}

trait C {}

impl<T> B for T
where
    T: C,
{
    fn b() {}
}

impl<T> A for T {
    fn a(){
        Self::b();
    }
}

Current output

error[E0277]: the trait bound `T: C` is not satisfied
  --> src/main.rs:18:15
   |
18 | impl<T> A for T {
   |               ^ the trait `C` is not implemented for `T`
   |
note: required for `T` to implement `B`
  --> src/main.rs:11:9
   |
11 | impl<T> B for T
   |         ^     ^
12 | where
13 |     T: C,
   |        - unsatisfied trait bound introduced here
note: required by a bound in `A`
  --> src/main.rs:1:10
   |
1  | trait A: B {
   |          ^ required by this bound in `A`
help: consider restricting type parameter `T`
   |
18 | impl<T: C> A for T {
   |       +++

For more information about this error, try `rustc --explain E0277`.

Desired output

error[E0277]: the trait bound `T: B` is not satisfied
  --> src/main.rs:18:15
   |
18 | impl<T> A for T {
   |               ^ the trait `B` is not implemented for `T`
   |
note: required by a bound in `A`
  --> src/main.rs:1:10
   |
1  | trait A: B {
   |          ^ required by this bound in `A`
help: consider restricting type parameter `T`
   |
18 | impl<T: B> A for T {
   |       +++

For more information about this error, try `rustc --explain E0277`.

Rationale and extra context

When providing a blanket impl for some trait A with a supertrait B, and B also has a blanket impl bounded on some other trait C, rustc will suggest bounding A's blanket impl on C rather than the supertrait B. This is a little confusing and likely the incorrect bound to suggest, as it would cause types that directly implement B to not satisfy the blanket impl for A, like the following example:

...

impl<T: C> A for T {
    fn a(){
        Self::b();
    }
}

struct D;

impl C for D {}

struct E;

impl B for E {
    fn b() {}
}

pub fn main() {
    D::a();
    E::a(); // error: method cannot be called on `E` due to unsatisfied trait bounds
}

This works as expected if T: B is specified as the bound for the blanket impl on A instead.

playground link

Other cases

No response

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-trait-systemArea: Trait systemD-confusingDiagnostics: Confusing error or lint that should be reworked.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions