Skip to content

Commit a208bae

Browse files
Support async gen fn
1 parent 2806c2d commit a208bae

File tree

16 files changed

+115
-104
lines changed

16 files changed

+115
-104
lines changed

compiler/rustc_ast/src/ast.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -2415,10 +2415,12 @@ pub enum Unsafe {
24152415
/// Iterator`.
24162416
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
24172417
pub enum CoroutineKind {
2418-
/// `async`, which evaluates to `impl Future`
2418+
/// `async`, which returns an `impl Future`
24192419
Async { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
2420-
/// `gen`, which evaluates to `impl Iterator`
2420+
/// `gen`, which returns an `impl Iterator`
24212421
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 },
24222424
}
24232425

24242426
impl CoroutineKind {
@@ -2435,7 +2437,10 @@ impl CoroutineKind {
24352437
pub fn return_id(self) -> (NodeId, Span) {
24362438
match self {
24372439
CoroutineKind::Async { return_impl_trait_id, span, .. }
2438-
| 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+
}
24392444
}
24402445
}
24412446
}

compiler/rustc_ast/src/mut_visit.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -874,7 +874,8 @@ pub fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis:
874874
pub fn noop_visit_coroutine_kind<T: MutVisitor>(coroutine_kind: &mut CoroutineKind, vis: &mut T) {
875875
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);

compiler/rustc_ast_lowering/src/expr.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_ast::*;
1313
use rustc_data_structures::stack::ensure_sufficient_stack;
1414
use rustc_hir as hir;
1515
use rustc_hir::def::{DefKind, Res};
16+
use rustc_middle::span_bug;
1617
use rustc_session::errors::report_lit_error;
1718
use rustc_span::source_map::{respan, Spanned};
1819
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -202,15 +203,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
202203
fn_decl_span,
203204
fn_arg_span,
204205
}) => match coroutine_kind {
205-
Some(
206-
CoroutineKind::Async { closure_id, .. }
207-
| CoroutineKind::Gen { closure_id, .. },
208-
) => self.lower_expr_async_closure(
206+
Some(coroutine_kind) => self.lower_expr_coroutine_closure(
209207
binder,
210208
*capture_clause,
211209
e.id,
212210
hir_id,
213-
*closure_id,
211+
*coroutine_kind,
214212
fn_decl,
215213
body,
216214
*fn_decl_span,
@@ -1098,18 +1096,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
10981096
(binder, params)
10991097
}
11001098

1101-
fn lower_expr_async_closure(
1099+
fn lower_expr_coroutine_closure(
11021100
&mut self,
11031101
binder: &ClosureBinder,
11041102
capture_clause: CaptureBy,
11051103
closure_id: NodeId,
11061104
closure_hir_id: hir::HirId,
1107-
inner_closure_id: NodeId,
1105+
coroutine_kind: CoroutineKind,
11081106
decl: &FnDecl,
11091107
body: &Expr,
11101108
fn_decl_span: Span,
11111109
fn_arg_span: Span,
11121110
) -> hir::ExprKind<'hir> {
1111+
let CoroutineKind::Async { closure_id: inner_closure_id, .. } = coroutine_kind else {
1112+
span_bug!(fn_decl_span, "`async gen` and `gen` closures are not supported, yet");
1113+
};
1114+
11131115
if let &ClosureBinder::For { span, .. } = binder {
11141116
self.tcx.sess.emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
11151117
}

compiler/rustc_ast_lowering/src/item.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -1035,11 +1035,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
10351035
let (Some(coroutine_kind), Some(body)) = (coroutine_kind, body) else {
10361036
return self.lower_fn_body_block(span, decl, body);
10371037
};
1038-
let closure_id = match coroutine_kind {
1039-
CoroutineKind::Async { closure_id, .. } | CoroutineKind::Gen { closure_id, .. } => {
1040-
closure_id
1041-
}
1042-
};
1038+
let (CoroutineKind::Async { closure_id, .. }
1039+
| CoroutineKind::Gen { closure_id, .. }
1040+
| CoroutineKind::AsyncGen { closure_id, .. }) = coroutine_kind;
10431041

10441042
self.lower_body(|this| {
10451043
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
@@ -1224,6 +1222,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
12241222
hir::CoroutineSource::Fn,
12251223
mkbody,
12261224
),
1225+
CoroutineKind::AsyncGen { .. } => this.make_async_gen_expr(
1226+
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
1227+
closure_id,
1228+
None,
1229+
body.span,
1230+
hir::CoroutineSource::Fn,
1231+
mkbody,
1232+
),
12271233
};
12281234

12291235
let hir_id = this.lower_node_id(closure_id);

compiler/rustc_ast_lowering/src/lib.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1904,7 +1904,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
19041904

19051905
let opaque_ty_node_id = match coro {
19061906
CoroutineKind::Async { return_impl_trait_id, .. }
1907-
| CoroutineKind::Gen { return_impl_trait_id, .. } => return_impl_trait_id,
1907+
| CoroutineKind::Gen { return_impl_trait_id, .. }
1908+
| CoroutineKind::AsyncGen { return_impl_trait_id, .. } => return_impl_trait_id,
19081909
};
19091910

19101911
let captured_lifetimes: Vec<_> = self
@@ -1960,8 +1961,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
19601961

19611962
// "<$assoc_ty_name = T>"
19621963
let (assoc_ty_name, trait_lang_item) = match coro {
1963-
CoroutineKind::Async { .. } => (hir::FN_OUTPUT_NAME, hir::LangItem::Future),
1964-
CoroutineKind::Gen { .. } => (hir::ITERATOR_ITEM_NAME, hir::LangItem::Iterator),
1964+
CoroutineKind::Async { .. } => (sym::Output, hir::LangItem::Future),
1965+
CoroutineKind::Gen { .. } => (sym::Item, hir::LangItem::Iterator),
1966+
CoroutineKind::AsyncGen { .. } => (sym::Item, hir::LangItem::AsyncIterator),
19651967
};
19661968

19671969
let future_args = self.arena.alloc(hir::GenericArgs {

compiler/rustc_ast_lowering/src/path.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
389389
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
390390
};
391391
let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
392-
let binding = self.assoc_ty_binding(hir::FN_OUTPUT_NAME, output_ty.span, output_ty);
392+
let binding = self.assoc_ty_binding(sym::Output, output_ty.span, output_ty);
393393
(
394394
GenericArgsCtor {
395395
args,

compiler/rustc_ast_pretty/src/pprust/state.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1498,6 +1498,10 @@ impl<'a> State<'a> {
14981498
ast::CoroutineKind::Async { .. } => {
14991499
self.word_nbsp("async");
15001500
}
1501+
ast::CoroutineKind::AsyncGen { .. } => {
1502+
self.word_nbsp("async");
1503+
self.word_nbsp("gen");
1504+
}
15011505
}
15021506
}
15031507

compiler/rustc_hir/src/hir.rs

-5
Original file line numberDiff line numberDiff line change
@@ -2255,11 +2255,6 @@ pub enum ImplItemKind<'hir> {
22552255
Type(&'hir Ty<'hir>),
22562256
}
22572257

2258-
/// The name of the associated type for `Fn` return types.
2259-
pub const FN_OUTPUT_NAME: Symbol = sym::Output;
2260-
/// The name of the associated type for `Iterator` item types.
2261-
pub const ITERATOR_ITEM_NAME: Symbol = sym::Item;
2262-
22632258
/// Bind a type to an associated type (i.e., `A = Foo`).
22642259
///
22652260
/// Bindings like `A: Debug` are represented as a special type `A =

compiler/rustc_parse/messages.ftl

-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or late
2323
parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
2424
.label = to use `async fn`, switch to Rust 2018 or later
2525
26-
parse_async_gen_fn = `async gen` functions are not supported
27-
2826
parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 2018 or later
2927
3028
parse_async_move_order_incorrect = the order of `move` and `async` is incorrect

compiler/rustc_parse/src/errors.rs

-7
Original file line numberDiff line numberDiff line change
@@ -562,13 +562,6 @@ pub(crate) struct GenFn {
562562
pub span: Span,
563563
}
564564

565-
#[derive(Diagnostic)]
566-
#[diag(parse_async_gen_fn)]
567-
pub(crate) struct AsyncGenFn {
568-
#[primary_span]
569-
pub span: Span,
570-
}
571-
572565
#[derive(Diagnostic)]
573566
#[diag(parse_comma_after_base_struct)]
574567
#[note]

compiler/rustc_parse/src/parser/expr.rs

+22-14
Original file line numberDiff line numberDiff line change
@@ -1442,21 +1442,21 @@ impl<'a> Parser<'a> {
14421442
} else if this.token.uninterpolated_span().at_least_rust_2018() {
14431443
// `Span:.at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
14441444
if this.check_keyword(kw::Async) {
1445-
if this.is_gen_block(kw::Async, 0) || this.is_gen_block(kw::Gen, 1) {
1445+
// FIXME(gen_blocks): Parse `gen async` and suggest swap
1446+
if this.is_gen_block(kw::Async, 0) {
14461447
// Check for `async {` and `async move {`,
14471448
// or `async gen {` and `async gen move {`.
14481449
this.parse_gen_block()
14491450
} else {
14501451
this.parse_expr_closure()
14511452
}
1452-
} else if this.eat_keyword(kw::Await) {
1453+
} else if this.token.uninterpolated_span().at_least_rust_2024()
1454+
&& (this.is_gen_block(kw::Gen, 0)
1455+
|| (this.check_keyword(kw::Async) && this.is_gen_block(kw::Gen, 1)))
1456+
{
1457+
this.parse_gen_block()
1458+
} else if this.eat_keyword_noexpect(kw::Await) {
14531459
this.recover_incorrect_await_syntax(lo, this.prev_token.span)
1454-
} else if this.token.uninterpolated_span().at_least_rust_2024() {
1455-
if this.is_gen_block(kw::Gen, 0) {
1456-
this.parse_gen_block()
1457-
} else {
1458-
this.parse_expr_lit()
1459-
}
14601460
} else {
14611461
this.parse_expr_lit()
14621462
}
@@ -2235,8 +2235,8 @@ impl<'a> Parser<'a> {
22352235
let movability =
22362236
if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
22372237

2238-
let asyncness = if self.token.uninterpolated_span().at_least_rust_2018() {
2239-
self.parse_asyncness(Case::Sensitive)
2238+
let coroutine_kind = if self.token.uninterpolated_span().at_least_rust_2018() {
2239+
self.parse_coroutine_kind(Case::Sensitive)
22402240
} else {
22412241
None
22422242
};
@@ -2262,9 +2262,17 @@ impl<'a> Parser<'a> {
22622262
}
22632263
};
22642264

2265-
if let Some(CoroutineKind::Async { span, .. }) = asyncness {
2266-
// Feature-gate `async ||` closures.
2267-
self.sess.gated_spans.gate(sym::async_closure, span);
2265+
match coroutine_kind {
2266+
Some(CoroutineKind::Async { span, .. }) => {
2267+
// Feature-gate `async ||` closures.
2268+
self.sess.gated_spans.gate(sym::async_closure, span);
2269+
}
2270+
Some(CoroutineKind::Gen { span, .. }) | Some(CoroutineKind::AsyncGen { span, .. }) => {
2271+
// Feature-gate `gen ||` and `async gen ||` closures.
2272+
// FIXME(gen_blocks): This perhaps should be a different gate.
2273+
self.sess.gated_spans.gate(sym::gen_blocks, span);
2274+
}
2275+
None => {}
22682276
}
22692277

22702278
if self.token.kind == TokenKind::Semi
@@ -2285,7 +2293,7 @@ impl<'a> Parser<'a> {
22852293
binder,
22862294
capture_clause,
22872295
constness,
2288-
coroutine_kind: asyncness,
2296+
coroutine_kind,
22892297
movability,
22902298
fn_decl,
22912299
body,

compiler/rustc_parse/src/parser/item.rs

+21-26
Original file line numberDiff line numberDiff line change
@@ -2394,18 +2394,15 @@ impl<'a> Parser<'a> {
23942394
let constness = self.parse_constness(case);
23952395

23962396
let async_start_sp = self.token.span;
2397-
let asyncness = self.parse_asyncness(case);
2398-
2399-
let _gen_start_sp = self.token.span;
2400-
let genness = self.parse_genness(case);
2397+
let coroutine_kind = self.parse_coroutine_kind(case);
24012398

24022399
let unsafe_start_sp = self.token.span;
24032400
let unsafety = self.parse_unsafety(case);
24042401

24052402
let ext_start_sp = self.token.span;
24062403
let ext = self.parse_extern(case);
24072404

2408-
if let Some(CoroutineKind::Async { span, .. }) = asyncness {
2405+
if let Some(CoroutineKind::Async { span, .. }) = coroutine_kind {
24092406
if span.is_rust_2015() {
24102407
self.sess.emit_err(errors::AsyncFnIn2015 {
24112408
span,
@@ -2414,16 +2411,11 @@ impl<'a> Parser<'a> {
24142411
}
24152412
}
24162413

2417-
if let Some(CoroutineKind::Gen { span, .. }) = genness {
2418-
self.sess.gated_spans.gate(sym::gen_blocks, span);
2419-
}
2420-
2421-
if let (
2422-
Some(CoroutineKind::Async { span: async_span, .. }),
2423-
Some(CoroutineKind::Gen { span: gen_span, .. }),
2424-
) = (asyncness, genness)
2425-
{
2426-
self.sess.emit_err(errors::AsyncGenFn { span: async_span.to(gen_span) });
2414+
match coroutine_kind {
2415+
Some(CoroutineKind::Gen { span, .. }) | Some(CoroutineKind::AsyncGen { span, .. }) => {
2416+
self.sess.gated_spans.gate(sym::gen_blocks, span);
2417+
}
2418+
Some(CoroutineKind::Async { .. }) | None => {}
24272419
}
24282420

24292421
if !self.eat_keyword_case(kw::Fn, case) {
@@ -2442,7 +2434,7 @@ impl<'a> Parser<'a> {
24422434

24432435
// We may be able to recover
24442436
let mut recover_constness = constness;
2445-
let mut recover_asyncness = asyncness;
2437+
let mut recover_coroutine_kind = coroutine_kind;
24462438
let mut recover_unsafety = unsafety;
24472439
// This will allow the machine fix to directly place the keyword in the correct place or to indicate
24482440
// that the keyword is already present and the second instance should be removed.
@@ -2455,15 +2447,24 @@ impl<'a> Parser<'a> {
24552447
}
24562448
}
24572449
} else if self.check_keyword(kw::Async) {
2458-
match asyncness {
2450+
match coroutine_kind {
24592451
Some(CoroutineKind::Async { span, .. }) => {
24602452
Some(WrongKw::Duplicated(span))
24612453
}
2454+
Some(CoroutineKind::AsyncGen { span, .. }) => {
2455+
Some(WrongKw::Duplicated(span))
2456+
}
24622457
Some(CoroutineKind::Gen { .. }) => {
2463-
panic!("not sure how to recover here")
2458+
recover_coroutine_kind = Some(CoroutineKind::AsyncGen {
2459+
span: self.token.span,
2460+
closure_id: DUMMY_NODE_ID,
2461+
return_impl_trait_id: DUMMY_NODE_ID,
2462+
});
2463+
// FIXME(gen_blocks): This span is wrong, didn't want to think about it.
2464+
Some(WrongKw::Misplaced(unsafe_start_sp))
24642465
}
24652466
None => {
2466-
recover_asyncness = Some(CoroutineKind::Async {
2467+
recover_coroutine_kind = Some(CoroutineKind::Async {
24672468
span: self.token.span,
24682469
closure_id: DUMMY_NODE_ID,
24692470
return_impl_trait_id: DUMMY_NODE_ID,
@@ -2561,7 +2562,7 @@ impl<'a> Parser<'a> {
25612562
return Ok(FnHeader {
25622563
constness: recover_constness,
25632564
unsafety: recover_unsafety,
2564-
coroutine_kind: recover_asyncness,
2565+
coroutine_kind: recover_coroutine_kind,
25652566
ext,
25662567
});
25672568
}
@@ -2571,12 +2572,6 @@ impl<'a> Parser<'a> {
25712572
}
25722573
}
25732574

2574-
let coroutine_kind = match asyncness {
2575-
Some(CoroutineKind::Async { .. }) => asyncness,
2576-
Some(CoroutineKind::Gen { .. }) => unreachable!("asycness cannot be Gen"),
2577-
None => genness,
2578-
};
2579-
25802575
Ok(FnHeader { constness, unsafety, coroutine_kind, ext })
25812576
}
25822577

0 commit comments

Comments
 (0)