Auto merge of #118847 - eholk:for-await, r=compiler-errors

Add support for `for await` loops

This adds support for `for await` loops. This includes parsing, desugaring in AST->HIR lowering, and adding some support functions to the library.

Given a loop like:
```rust
for await i in iter {
    ...
}
```
this is desugared to something like:
```rust
let mut iter = iter.into_async_iter();
while let Some(i) = loop {
    match core::pin::Pin::new(&mut iter).poll_next(cx) {
        Poll::Ready(i) => break i,
        Poll::Pending => yield,
    }
} {
    ...
}
```

This PR also adds a basic `IntoAsyncIterator` trait. This is partly for symmetry with the way `Iterator` and `IntoIterator` work. The other reason is that for async iterators it's helpful to have a place apart from the data structure being iterated over to store state. `IntoAsyncIterator` gives us a good place to do this.

I've gated this feature behind `async_for_loop` and opened #118898 as the feature tracking issue.

r? `@compiler-errors`
This commit is contained in:
bors 2023-12-22 14:17:10 +00:00
commit 4ad06d1adf
5 changed files with 24 additions and 7 deletions

View file

@ -220,7 +220,11 @@ where
F: FnMut(&ast::Block, Option<&ast::Label>),
{
if let ast::ExprKind::While(_, loop_block, label)
| ast::ExprKind::ForLoop(_, _, loop_block, label)
| ast::ExprKind::ForLoop {
body: loop_block,
label,
..
}
| ast::ExprKind::Loop(loop_block, label, ..) = &expr.kind
{
func(loop_block, label.as_ref());

View file

@ -111,7 +111,7 @@ impl<'ast> Visitor<'ast> for BreakVisitor {
ExprKind::If(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els),
ExprKind::If(_, _, None)
// ignore loops for simplicity
| ExprKind::While(..) | ExprKind::ForLoop(..) | ExprKind::Loop(..) => false,
| ExprKind::While(..) | ExprKind::ForLoop { .. } | ExprKind::Loop(..) => false,
_ => {
walk_expr(self, expr);
return;

View file

@ -554,7 +554,7 @@ fn ident_difference_expr_with_base_location(
| (Closure(_), Closure(_))
| (Match(_, _), Match(_, _))
| (Loop(_, _, _), Loop(_, _, _))
| (ForLoop(_, _, _, _), ForLoop(_, _, _, _))
| (ForLoop { .. }, ForLoop { .. })
| (While(_, _, _), While(_, _, _))
| (If(_, _, _), If(_, _, _))
| (Let(_, _, _, _), Let(_, _, _, _))

View file

@ -169,9 +169,22 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
(Let(lp, le, _, _), Let(rp, re, _, _)) => eq_pat(lp, rp) && eq_expr(le, re),
(If(lc, lt, le), If(rc, rt, re)) => eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le, re),
(While(lc, lt, ll), While(rc, rt, rl)) => eq_label(ll, rl) && eq_expr(lc, rc) && eq_block(lt, rt),
(ForLoop(lp, li, lt, ll), ForLoop(rp, ri, rt, rl)) => {
eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt)
},
(
ForLoop {
pat: lp,
iter: li,
body: lt,
label: ll,
kind: lk,
},
ForLoop {
pat: rp,
iter: ri,
body: rt,
label: rl,
kind: rk,
},
) => eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk,
(Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll, rl) && eq_block(lt, rt),
(Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb),
(TryBlock(l), TryBlock(r)) => eq_block(l, r),

View file

@ -197,7 +197,7 @@ impl<'a> Sugg<'a> {
| ast::ExprKind::Continue(..)
| ast::ExprKind::Yield(..)
| ast::ExprKind::Field(..)
| ast::ExprKind::ForLoop(..)
| ast::ExprKind::ForLoop { .. }
| ast::ExprKind::Index(..)
| ast::ExprKind::InlineAsm(..)
| ast::ExprKind::OffsetOf(..)