Skip to content

Commit

Permalink
Auto merge of #118420 - compiler-errors:async-gen, r=eholk
Browse files Browse the repository at this point in the history
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 (rust-lang/rfcs#3513, rust-lang/rust#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`
  • Loading branch information
bors committed Dec 8, 2023
2 parents 77bb46d + 3ffacf7 commit 9c809ce
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 14 deletions.
22 changes: 16 additions & 6 deletions src/closures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub(crate) fn rewrite_closure(
binder: &ast::ClosureBinder,
constness: ast::Const,
capture: ast::CaptureBy,
coro_kind: &Option<ast::CoroutineKind>,
coroutine_kind: &Option<ast::CoroutineKind>,
movability: ast::Movability,
fn_decl: &ast::FnDecl,
body: &ast::Expr,
Expand All @@ -40,7 +40,16 @@ pub(crate) fn rewrite_closure(
debug!("rewrite_closure {:?}", body);

let (prefix, extra_offset) = rewrite_closure_fn_decl(
binder, constness, capture, coro_kind, movability, fn_decl, body, span, context, shape,
binder,
constness,
capture,
coroutine_kind,
movability,
fn_decl,
body,
span,
context,
shape,
)?;
// 1 = space between `|...|` and body.
let body_shape = shape.offset_left(extra_offset)?;
Expand Down Expand Up @@ -233,7 +242,7 @@ fn rewrite_closure_fn_decl(
binder: &ast::ClosureBinder,
constness: ast::Const,
capture: ast::CaptureBy,
coro_kind: &Option<ast::CoroutineKind>,
coroutine_kind: &Option<ast::CoroutineKind>,
movability: ast::Movability,
fn_decl: &ast::FnDecl,
body: &ast::Expr,
Expand Down Expand Up @@ -263,9 +272,10 @@ fn rewrite_closure_fn_decl(
} else {
""
};
let coro = match coro_kind {
let coro = match coroutine_kind {
Some(ast::CoroutineKind::Async { .. }) => "async ",
Some(ast::CoroutineKind::Gen { .. }) => "gen ",
Some(ast::CoroutineKind::AsyncGen { .. }) => "async gen ",
None => "",
};
let mover = if matches!(capture, ast::CaptureBy::Value { .. }) {
Expand Down Expand Up @@ -343,7 +353,7 @@ pub(crate) fn rewrite_last_closure(
ref binder,
constness,
capture_clause,
ref coro_kind,
ref coroutine_kind,
movability,
ref fn_decl,
ref body,
Expand All @@ -364,7 +374,7 @@ pub(crate) fn rewrite_last_closure(
binder,
constness,
capture_clause,
coro_kind,
coroutine_kind,
movability,
fn_decl,
body,
Expand Down
2 changes: 1 addition & 1 deletion src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ pub(crate) fn format_expr(
&cl.binder,
cl.constness,
cl.capture_clause,
&cl.coro_kind,
&cl.coroutine_kind,
cl.movability,
&cl.fn_decl,
&cl.body,
Expand Down
10 changes: 5 additions & 5 deletions src/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ pub(crate) struct FnSig<'a> {
decl: &'a ast::FnDecl,
generics: &'a ast::Generics,
ext: ast::Extern,
coro_kind: Cow<'a, Option<ast::CoroutineKind>>,
coroutine_kind: Cow<'a, Option<ast::CoroutineKind>>,
constness: ast::Const,
defaultness: ast::Defaultness,
unsafety: ast::Unsafe,
Expand All @@ -302,7 +302,7 @@ impl<'a> FnSig<'a> {
) -> FnSig<'a> {
FnSig {
unsafety: method_sig.header.unsafety,
coro_kind: Cow::Borrowed(&method_sig.header.coro_kind),
coroutine_kind: Cow::Borrowed(&method_sig.header.coroutine_kind),
constness: method_sig.header.constness,
defaultness: ast::Defaultness::Final,
ext: method_sig.header.ext,
Expand All @@ -328,7 +328,7 @@ impl<'a> FnSig<'a> {
generics,
ext: fn_sig.header.ext,
constness: fn_sig.header.constness,
coro_kind: Cow::Borrowed(&fn_sig.header.coro_kind),
coroutine_kind: Cow::Borrowed(&fn_sig.header.coroutine_kind),
defaultness,
unsafety: fn_sig.header.unsafety,
visibility: vis,
Expand All @@ -343,8 +343,8 @@ impl<'a> FnSig<'a> {
result.push_str(&*format_visibility(context, self.visibility));
result.push_str(format_defaultness(self.defaultness));
result.push_str(format_constness(self.constness));
self.coro_kind
.map(|coro_kind| result.push_str(format_coro(&coro_kind)));
self.coroutine_kind
.map(|coroutine_kind| result.push_str(format_coro(&coroutine_kind)));
result.push_str(format_unsafety(self.unsafety));
result.push_str(&format_extern(
self.ext,
Expand Down
5 changes: 3 additions & 2 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,11 @@ pub(crate) fn format_visibility(
}

#[inline]
pub(crate) fn format_coro(coro_kind: &ast::CoroutineKind) -> &'static str {
match coro_kind {
pub(crate) fn format_coro(coroutine_kind: &ast::CoroutineKind) -> &'static str {
match coroutine_kind {
ast::CoroutineKind::Async { .. } => "async ",
ast::CoroutineKind::Gen { .. } => "gen ",
ast::CoroutineKind::AsyncGen { .. } => "async gen ",
}
}

Expand Down

0 comments on commit 9c809ce

Please sign in to comment.