-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Closed
Labels
A-async-awaitArea: Async & AwaitArea: Async & AwaitA-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsA-lifetimesArea: Lifetimes / regionsArea: Lifetimes / regionsAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.Async-await issues that have been triaged during a working group meeting.D-confusingDiagnostics: Confusing error or lint that should be reworked.Diagnostics: Confusing error or lint that should be reworked.D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.Diagnostics: Confusing error or lint; hard to understand for new users.E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.E-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Description
Consider the following code:
use std::sync::Arc;
use tokio::runtime::Runtime; // 0.3.1
async fn f() {
let room_ref = Arc::new(Vec::new());
let gameloop_handle = Runtime::new().unwrap().spawn(async {
game_loop(Arc::clone(&room_ref))
});
gameloop_handle.await;
}
fn game_loop(v: Arc<Vec<usize>>) {}
The error message has a helpful hint:
help: to force the async block to take ownership of `room_ref` (and any other referenced variables), use the `move` keyword
|
7 | let gameloop_handle = Runtime::new().unwrap().spawn(async move {
8 | game_loop(Arc::clone(&room_ref))
9 | });
But it doesn't explain very well why move
is necessary:
error[E0373]: async block may outlive the current function, but it borrows `room_ref`, which is owned by the current function
--> src/lib.rs:7:63
|
7 | let gameloop_handle = Runtime::new().unwrap().spawn(async {
| _______________________________________________________________^
8 | | game_loop(Arc::clone(&room_ref))
| | -------- `room_ref` is borrowed here
9 | | });
| |_____^ may outlive borrowed value `room_ref`
|
note: function requires argument type to outlive `'static`
--> src/lib.rs:7:57
|
7 | let gameloop_handle = Runtime::new().unwrap().spawn(async {
| _________________________________________________________^
8 | | game_loop(Arc::clone(&room_ref))
9 | | });
| |_____^
In particular, 'async block may outlive the current function' makes no sense without a very good mental model of async: the future is await
ed within the current function, so of course it can't outlive it. The thing to realize here is that even though it's written as one function, it's actually two: one executed before the yield point, and one after, and the stack space for the first function goes away when you call await
.
It would be nice to instead say something like
note: borrows cannot be held across a yield point, because the stack space of the current function is not preserved
help: see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor for more information
estebank
Metadata
Metadata
Assignees
Labels
A-async-awaitArea: Async & AwaitArea: Async & AwaitA-diagnosticsArea: Messages for errors, warnings, and lintsArea: Messages for errors, warnings, and lintsA-lifetimesArea: Lifetimes / regionsArea: Lifetimes / regionsAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.Async-await issues that have been triaged during a working group meeting.D-confusingDiagnostics: Confusing error or lint that should be reworked.Diagnostics: Confusing error or lint that should be reworked.D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.Diagnostics: Confusing error or lint; hard to understand for new users.E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.E-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.