Closed
Description
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 theawait
call, which would resolve this issue