rust-lang / rust-lang/rust

Confusing "Mismatched types" error due to unsatisfied trait bound

Open
#126,619 4 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

A-diagnostics T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Code
// #[derive(Clone)] // <- uncomment this to fix it
struct Thing;

fn main() {
    message_fn(Message1);
}

fn message_fn<M>(_: M)
where
    Thing: HasMessage<M>,
{
    unimplemented!()
}

trait HasMessage<T> {}

struct Message1;
impl<M: Clone> HasMessage<Message1> for M {}

struct Message2;
impl<M> HasMessage<Message2> for M {}

playground link

Current output
   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
 --> src/main.rs:5:16
  |
5 |     message_fn(Message1);
  |     ---------- ^^^^^^^^ expected `Message2`, found `Message1`
  |     |
  |     arguments to this function are incorrect
  |
note: function defined here
 --> src/main.rs:8:4
  |
8 | fn message_fn<M>(_: M)
  |    ^^^^^^^^^^    ----

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` (bin "playground") due to 1 previous error
Desired output
Something mentioning the fact that `Thing` doesn't implement `Clone`.
Rationale and extra context

It's unclear to me why rust decides that the Message2 impl must be the intended impl in main. The intended impl is the Message1 one.

The actual reason the code shouldn't compile is because the author of the code forgot to implement Clone for Thing, which is required for the Message1 impl. However, figuring that out from the error message is difficult, especially in the original code where there are other stuff going on.

Other cases

Adding a Message3 results in a reasonable error

Code and error
// #[derive(Clone)] // <- uncomment this to fix it
struct Thing;

fn main() {
    message_fn(Message1);
}

fn message_fn<M>(_: M)
where
    Thing: HasMessage<M>,
{
    unimplemented!()
}

trait HasMessage<T> {}

struct Message1;
impl<M: Clone> HasMessage<Message1> for M {}

struct Message2;
impl<M> HasMessage<Message2> for M {}

struct Message3;
impl<M> HasMessage<Message3> for M {}
   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `Thing: HasMessage<Message1>` is not satisfied
  --> src/main.rs:5:16
   |
5  |     message_fn(Message1);
   |     ---------- ^^^^^^^^ the trait `HasMessage<Message1>` is not implemented for `Thing`
   |     |
   |     required by a bound introduced by this call
   |
note: required for `Thing` to implement `HasMessage<Message1>`
  --> src/main.rs:18:16
   |
18 | impl<M: Clone> HasMessage<Message1> for M {}
   |         -----  ^^^^^^^^^^^^^^^^^^^^     ^
   |         |
   |         unsatisfied trait bound introduced here
note: required by a bound in `message_fn`
  --> src/main.rs:10:12
   |
8  | fn message_fn<M>(_: M)
   |    ---------- required by a bound in this function
9  | where
10 |     Thing: HasMessage<M>,
   |            ^^^^^^^^^^^^^ required by this bound in `message_fn`
help: consider borrowing here
   |
5  |     message_fn(&Message1);
   |                +

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` (bin "playground") due to 1 previous error

Deleting the Message2 also results in a reasonable error

Code and error
// #[derive(Clone)] // <- uncomment this to fix it
struct Thing;

fn main() {
    message_fn(Message1);
}

fn message_fn<M>(_: M)
where
    Thing: HasMessage<M>,
{
    unimplemented!()
}

trait HasMessage<T> {}

struct Message1;
impl<M: Clone> HasMessage<Message1> for M {}
   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `Thing: HasMessage<_>` is not satisfied
  --> src/main.rs:5:16
   |
5  |     message_fn(Message1);
   |     ---------- ^^^^^^^^ the trait `HasMessage<_>` is not implemented for `Thing`
   |     |
   |     required by a bound introduced by this call
   |
note: required for `Thing` to implement `HasMessage<Message1>`
  --> src/main.rs:18:16
   |
18 | impl<M: Clone> HasMessage<Message1> for M {}
   |         -----  ^^^^^^^^^^^^^^^^^^^^     ^
   |         |
   |         unsatisfied trait bound introduced here
note: required by a bound in `message_fn`
  --> src/main.rs:10:12
   |
8  | fn message_fn<M>(_: M)
   |    ---------- required by a bound in this function
9  | where
10 |     Thing: HasMessage<M>,
   |            ^^^^^^^^^^^^^ required by this bound in `message_fn`
help: consider borrowing here
   |
5  |     message_fn(&Message1);
   |                +

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` (bin "playground") due to 1 previous error
Rust Version
Playground's nightly rust (1.81.0-nightly (2024-06-17 59e2c01c2217a0154622))
Anything else?

This code is reduced from real code found by @tqwewe

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the example in the Playground's src/main.rs, first with Message2 present and then with it removed or with Message3 added. Compare the diagnostics and trace the compiler's trait-resolution and error-reporting entry points; done means the original case explains the unsatisfied Clone bound without incorrectly reporting Message2 as the expected type.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.