Skip to content

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

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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