Skip to content

Commit b072357

Browse files
committed
Auto merge of rust-lang#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 (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`
2 parents 5ea6256 + a8c7761 commit b072357

File tree

61 files changed

+1118
-355
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1118
-355
lines changed

compiler/rustc_ast/src/ast.rs

+20-8
Original file line numberDiff line numberDiff line change
@@ -1311,7 +1311,7 @@ pub struct Closure {
13111311
pub binder: ClosureBinder,
13121312
pub capture_clause: CaptureBy,
13131313
pub constness: Const,
1314-
pub coro_kind: Option<CoroutineKind>,
1314+
pub coroutine_kind: Option<CoroutineKind>,
13151315
pub movability: Movability,
13161316
pub fn_decl: P<FnDecl>,
13171317
pub body: P<Expr>,
@@ -1516,6 +1516,7 @@ pub enum ExprKind {
15161516
pub enum GenBlockKind {
15171517
Async,
15181518
Gen,
1519+
AsyncGen,
15191520
}
15201521

15211522
impl fmt::Display for GenBlockKind {
@@ -1529,6 +1530,7 @@ impl GenBlockKind {
15291530
match self {
15301531
GenBlockKind::Async => "async",
15311532
GenBlockKind::Gen => "gen",
1533+
GenBlockKind::AsyncGen => "async gen",
15321534
}
15331535
}
15341536
}
@@ -2413,10 +2415,12 @@ pub enum Unsafe {
24132415
/// Iterator`.
24142416
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
24152417
pub enum CoroutineKind {
2416-
/// `async`, which evaluates to `impl Future`
2418+
/// `async`, which returns an `impl Future`
24172419
Async { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
2418-
/// `gen`, which evaluates to `impl Iterator`
2420+
/// `gen`, which returns an `impl Iterator`
24192421
Gen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
2422+
/// `async gen`, which returns an `impl AsyncIterator`
2423+
AsyncGen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
24202424
}
24212425

24222426
impl CoroutineKind {
@@ -2433,7 +2437,10 @@ impl CoroutineKind {
24332437
pub fn return_id(self) -> (NodeId, Span) {
24342438
match self {
24352439
CoroutineKind::Async { return_impl_trait_id, span, .. }
2436-
| CoroutineKind::Gen { return_impl_trait_id, span, .. } => (return_impl_trait_id, span),
2440+
| CoroutineKind::Gen { return_impl_trait_id, span, .. }
2441+
| CoroutineKind::AsyncGen { return_impl_trait_id, span, .. } => {
2442+
(return_impl_trait_id, span)
2443+
}
24372444
}
24382445
}
24392446
}
@@ -2838,7 +2845,7 @@ pub struct FnHeader {
28382845
/// The `unsafe` keyword, if any
28392846
pub unsafety: Unsafe,
28402847
/// Whether this is `async`, `gen`, or nothing.
2841-
pub coro_kind: Option<CoroutineKind>,
2848+
pub coroutine_kind: Option<CoroutineKind>,
28422849
/// The `const` keyword, if any
28432850
pub constness: Const,
28442851
/// The `extern` keyword and corresponding ABI string, if any
@@ -2848,17 +2855,22 @@ pub struct FnHeader {
28482855
impl FnHeader {
28492856
/// Does this function header have any qualifiers or is it empty?
28502857
pub fn has_qualifiers(&self) -> bool {
2851-
let Self { unsafety, coro_kind, constness, ext } = self;
2858+
let Self { unsafety, coroutine_kind, constness, ext } = self;
28522859
matches!(unsafety, Unsafe::Yes(_))
2853-
|| coro_kind.is_some()
2860+
|| coroutine_kind.is_some()
28542861
|| matches!(constness, Const::Yes(_))
28552862
|| !matches!(ext, Extern::None)
28562863
}
28572864
}
28582865

28592866
impl Default for FnHeader {
28602867
fn default() -> FnHeader {
2861-
FnHeader { unsafety: Unsafe::No, coro_kind: None, constness: Const::No, ext: Extern::None }
2868+
FnHeader {
2869+
unsafety: Unsafe::No,
2870+
coroutine_kind: None,
2871+
constness: Const::No,
2872+
ext: Extern::None,
2873+
}
28622874
}
28632875
}
28642876

compiler/rustc_ast/src/mut_visit.rs

+10-9
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ pub trait MutVisitor: Sized {
121121
noop_visit_fn_decl(d, self);
122122
}
123123

124-
fn visit_coro_kind(&mut self, a: &mut CoroutineKind) {
125-
noop_visit_coro_kind(a, self);
124+
fn visit_coroutine_kind(&mut self, a: &mut CoroutineKind) {
125+
noop_visit_coroutine_kind(a, self);
126126
}
127127

128128
fn visit_closure_binder(&mut self, b: &mut ClosureBinder) {
@@ -871,10 +871,11 @@ pub fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis:
871871
}
872872
}
873873

874-
pub fn noop_visit_coro_kind<T: MutVisitor>(coro_kind: &mut CoroutineKind, vis: &mut T) {
875-
match coro_kind {
874+
pub fn noop_visit_coroutine_kind<T: MutVisitor>(coroutine_kind: &mut CoroutineKind, vis: &mut T) {
875+
match coroutine_kind {
876876
CoroutineKind::Async { span, closure_id, return_impl_trait_id }
877-
| CoroutineKind::Gen { span, closure_id, return_impl_trait_id } => {
877+
| CoroutineKind::Gen { span, closure_id, return_impl_trait_id }
878+
| CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id } => {
878879
vis.visit_span(span);
879880
vis.visit_id(closure_id);
880881
vis.visit_id(return_impl_trait_id);
@@ -1171,9 +1172,9 @@ fn visit_const_item<T: MutVisitor>(
11711172
}
11721173

11731174
pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
1174-
let FnHeader { unsafety, coro_kind, constness, ext: _ } = header;
1175+
let FnHeader { unsafety, coroutine_kind, constness, ext: _ } = header;
11751176
visit_constness(constness, vis);
1176-
coro_kind.as_mut().map(|coro_kind| vis.visit_coro_kind(coro_kind));
1177+
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
11771178
visit_unsafety(unsafety, vis);
11781179
}
11791180

@@ -1407,7 +1408,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
14071408
binder,
14081409
capture_clause,
14091410
constness,
1410-
coro_kind,
1411+
coroutine_kind,
14111412
movability: _,
14121413
fn_decl,
14131414
body,
@@ -1416,7 +1417,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
14161417
}) => {
14171418
vis.visit_closure_binder(binder);
14181419
visit_constness(constness, vis);
1419-
coro_kind.as_mut().map(|coro_kind| vis.visit_coro_kind(coro_kind));
1420+
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
14201421
vis.visit_capture_by(capture_clause);
14211422
vis.visit_fn_decl(fn_decl);
14221423
vis.visit_expr(body);

compiler/rustc_ast/src/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -861,7 +861,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
861861
ExprKind::Closure(box Closure {
862862
binder,
863863
capture_clause,
864-
coro_kind: _,
864+
coroutine_kind: _,
865865
constness: _,
866866
movability: _,
867867
fn_decl,

0 commit comments

Comments
 (0)