Skip to content

Commit 56278a6

Browse files
committed
Auto merge of #118457 - eholk:genfn, r=compiler-errors
Add support for `gen fn` This builds on #116447 to add support for `gen fn` functions. For the most part we follow the same approach as desugaring `async fn`, but replacing `Future` with `Iterator` and `async {}` with `gen {}` for the body. The version implemented here uses the return type of a `gen fn` as the yield type. For example: ```rust gen fn count_to_three() -> i32 { yield 1; yield 2; yield 3; } ``` In the future, I think we should experiment with a syntax like `gen fn count_to_three() yield i32 { ... }`, but that can go in another PR. cc `@oli-obk` `@compiler-errors`
2 parents ec94480 + 2c8dbd9 commit 56278a6

File tree

36 files changed

+417
-234
lines changed

36 files changed

+417
-234
lines changed

compiler/rustc_ast/src/ast.rs

+28-27
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 asyncness: Async,
1314+
pub coro_kind: Option<CoroutineKind>,
13151315
pub movability: Movability,
13161316
pub fn_decl: P<FnDecl>,
13171317
pub body: P<Expr>,
@@ -2406,28 +2406,34 @@ pub enum Unsafe {
24062406
No,
24072407
}
24082408

2409+
/// Describes what kind of coroutine markers, if any, a function has.
2410+
///
2411+
/// Coroutine markers are things that cause the function to generate a coroutine, such as `async`,
2412+
/// which makes the function return `impl Future`, or `gen`, which makes the function return `impl
2413+
/// Iterator`.
24092414
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
2410-
pub enum Async {
2411-
Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
2412-
No,
2415+
pub enum CoroutineKind {
2416+
/// `async`, which evaluates to `impl Future`
2417+
Async { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
2418+
/// `gen`, which evaluates to `impl Iterator`
2419+
Gen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
24132420
}
24142421

2415-
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
2416-
pub enum Gen {
2417-
Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
2418-
No,
2419-
}
2420-
2421-
impl Async {
2422+
impl CoroutineKind {
24222423
pub fn is_async(self) -> bool {
2423-
matches!(self, Async::Yes { .. })
2424+
matches!(self, CoroutineKind::Async { .. })
2425+
}
2426+
2427+
pub fn is_gen(self) -> bool {
2428+
matches!(self, CoroutineKind::Gen { .. })
24242429
}
24252430

2426-
/// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
2427-
pub fn opt_return_id(self) -> Option<(NodeId, Span)> {
2431+
/// In this case this is an `async` or `gen` return, the `NodeId` for the generated `impl Trait`
2432+
/// item.
2433+
pub fn return_id(self) -> (NodeId, Span) {
24282434
match self {
2429-
Async::Yes { return_impl_trait_id, span, .. } => Some((return_impl_trait_id, span)),
2430-
Async::No => None,
2435+
CoroutineKind::Async { return_impl_trait_id, span, .. }
2436+
| CoroutineKind::Gen { return_impl_trait_id, span, .. } => (return_impl_trait_id, span),
24312437
}
24322438
}
24332439
}
@@ -2831,8 +2837,8 @@ impl Extern {
28312837
pub struct FnHeader {
28322838
/// The `unsafe` keyword, if any
28332839
pub unsafety: Unsafe,
2834-
/// The `async` keyword, if any
2835-
pub asyncness: Async,
2840+
/// Whether this is `async`, `gen`, or nothing.
2841+
pub coro_kind: Option<CoroutineKind>,
28362842
/// The `const` keyword, if any
28372843
pub constness: Const,
28382844
/// The `extern` keyword and corresponding ABI string, if any
@@ -2842,22 +2848,17 @@ pub struct FnHeader {
28422848
impl FnHeader {
28432849
/// Does this function header have any qualifiers or is it empty?
28442850
pub fn has_qualifiers(&self) -> bool {
2845-
let Self { unsafety, asyncness, constness, ext } = self;
2851+
let Self { unsafety, coro_kind, constness, ext } = self;
28462852
matches!(unsafety, Unsafe::Yes(_))
2847-
|| asyncness.is_async()
2853+
|| coro_kind.is_some()
28482854
|| matches!(constness, Const::Yes(_))
28492855
|| !matches!(ext, Extern::None)
28502856
}
28512857
}
28522858

28532859
impl Default for FnHeader {
28542860
fn default() -> FnHeader {
2855-
FnHeader {
2856-
unsafety: Unsafe::No,
2857-
asyncness: Async::No,
2858-
constness: Const::No,
2859-
ext: Extern::None,
2860-
}
2861+
FnHeader { unsafety: Unsafe::No, coro_kind: None, constness: Const::No, ext: Extern::None }
28612862
}
28622863
}
28632864

@@ -3177,7 +3178,7 @@ mod size_asserts {
31773178
static_assert_size!(Block, 32);
31783179
static_assert_size!(Expr, 72);
31793180
static_assert_size!(ExprKind, 40);
3180-
static_assert_size!(Fn, 152);
3181+
static_assert_size!(Fn, 160);
31813182
static_assert_size!(ForeignItem, 96);
31823183
static_assert_size!(ForeignItemKind, 24);
31833184
static_assert_size!(GenericArg, 24);

compiler/rustc_ast/src/mut_visit.rs

+11-10
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_asyncness(&mut self, a: &mut Async) {
125-
noop_visit_asyncness(a, self);
124+
fn visit_coro_kind(&mut self, a: &mut CoroutineKind) {
125+
noop_visit_coro_kind(a, self);
126126
}
127127

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

874-
pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) {
875-
match asyncness {
876-
Async::Yes { span: _, closure_id, return_impl_trait_id } => {
874+
pub fn noop_visit_coro_kind<T: MutVisitor>(coro_kind: &mut CoroutineKind, vis: &mut T) {
875+
match coro_kind {
876+
CoroutineKind::Async { span, closure_id, return_impl_trait_id }
877+
| CoroutineKind::Gen { span, closure_id, return_impl_trait_id } => {
878+
vis.visit_span(span);
877879
vis.visit_id(closure_id);
878880
vis.visit_id(return_impl_trait_id);
879881
}
880-
Async::No => {}
881882
}
882883
}
883884

@@ -1170,9 +1171,9 @@ fn visit_const_item<T: MutVisitor>(
11701171
}
11711172

11721173
pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
1173-
let FnHeader { unsafety, asyncness, constness, ext: _ } = header;
1174+
let FnHeader { unsafety, coro_kind, constness, ext: _ } = header;
11741175
visit_constness(constness, vis);
1175-
vis.visit_asyncness(asyncness);
1176+
coro_kind.as_mut().map(|coro_kind| vis.visit_coro_kind(coro_kind));
11761177
visit_unsafety(unsafety, vis);
11771178
}
11781179

@@ -1406,7 +1407,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
14061407
binder,
14071408
capture_clause,
14081409
constness,
1409-
asyncness,
1410+
coro_kind,
14101411
movability: _,
14111412
fn_decl,
14121413
body,
@@ -1415,7 +1416,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
14151416
}) => {
14161417
vis.visit_closure_binder(binder);
14171418
visit_constness(constness, vis);
1418-
vis.visit_asyncness(asyncness);
1419+
coro_kind.as_mut().map(|coro_kind| vis.visit_coro_kind(coro_kind));
14191420
vis.visit_capture_by(capture_clause);
14201421
vis.visit_fn_decl(fn_decl);
14211422
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-
asyncness: _,
864+
coro_kind: _,
865865
constness: _,
866866
movability: _,
867867
fn_decl,

compiler/rustc_ast_lowering/src/expr.rs

+28-28
Original file line numberDiff line numberDiff line change
@@ -195,39 +195,39 @@ impl<'hir> LoweringContext<'_, 'hir> {
195195
binder,
196196
capture_clause,
197197
constness,
198-
asyncness,
198+
coro_kind,
199199
movability,
200200
fn_decl,
201201
body,
202202
fn_decl_span,
203203
fn_arg_span,
204-
}) => {
205-
if let Async::Yes { closure_id, .. } = asyncness {
206-
self.lower_expr_async_closure(
207-
binder,
208-
*capture_clause,
209-
e.id,
210-
hir_id,
211-
*closure_id,
212-
fn_decl,
213-
body,
214-
*fn_decl_span,
215-
*fn_arg_span,
216-
)
217-
} else {
218-
self.lower_expr_closure(
219-
binder,
220-
*capture_clause,
221-
e.id,
222-
*constness,
223-
*movability,
224-
fn_decl,
225-
body,
226-
*fn_decl_span,
227-
*fn_arg_span,
228-
)
229-
}
230-
}
204+
}) => match coro_kind {
205+
Some(
206+
CoroutineKind::Async { closure_id, .. }
207+
| CoroutineKind::Gen { closure_id, .. },
208+
) => self.lower_expr_async_closure(
209+
binder,
210+
*capture_clause,
211+
e.id,
212+
hir_id,
213+
*closure_id,
214+
fn_decl,
215+
body,
216+
*fn_decl_span,
217+
*fn_arg_span,
218+
),
219+
None => self.lower_expr_closure(
220+
binder,
221+
*capture_clause,
222+
e.id,
223+
*constness,
224+
*movability,
225+
fn_decl,
226+
body,
227+
*fn_decl_span,
228+
*fn_arg_span,
229+
),
230+
},
231231
ExprKind::Block(blk, opt_label) => {
232232
let opt_label = self.lower_label(*opt_label);
233233
hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)

0 commit comments

Comments
 (0)