Skip to content

Commit

Permalink
Auto merge of rust-lang#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#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 f39d18b + 62f7337 commit 0252580
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 6 deletions.
2 changes: 1 addition & 1 deletion clippy_lints/src/doc/needless_doctest_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub fn check(
if !ignore {
get_test_spans(&item, &mut test_attr_spans);
}
let is_async = matches!(sig.header.coro_kind, Some(CoroutineKind::Async { .. }));
let is_async = matches!(sig.header.coroutine_kind, Some(CoroutineKind::Async { .. }));
let returns_nothing = match &sig.decl.output {
FnRetTy::Default(..) => true,
FnRetTy::Ty(ty) if ty.kind.is_unit() => true,
Expand Down
11 changes: 6 additions & 5 deletions clippy_utils/src/ast_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
Closure(box ast::Closure {
binder: lb,
capture_clause: lc,
coro_kind: la,
coroutine_kind: la,
movability: lm,
fn_decl: lf,
body: le,
Expand All @@ -197,7 +197,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
Closure(box ast::Closure {
binder: rb,
capture_clause: rc,
coro_kind: ra,
coroutine_kind: ra,
movability: rm,
fn_decl: rf,
body: re,
Expand Down Expand Up @@ -563,18 +563,19 @@ pub fn eq_fn_sig(l: &FnSig, r: &FnSig) -> bool {
eq_fn_decl(&l.decl, &r.decl) && eq_fn_header(&l.header, &r.header)
}

fn eq_opt_coro_kind(l: Option<CoroutineKind>, r: Option<CoroutineKind>) -> bool {
fn eq_opt_coroutine_kind(l: Option<CoroutineKind>, r: Option<CoroutineKind>) -> bool {
match (l, r) {
(Some(CoroutineKind::Async { .. }), Some(CoroutineKind::Async { .. }))
| (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. })) => true,
| (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. }))
| (Some(CoroutineKind::AsyncGen { .. }), Some(CoroutineKind::AsyncGen { .. })) => true,
(None, None) => true,
_ => false,
}
}

pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
matches!(l.unsafety, Unsafe::No) == matches!(r.unsafety, Unsafe::No)
&& eq_opt_coro_kind(l.coro_kind, r.coro_kind)
&& eq_opt_coroutine_kind(l.coroutine_kind, r.coroutine_kind)
&& matches!(l.constness, Const::No) == matches!(r.constness, Const::No)
&& eq_ext(&l.ext, &r.ext)
}
Expand Down

0 comments on commit 0252580

Please sign in to comment.