Description
We need to spec what generators are operationally. One option is to simply include the current generator lowering that rustc does in the spec. This has a number of downsides though, the biggest one being that it significantly inhibits optimizations. Specifically, for an async block like this:
async {
let x = 5_u64;
something.await;
dbg!(x);
}
We would like to justify two optimizations:
- Const propagating the
5
into thedbg!
invocation. - The
Future
that results from this async block having size less thansize_of::<u64>()
.
If our spec simply says that async blocks are subjected to the standard generator lowering, neither of these optimizations is correct. The &mut Future
that the caller of poll
has when the .await
point is hit might be used to modify x
, so we cannot const-prop, and x
is clearly alive across an await point, and so we must allocate space for it in the future.
Specifically, we are looking to prove two theorems:
- An optimization can soundly treat a
_ret = yield(_arg) [resume => bbA, drop => bbB]
as a_ret = call UNKNOWN_FN(_arg) [return => bbA, unwind => bbB]
. HereUNKNOWN_FN
is some unknown function that is unique to this yield point. - The generator lowering pass in MIR today is sound.
cc @tmandry and @saethlin with whom I talked about this issue at some length during rustconf