Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

help text for Send trait bound mismatch is misleading #69983

Closed
davepacheco opened this issue Mar 13, 2020 · 0 comments · Fixed by #70009
Closed

help text for Send trait bound mismatch is misleading #69983

davepacheco opened this issue Mar 13, 2020 · 0 comments · Fixed by #70009
Assignees
Labels
A-diagnostics Area: Messages for errors, warnings, and lints D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. P-medium Medium priority regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@davepacheco
Copy link

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.

@estebank estebank added A-diagnostics Area: Messages for errors, warnings, and lints D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 13, 2020
@estebank estebank self-assigned this Mar 13, 2020
@spastorino spastorino added the P-medium Medium priority label Mar 18, 2020
Centril added a commit to Centril/rust that referenced this issue Mar 27, 2020
Tweak `suggest_constraining_type_param`

Some of the bound restriction structured suggestions were incorrect while others had subpar output.

The only issue left is a suggestion for an already present bound when dealing with `const`s that should be handled independently.

Fix rust-lang#69983.
@bors bors closed this as completed in 4911572 Mar 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. P-medium Medium priority regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants