1
Fork 0

Auto merge of #116447 - oli-obk:gen_fn, r=compiler-errors

Implement `gen` blocks in the 2024 edition

Coroutines tracking issue https://github.com/rust-lang/rust/issues/43122
`gen` block tracking issue https://github.com/rust-lang/rust/issues/117078

This PR implements `gen` blocks that implement `Iterator`. Most of the logic with `async` blocks is shared, and thus I renamed various types that were referring to `async` specifically.

An example usage of `gen` blocks is

```rust
fn foo() -> impl Iterator<Item = i32> {
    gen {
        yield 42;
        for i in 5..18 {
            if i.is_even() { continue }
            yield i * 2;
        }
    }
}
```

The limitations (to be resolved) of the implementation are listed in the tracking issue
This commit is contained in:
bors 2023-10-29 00:03:52 +00:00
commit 2cad938a81
75 changed files with 1096 additions and 148 deletions

View file

@ -1235,7 +1235,7 @@ impl Expr {
ExprKind::Closure(..) => ExprPrecedence::Closure,
ExprKind::Block(..) => ExprPrecedence::Block,
ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
ExprKind::Async(..) => ExprPrecedence::Async,
ExprKind::Gen(..) => ExprPrecedence::Gen,
ExprKind::Await(..) => ExprPrecedence::Await,
ExprKind::Assign(..) => ExprPrecedence::Assign,
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
@ -1405,11 +1405,9 @@ pub enum ExprKind {
Closure(Box<Closure>),
/// A block (`'label: { ... }`).
Block(P<Block>, Option<Label>),
/// An async block (`async move { ... }`).
///
/// The async block used to have a `NodeId`, which was removed in favor of
/// using the parent `NodeId` of the parent `Expr`.
Async(CaptureBy, P<Block>),
/// An `async` block (`async move { ... }`),
/// or a `gen` block (`gen move { ... }`)
Gen(CaptureBy, P<Block>, GenBlockKind),
/// An await expression (`my_future.await`). Span is of await keyword.
Await(P<Expr>, Span),
@ -1499,6 +1497,28 @@ pub enum ExprKind {
Err,
}
/// Used to differentiate between `async {}` blocks and `gen {}` blocks.
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
pub enum GenBlockKind {
Async,
Gen,
}
impl fmt::Display for GenBlockKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.modifier().fmt(f)
}
}
impl GenBlockKind {
pub fn modifier(&self) -> &'static str {
match self {
GenBlockKind::Async => "async",
GenBlockKind::Gen => "gen",
}
}
}
/// The explicit `Self` type in a "qualified path". The actual
/// path, including the trait and the associated item, is stored
/// separately. `position` represents the index of the associated
@ -2363,6 +2383,12 @@ pub enum Async {
No,
}
#[derive(Copy, Clone, Encodable, Decodable, Debug)]
pub enum Gen {
Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
No,
}
impl Async {
pub fn is_async(self) -> bool {
matches!(self, Async::Yes { .. })

View file

@ -1418,7 +1418,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
vis.visit_block(blk);
visit_opt(label, |label| vis.visit_label(label));
}
ExprKind::Async(_capture_by, body) => {
ExprKind::Gen(_capture_by, body, _) => {
vis.visit_block(body);
}
ExprKind::Await(expr, await_kw_span) => {

View file

@ -197,6 +197,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
kw::Continue,
kw::False,
kw::For,
kw::Gen,
kw::If,
kw::Let,
kw::Loop,

View file

@ -46,7 +46,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
Closure(closure) => {
expr = &closure.body;
}
Async(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..)
Gen(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..)
| TryBlock(..) | While(..) => break Some(expr),
_ => break None,
}

View file

@ -285,7 +285,7 @@ pub enum ExprPrecedence {
Block,
TryBlock,
Struct,
Async,
Gen,
Await,
Err,
}
@ -351,7 +351,7 @@ impl ExprPrecedence {
| ExprPrecedence::ConstBlock
| ExprPrecedence::Block
| ExprPrecedence::TryBlock
| ExprPrecedence::Async
| ExprPrecedence::Gen
| ExprPrecedence::Struct
| ExprPrecedence::Err => PREC_PAREN,
}

View file

@ -872,7 +872,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_block(block);
}
ExprKind::Async(_, body) => {
ExprKind::Gen(_, body, _) => {
visitor.visit_block(body);
}
ExprKind::Await(expr, _) => visitor.visit_expr(expr),