Skip to content

Async/Await: Confusing error message when using non-Send type in async fn #65667

Closed
@dbrgn

Description

@dbrgn

With this Cargo.toml:

[package]
name = "errmsg"
version = "0.1.0"
edition = "2018"

[dependencies]
futures-preview = { version = "0.3.0-alpha.19", features = ["async-await"] }
tokio = "0.2.0-alpha.6"

...and this main.rs:

use std::rc::Rc;
use std::time::Duration;

use tokio::timer::delay;

async fn wait() {
    let rc = Rc::new(0);
    println!("Before sleep");
    delay(tokio::clock::now() + Duration::from_millis(500)).await;
    println!("After sleep");
}

#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
    println!("Start");
    tokio::spawn(wait());
    println!("End");
    Ok(())
}

...I get this error message:

   Compiling errmsg v0.1.0 (/tmp/errmsg)
error[E0277]: `std::rc::Rc<i32>` cannot be sent between threads safely
   --> src/main.rs:16:5
    |
16  |     tokio::spawn(wait());
    |     ^^^^^^^^^^^^ `std::rc::Rc<i32>` cannot be sent between threads safely
    |
   ::: /home/danilo/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.0-alpha.6/src/executor.rs:100:40
    |
100 |     F: Future<Output = ()> + 'static + Send,
    |                                        ---- required by this bound in `tokio::executor::spawn`
    |
    = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<i32>`
    = note: required because it appears within the type `{std::rc::Rc<i32>, fn(std::time::Instant) -> tokio_timer::delay::Delay {tokio_timer::delay}, fn() -> std::time::Instant {tokio_timer::clock::now}, std::time::Instant, fn(u64) -> std::time::Duration {std::time::Duration::from_millis}, u64, std::time::Duration, tokio_timer::delay::Delay, ()}`
    = note: required because it appears within the type `[static generator@src/main.rs:6:17: 11:2 {std::rc::Rc<i32>, fn(std::time::Instant) -> tokio_timer::delay::Delay {tokio_timer::delay}, fn() -> std::time::Instant {tokio_timer::clock::now}, std::time::Instant, fn(u64) -> std::time::Duration {std::time::Duration::from_millis}, u64, std::time::Duration, tokio_timer::delay::Delay, ()}]`
    = note: required because it appears within the type `std::future::GenFuture<[static generator@src/main.rs:6:17: 11:2 {std::rc::Rc<i32>, fn(std::time::Instant) -> tokio_timer::delay::Delay {tokio_timer::delay}, fn() -> std::time::Instant {tokio_timer::clock::now}, std::time::Instant, fn(u64) -> std::time::Duration {std::time::Duration::from_millis}, u64, std::time::Duration, tokio_timer::delay::Delay, ()}]>`
    = note: required because it appears within the type `impl std::future::Future`
    = note: required because it appears within the type `impl std::future::Future`

If I comment out the unused rc assignment, then everything works fine.

If comment out the delay(..).await statement, it works too!

If I put the rc assignment in a block, it compiles as well (because the rc is dropped by the time await is called).

From what I know about the implementation of async-await, I think this is because a state machine is created that keeps the local variables across multiple await-points, right? In any case, the error message is quite confusing, especially when the await call and the non-Send type are not related at all.

It seems that we're back at a pre-NLL situation with the borrow checker in async functions.

In summary, two issues:

  • The error message is quite confusing and not all too helpful, expecially if the user doesn't know anything about the internal implementation of async-await
  • The rc could be dropped before the await call, which would resolve this issue

Metadata

Metadata

Assignees

Labels

A-async-awaitArea: Async & AwaitA-diagnosticsArea: Messages for errors, warnings, and lintsAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.D-confusingDiagnostics: Confusing error or lint that should be reworked.T-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