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 b29b02ca5b
5 changed files with 23 additions and 13 deletions

View File

@ -448,7 +448,7 @@ fn is_block_closure_forced(context: &RewriteContext<'_>, expr: &ast::Expr) -> bo
fn is_block_closure_forced_inner(expr: &ast::Expr, version: Version) -> bool {
match expr.kind {
ast::ExprKind::If(..) | ast::ExprKind::While(..) | ast::ExprKind::ForLoop(..) => true,
ast::ExprKind::If(..) | ast::ExprKind::While(..) | ast::ExprKind::ForLoop { .. } => true,
ast::ExprKind::Loop(..) if version == Version::Two => true,
ast::ExprKind::AddrOf(_, _, ref expr)
| ast::ExprKind::Try(ref expr)
@ -473,7 +473,7 @@ fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
| ast::ExprKind::Block(..)
| ast::ExprKind::While(..)
| ast::ExprKind::Loop(..)
| ast::ExprKind::ForLoop(..)
| ast::ExprKind::ForLoop { .. }
| ast::ExprKind::TryBlock(..) => false,
_ => true,
}

View File

@ -3,7 +3,7 @@
use itertools::Itertools;
use rustc_ast::token::{Delimiter, Lit, LitKind};
use rustc_ast::{ast, ptr, token};
use rustc_ast::{ast, ptr, token, ForLoopKind};
use rustc_span::{BytePos, Span};
use crate::chains::rewrite_chain;
@ -134,7 +134,7 @@ pub(crate) fn format_expr(
}
ast::ExprKind::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr),
ast::ExprKind::If(..)
| ast::ExprKind::ForLoop(..)
| ast::ExprKind::ForLoop { .. }
| ast::ExprKind::Loop(..)
| ast::ExprKind::While(..) => to_control_flow(expr, expr_type)
.and_then(|control_flow| control_flow.rewrite(context, shape)),
@ -682,9 +682,15 @@ fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow<
expr.span,
))
}
ast::ExprKind::ForLoop(ref pat, ref cond, ref block, label) => {
Some(ControlFlow::new_for(pat, cond, block, label, expr.span))
}
ast::ExprKind::ForLoop {
ref pat,
ref iter,
ref body,
label,
kind,
} => Some(ControlFlow::new_for(
pat, iter, body, label, expr.span, kind,
)),
ast::ExprKind::Loop(ref block, label, _) => {
Some(ControlFlow::new_loop(block, label, expr.span))
}
@ -771,6 +777,7 @@ fn new_for(
block: &'a ast::Block,
label: Option<ast::Label>,
span: Span,
kind: ForLoopKind,
) -> ControlFlow<'a> {
ControlFlow {
cond: Some(cond),
@ -778,7 +785,10 @@ fn new_for(
else_block: None,
label,
pat: Some(pat),
keyword: "for",
keyword: match kind {
ForLoopKind::For => "for",
ForLoopKind::ForAwait => "for await",
},
matcher: "",
connector: " in",
allow_single_line: false,
@ -1364,7 +1374,7 @@ pub(crate) fn can_be_overflowed_expr(
|| context.config.overflow_delimited_expr()
}
ast::ExprKind::If(..)
| ast::ExprKind::ForLoop(..)
| ast::ExprKind::ForLoop { .. }
| ast::ExprKind::Loop(..)
| ast::ExprKind::While(..) => {
context.config.combine_control_expr() && context.use_block_indent() && args_len == 1

View File

@ -591,7 +591,7 @@ fn can_flatten_block_around_this(body: &ast::Expr) -> bool {
ast::ExprKind::If(..) => false,
// We do not allow collapsing a block around expression with condition
// to avoid it being cluttered with match arm.
ast::ExprKind::ForLoop(..) | ast::ExprKind::While(..) => false,
ast::ExprKind::ForLoop { .. } | ast::ExprKind::While(..) => false,
ast::ExprKind::Loop(..)
| ast::ExprKind::Match(..)
| ast::ExprKind::Block(..)

View File

@ -409,7 +409,7 @@ fn rewrite_last_item_with_overflow(
// When overflowing the expressions which consists of a control flow
// expression, avoid condition to use multi line.
ast::ExprKind::If(..)
| ast::ExprKind::ForLoop(..)
| ast::ExprKind::ForLoop { .. }
| ast::ExprKind::Loop(..)
| ast::ExprKind::While(..)
| ast::ExprKind::Match(..) => {

View File

@ -295,7 +295,7 @@ pub(crate) fn semicolon_for_stmt(
) -> bool {
match stmt.kind {
ast::StmtKind::Semi(ref expr) => match expr.kind {
ast::ExprKind::While(..) | ast::ExprKind::Loop(..) | ast::ExprKind::ForLoop(..) => {
ast::ExprKind::While(..) | ast::ExprKind::Loop(..) | ast::ExprKind::ForLoop { .. } => {
false
}
ast::ExprKind::Break(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Ret(..) => {
@ -476,7 +476,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
| ast::ExprKind::ConstBlock(..)
| ast::ExprKind::Gen(..)
| ast::ExprKind::Loop(..)
| ast::ExprKind::ForLoop(..)
| ast::ExprKind::ForLoop { .. }
| ast::ExprKind::TryBlock(..)
| ast::ExprKind::Match(..) => repr.contains('\n'),
ast::ExprKind::Paren(ref expr)