Skip to content

help text for Send trait bound mismatch is misleading #69983

Closed
@davepacheco

Description

@davepacheco

This is a small issue but it cost me a fair bit of time and I thought an improvement here could help other new users.

Summary: when a caller tries to invoke a function with a trait bound that includes Send, but the caller's value is not Send, the error message says:

"error[E0277]: T cannot be sent between threads safely"

The problem here isn't (necessarily) that T cannot be sent between threads safely, but more precisely that the function expected T: Send and got plain T.

It might not be obvious how this can be so misleading, but as a relatively new user, I thought Rust was telling me that something in my code was trying to send a value between threads and additionally that the value actually couldn't be sent between threads safely. Often times neither of those was the case. You can easily generate this error with single-threaded code and concrete types that all implement Send. In my case, often I'd forgotten to put Send on a trait bounds of the caller, or I'd erroneously put Send on a trait bound of the callee. Really, this error is just a simple trait bound mismatch. Just from my experience, it looks like this message is special-cased for Send in order to provide more useful information for someone who might not be familiar with Send -- which is great. I think that information probably belongs in a "note" though, and the error should be precise about what actually happened instead of inferring too much (incorrectly, in some cases).

For trait bound mismatches involving types other than Send, the message is more precise:

use std::fmt::Debug;

trait TheTrait: Debug  {}
trait OtherTrait: Debug {}

#[derive(Debug)]
struct TheStruct {}
impl TheTrait for TheStruct {}

fn func1<T: TheTrait>(t: T)
{
    func2(t);
}

fn func2<T: OtherTrait>(t: T)
{
    eprintln!("{:?}", t);
}

fn main()
{
    let instance = TheStruct {};
    func1(instance);
}

Here's that example in the playground. The error message is:

error[E0277]: the trait bound `T: OtherTrait` is not satisfied
  --> src/main.rs:12:11
   |
10 | fn func1<T: TheTrait>(t: T)
   |          -- help: consider further restricting this bound: `T: OtherTrait +`
11 | {
12 |     func2(t);
   |           ^ the trait `OtherTrait` is not implemented for `T`
...
15 | fn func2<T: OtherTrait>(t: T)
   |    -----    ---------- required by this bound in `func2`

which is pretty clear and precise about the problem. Here's a similar example where the trait bound is Send:

use std::fmt::Debug;

trait TheTrait: Debug  {}

#[derive(Debug)]
struct TheStruct {}
impl TheTrait for TheStruct {}

fn func1<T: TheTrait>(t: T)
{
    func2(t);
}

fn func2<T: TheTrait + Send>(t: T)
{
    eprintln!("{:?}", t);
}

fn main()
{
    let instance = TheStruct {};
    func1(instance);
}

Here's that one on the playground.

Now the error message is:

error[E0277]: `T` cannot be sent between threads safely
  --> src/main.rs:11:11
   |
9  | fn func1<T: TheTrait>(t: T)
   |          -- help: consider further restricting this bound: `T: std::marker::Send +`
10 | {
11 |     func2(t);
   |           ^ `T` cannot be sent between threads safely
...
14 | fn func2<T: TheTrait + Send>(t: T)
   |    -----               ---- required by this bound in `func2`
   |
   = help: the trait `std::marker::Send` is not implemented for `T`

This is the same error code (E0277) and the "help" text is right but the summary message isn't.

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsD-invalid-suggestionDiagnostics: A structured suggestion resulting in incorrect code.P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-betaPerformance or correctness regression from stable to beta.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions