Skip to content

Confusing E0277 diagnostic with blanket implementations #119983

Closed
@zopsicle

Description

@zopsicle

Code

trait A {}
trait B {}
impl<T> A for T where T: B {}
fn f<T>(_: T) where T: A {}
fn g() { f(()) }

Current output

error[E0277]: the trait bound `(): B` is not satisfied
 --> <source>:5:12
  |
5 | fn g() { f(()) }
  |          - ^^ the trait `B` is not implemented for `()`
  |          |
  |          required by a bound introduced by this call
  |
note: required for `()` to implement `A`
 --> <source>:3:9
  |
3 | impl<T> A for T where T: B {}
  |         ^     ^          - unsatisfied trait bound introduced here
note: required by a bound in `f`
 --> <source>:4:24
  |
4 | fn f<T>(_: T) where T: A {}
  |                        ^ required by this bound in `f`

Desired output

error[E0277]: the trait bound `(): A` is not satisfied
 --> <source>:5:12
  |
5 | fn g() { f(()) }
  |          - ^^ the trait `A` is not implemented for `()`
  |          |
  |          required by a bound introduced by this call
  |
note: required by a bound in `f`
 --> <source>:4:24
  |
4 | fn f<T>(_: T) where T: A {}
  |                        ^ required by this bound in `f`
note: an implementation of `B` for `()` would also satisfy this bound
 --> <source>:3:9
  |
3 | impl<T> A for T where T: B {}
  |         ^     ^          - blanket implementation defined here

Rationale and extra context

impl A for () {} and impl B for () {} are both valid solutions, but the diagnostic focuses only on the latter. A suggestion to implement A is arguably easier to understand, as it directly implements the trait that the bound on f requires, rather than indirectly. In fact, given no knowledge about the intended semantics for A and B, for any given type T, impl B for T {} is less likely to be correct than impl A for T {}, since B may pose additional informal (e.g. safety, documented invariants) requirements on top of those posed by A.

In my experience this often comes up when using bytemuck, which defines impl<T: Pod> AnyBitPattern for T.

I understand that the current diagnostic is helpful when the bound is T: Into<U> or T: TryInto<U> and the compiler better suggest to implement From or TryFrom. Perhaps these traits could be annotated with an attribute, which would then also emit a warning when implementing Into and TryInto non-blanketly.

Other cases

No response

Rust Version

rustc 1.73.0 (cc66ad468 2023-10-03)
binary: rustc
commit-hash: cc66ad468955717ab92600c770da8c1601a4ff33
commit-date: 2023-10-03
host: x86_64-unknown-linux-gnu
release: 1.73.0
LLVM version: 17.0.2

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsT-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