Description
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.