Closed
Description
Rust 1.65 doesn't compile this code:
fn main() {
tokio::spawn(async move {
let non_send = get_non_send();
drop(non_send);
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
});
}
fn get_non_send() -> Box<dyn std::io::Read> {
unimplemented!()
}
It complains that the future is not Send
, reporting the following:
error: future cannot be sent between threads safely
--> src/main.rs:4:18
|
4 | tokio::spawn(async move {
| __________________^
5 | | let non_send = get_non_send();
6 | | drop(non_send);
7 | | tokio::time::sleep(std::time::Duration::from_secs(1)).await;
8 | | });
| |_____^ future created by async block is not `Send`
|
= help: the trait `Send` is not implemented for `dyn std::io::Read`
note: future is not `Send` as this value is used across an await
--> src/main.rs:7:62
|
5 | let non_send = get_non_send();
| -------- has type `Box<dyn std::io::Read>` which is not `Send`
6 | drop(non_send);
7 | tokio::time::sleep(std::time::Duration::from_secs(1)).await;
| ^^^^^^ await occurs here, with `non_send` maybe used later
8 | });
| - `non_send` is later dropped here
note: required by a bound in `tokio::spawn`
--> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.22.0/src/task/spawn.rs:163:21
|
163 | T: Future + Send + 'static,
| ^^^^ required by this bound in `tokio::spawn`
I would expect it to compile, since the offending non-Send value is unconditionally dropped before .await
.
If I change drop(non_send)
to a block that makes it go out of scope, then it compiles:
tokio::spawn(async move {
{
let non_send = get_non_send();
}
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
});
As shown, the first example can be trivially transformed to use a scope, but in other situations it might not be as easy. This report is inspired by a post on reddit that described this issue in a slightly more complex scenario.