Skip to content

Bound error caused by imperfect derives should include links to further explanation #157117

@estebank

Description

@estebank

Code

#[derive(Debug)]
struct S<T>(T);

struct X;
fn main() {
    println!("{:?}", S(X));
}

Current output

error[E0277]: `X` doesn't implement `Debug`
 --> src/main.rs:6:22
  |
6 |     println!("{:?}", S(X));
  |               ----   ^^^^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug`
  |               |
  |               required by this formatting parameter
  |
  = help: the trait `Debug` is not implemented for `X`
  = note: add `#[derive(Debug)]` to `X` or manually `impl Debug for X`
help: the trait `Debug` is implemented for `S<T>`
 --> src/main.rs:1:10
  |
1 | #[derive(Debug)]
  |          ^^^^^
note: required for `S<X>` to implement `Debug`
 --> src/main.rs:2:8
  |
1 | #[derive(Debug)]
  |          ----- in this derive macro expansion
2 | struct S<T>(T);
  |        ^ - type parameter would need to implement `Debug`
  = help: consider manually implementing `Debug` to avoid undesired bounds
help: consider annotating `X` with `#[derive(Debug)]`
  |
4 + #[derive(Debug)]
5 | struct X;
  |

Desired output

error[E0277]: `X` doesn't implement `Debug`
 --> src/main.rs:6:22
  |
6 |     println!("{:?}", S(X));
  |               ----   ^^^^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug`
  |               |
  |               required by this formatting parameter
  |
  = help: the trait `Debug` is not implemented for `X`
  = note: add `#[derive(Debug)]` to `X` or manually `impl Debug for X`
help: the trait `Debug` is implemented for `S<T>`
 --> src/main.rs:1:10
  |
1 | #[derive(Debug)]
  |          ^^^^^
note: required for `S<X>` to implement `Debug`
 --> src/main.rs:2:8
  |
1 | #[derive(Debug)]
  |          ----- in this derive macro expansion
2 | struct S<T>(T);
  |        ^ - type parameter would need to implement `Debug`
  = help: consider manually implementing `Debug` to avoid undesired bounds caused by "imperfect derives", or using a crate like `derive-where`, `derivative` or `perfect_derive`
          to learn more, visit <https://github.com/rust-lang/rust/issues/26925> and <https://smallcultfollowing.com/babysteps//blog/2022/04/12/implied-bounds-and-perfect-derive/>
help: consider annotating `X` with `#[derive(Debug)]`
  |
4 + #[derive(Debug)]
5 | struct X;
  |

Rationale and extra context

Imperfect derives are non-obvious and require additional context for what they are and why they are the way they are. There's currently no single place where all of the reasons for them is properly documented. We should likely add either more info in The Reference, The Book, but for now we can at least update the "canonical" ticket #26925 description with a summary of the situation (the trait system was blocking us due to cycles, the new trait system should be unblocking this, changing to perfect derives would be a semver hazard) and link to it.

The "desired output" above is just an example and doesn't need to be followed exactly.

Other cases

Rust Version

1.95 through 1.98-nightly

Anything else?

Noticed the lack of centralized info on the matter and possibility to improve the diagnostic after seeing https://www.reddit.com/r/rust/comments/1tkpxf8/rusts_standard_derives_are_dumb/

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-trait-systemArea: Trait systemD-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions