Expand description
This is the implementation of the pass which transforms coroutines into state machines.
MIR generation for coroutines creates a function which has a self argument which passes by value. This argument is effectively a coroutine type which only contains upvars and is only used for this argument inside the MIR for the coroutine. It is passed by value to enable upvars to be moved out of it. Drop elaboration runs on that MIR before this pass and creates drop flags for MIR locals. It will also drop the coroutine argument (which only consists of upvars) if any of the upvars are moved out of. This pass elaborates the drops of upvars / coroutine argument in the case that none of the upvars were moved out of. This is because we cannot have any drops of this coroutine in the MIR, since it is used to create the drop glue for the coroutine. We’d get infinite recursion otherwise.
This pass creates the implementation for either the Coroutine::resume
or Future::poll
function and the drop shim for the coroutine based on the MIR input.
It converts the coroutine argument from Self to &mut Self adding derefs in the MIR as needed.
It computes the final layout of the coroutine struct which looks like this:
First upvars are stored
It is followed by the coroutine state field.
Then finally the MIR locals which are live across a suspension point are stored.
ignore (illustrative) struct Coroutine { upvars..., state: u32, mir_locals..., }
This pass computes the meaning of the state field and the MIR locals which are live
across a suspension point. There are however three hardcoded coroutine states:
0 - Coroutine have not been resumed yet
1 - Coroutine has returned / is completed
2 - Coroutine has been poisoned
It also rewrites return x
and yield y
as setting a new coroutine state and returning
CoroutineState::Complete(x)
and CoroutineState::Yielded(y)
,
or Poll::Ready(x)
and Poll::Pending
respectively.
MIR locals which are live across a suspension point are moved to the coroutine struct
with references to them being updated with references to the coroutine struct.
The pass creates two functions which have a switch on the coroutine state giving the action to take.
One of them is the implementation of Coroutine::resume
/ Future::poll
.
For coroutines with state 0 (unresumed) it starts the execution of the coroutine.
For coroutines with state 1 (returned) and state 2 (poisoned) it panics.
Otherwise it continues the execution from the last suspension point.
The other function is the drop glue for the coroutine. For coroutines with state 0 (unresumed) it drops the upvars of the coroutine. For coroutines with state 1 (returned) and state 2 (poisoned) it does nothing. Otherwise it drops all the values in scope at the last suspension point.
Modules§
- by_
move_ 🔒body - This pass constructs a second coroutine body sufficient for return from
FnOnce
/AsyncFnOnce
implementations for coroutine-closures (e.g. async closures).
Structs§
- Coroutine
Saved 🔒Locals - The set of
Local
s that must be saved across yield points. - Ensure
Coroutine 🔒Field Assignments Never Alias - Looks for any assignments between locals (e.g.,
_4 = _5
) that will both be converted to fields in the coroutine state machine but whose storage is not marked as conflicting - Liveness
Info 🔒 - Rename
Local 🔒Visitor - Self
ArgVisitor 🔒 - State
Transform 🔒 - Storage
Conflict 🔒Visitor - Suspend
Check 🔒Data - Suspension
Point 🔒 - A
yield
point in the coroutine. - Transform
Visitor 🔒
Enums§
- Operation 🔒
- An operation that can be performed on a coroutine.
Constants§
- SELF_
ARG 🔒
Functions§
- can_
return 🔒 - can_
unwind 🔒 - check_
field_ 🔒tys_ sized - check_
must_ 🔒not_ suspend_ def - check_
must_ 🔒not_ suspend_ ty - check_
suspend_ 🔒tys - compute_
layout 🔒 - compute_
storage_ 🔒conflicts - For every saved local, looks for which locals are StorageLive at the same
time. Generates a bitset for every local of all the other locals that may be
StorageLive simultaneously with that local. This is used in the layout
computation; see
CoroutineLayout
for more. - create_
cases 🔒 - create_
coroutine_ 🔒drop_ shim - create_
coroutine_ 🔒resume_ function - elaborate_
coroutine_ 🔒drops - eliminate_
get_ 🔒context_ call - insert_
clean_ 🔒drop - insert_
panic_ 🔒block - insert_
switch 🔒 - Replaces the entry point of
body
with a block that switches on the coroutine discriminant and dispatches to blocks according tocases
. - insert_
term_ 🔒block - locals_
live_ 🔒across_ suspend_ points - Computes which locals have to be stored in the state-machine for the given coroutine.
- make_
aggregate_ 🔒adt - make_
coroutine_ 🔒state_ argument_ indirect - make_
coroutine_ 🔒state_ argument_ pinned - mir_
coroutine_ 🔒witnesses - replace_
base 🔒 - replace_
local 🔒 - Allocates a new local and replaces all references of
local
with it. Returns the new local. - replace_
resume_ 🔒ty_ local - transform_
async_ 🔒context - Transforms the
body
of the coroutine applying the following transforms: - transform_
gen_ 🔒context - Transforms the
body
of the coroutine applying the following transform: