Auto merge of #118420 - compiler-errors:async-gen, r=eholk

Introduce support for `async gen` blocks

I'm delighted to demonstrate that `async gen` block are not very difficult to support. They're simply coroutines that yield `Poll<Option<T>>` and return `()`.

**This PR is WIP and in draft mode for now** -- I'm mostly putting it up to show folks that it's possible. This PR needs a lang-team experiment associated with it or possible an RFC, since I don't think it falls under the jurisdiction of the `gen` RFC that was recently authored by oli (https://github.com/rust-lang/rfcs/pull/3513, https://github.com/rust-lang/rust/issues/117078).

### Technical note on the pre-generator-transform yield type:

The reason that the underlying coroutines yield `Poll<Option<T>>` and not `Poll<T>` (which would make more sense, IMO, for the pre-transformed coroutine), is because the `TransformVisitor` that is used to turn coroutines into built-in state machine functions would have to destructure and reconstruct the latter into the former, which requires at least inserting a new basic block (for a `switchInt` terminator, to match on the `Poll` discriminant).

This does mean that the desugaring (at the `rustc_ast_lowering` level) of `async gen` blocks is a bit more involved. However, since we already need to intercept both `.await` and `yield` operators, I don't consider it much of a technical burden.

r? `@ghost`
This commit is contained in:
bors
2023-12-08 19:13:57 +00:00
61 changed files with 1120 additions and 357 deletions

View File

@@ -916,8 +916,10 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
&sig.decl.output,
);
if let Some((coro_node_id, _)) =
sig.header.coro_kind.map(|coro_kind| coro_kind.return_id())
if let Some((coro_node_id, _)) = sig
.header
.coroutine_kind
.map(|coroutine_kind| coroutine_kind.return_id())
{
this.record_lifetime_params_for_impl_trait(coro_node_id);
}
@@ -942,8 +944,10 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
this.visit_generics(generics);
let declaration = &sig.decl;
let coro_node_id =
sig.header.coro_kind.map(|coro_kind| coro_kind.return_id());
let coro_node_id = sig
.header
.coroutine_kind
.map(|coroutine_kind| coroutine_kind.return_id());
this.with_lifetime_rib(
LifetimeRibKind::AnonymousCreateParameter {
@@ -4294,7 +4298,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
//
// Similarly, `gen |x| ...` gets desugared to `|x| gen {...}`, so we handle that too.
ExprKind::Closure(box ast::Closure {
coro_kind: Some(_),
coroutine_kind: Some(_),
ref fn_decl,
ref body,
..