Repository navigation
Dropped variables still included in generator type #57478
Copy link
Copy link
Closed
Labels
A-async-awaitArea: Async & AwaitArea: Async & AwaitA-coroutinesArea: CoroutinesArea: CoroutinesA-type-systemArea: Type systemArea: Type systemAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.Async-await issues that have been triaged during a working group meeting.C-enhancementCategory: An issue proposing an enhancement or a PR with one.Category: An issue proposing an enhancement or a PR with one.P-lowLow priorityLow priorityT-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.T-langRelevant to the language teamRelevant to the language team
Description
struct Foo;
impl !Send for Foo {}
let _: impl Send = || {
let guard = Foo;
drop(guard);
yield;
};(full playground) fails with
error[E0277]: `Foo` cannot be sent between threads safely
--> src/main.rs:14:12
|
14 | let _: impl Send = || {
| ^^^^^^^^^ `Foo` cannot be sent between threads safely
|
= help: within `[generator@src/main.rs:14:24: 18:6 {Foo, ()}]`, the trait `std::marker::Send` is not implemented for `Foo`
= note: required because it appears within the type `{Foo, ()}`
= note: required because it appears within the type `[generator@src/main.rs:14:24: 18:6 {Foo, ()}]`
The guard should be dead and deallocated before the yield point so shouldn't appear in the generator type and affect the Sendness. Wrapping the guard in a new scope before the yield avoids this (included in the playground). First noticed in relation to async functions on u.rl.o.
Reacted by Lucien Greathouse, Kornel, Jon Gjengset, bb010g, Egor Ivkov, Jakub Beránek, Smitty, Paul Loyd, Sebastian Urban, Felipe S. S. Schneider and 4 more
Metadata
Metadata
Assignees
Labels
A-async-awaitArea: Async & AwaitArea: Async & AwaitA-coroutinesArea: CoroutinesArea: CoroutinesA-type-systemArea: Type systemArea: Type systemAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.Async-await issues that have been triaged during a working group meeting.C-enhancementCategory: An issue proposing an enhancement or a PR with one.Category: An issue proposing an enhancement or a PR with one.P-lowLow priorityLow priorityT-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.T-langRelevant to the language teamRelevant to the language team
Type
Projects
- StatusShow more project fieldsDone
Activity
Aaron1011 commentedon Jan 23, 2019
I'd like to work on this.
Aaron1011 commentedon Jan 23, 2019
This is going to be tricky.
The error is occurring due to the computed generator witness type including
Foo. This is done during initial type checking, before any MIR has been generated.Making this work would require type resolution to depend on the results of NLL. Specifically, the computed generator witness type would have to depend on which locals are computed to be live during mir-borrowck.
@Zoxc @nikomatsakis: Thoughts?
Zoxc commentedon Jan 26, 2019
My plan for this is just to generate MIR for just the generator during type checking and then do the analysis on MIR. Currently that isn't very feasible given the current compiler structure.
tmandry commentedon Jun 12, 2019
cc @rust-lang/lang, are we 100% sure we want to support this? The implication is there is going to be a "sharp edge" here when drops for certain locals move around relative to yield points (or vice versa).
It's also possible to work around it by turning your scope into a function call (possibly a closure that is immediately called).
Nemo157 commentedon Jun 12, 2019
You don't need a function call, just adding an actual scope around the variable that's dropped between yields is enough (this is included in the playground):
It makes sense to me why this is as it is and the solution could be just improved diagnostics telling users to add these extra scopes, it just seems like an unnecessary pain point for async functions.
Change how we compute yield_in_scope
Nemo157 commentedon Aug 21, 2019
After being reminded of this I realised this isn't really about "dropping" variables, it's about moving the variables out of the generator, any function that takes ownership should cause the variable to no longer be alive in the generator (this is the same thing since
dropis just a trivial function to move the variable out, but being explicit about it might help others like me that didn't instantly make the connection):oconnor663 commentedon Aug 21, 2019
Another twist on the same problem might be using something like
ManuallyDrop:52 remaining items
xmh0511 commentedon Mar 29, 2024
This issue has been fixed by #107421. See https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=d729e04078319d7a3ba796d917fa4de2
WaffleLapkin commentedon Mar 30, 2024
Closing as per the above comment.
zjp-CN commentedon Mar 7, 2025
As a reminder to tell people the problem is not fully solved:
although this issue is treated as closed, the compiler still doesn't treat the dropped variables to be dead.
Sendness for anasyncblock where a!Sendvalue is dropped before an.awaitpoint #128095 (comment)Sendness for anasyncblock where a!Sendvalue is dropped before an.awaitpoint #128095 (comment)Plan-Korrektur: Task 6s drop(conn) kompiliert auf diesem Toolchain nicht