about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-22 14:17:10 +0000
committerbors <bors@rust-lang.org>2023-12-22 14:17:10 +0000
commit4ad06d1adf1d4afe1ded4c09ad2bb3dc782680d7 (patch)
tree7d3fe1a5744eb5c16e4d6f650a0ceeaf809ea4b5
parent062845421b8a678f2807f0682db429025dd18ebe (diff)
parent212ea0359c52f63cf05cdd73cf5c30f42aae2aa8 (diff)
downloadrust-4ad06d1adf1d4afe1ded4c09ad2bb3dc782680d7.tar.gz
rust-4ad06d1adf1d4afe1ded4c09ad2bb3dc782680d7.zip
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`
-rw-r--r--clippy_lints/src/needless_continue.rs6
-rw-r--r--clippy_lints/src/redundant_else.rs2
-rw-r--r--clippy_lints/src/suspicious_operation_groupings.rs2
-rw-r--r--clippy_utils/src/ast_utils.rs19
-rw-r--r--clippy_utils/src/sugg.rs2
5 files changed, 24 insertions, 7 deletions
diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs
index 4b9ab50e4fd..ff72b5e69ef 100644
--- a/clippy_lints/src/needless_continue.rs
+++ b/clippy_lints/src/needless_continue.rs
@@ -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());
diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs
index 001686c84f8..fb434fb7450 100644
--- a/clippy_lints/src/redundant_else.rs
+++ b/clippy_lints/src/redundant_else.rs
@@ -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;
diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs
index 8b9d9bade91..60e9d262e7e 100644
--- a/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/clippy_lints/src/suspicious_operation_groupings.rs
@@ -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(_, _, _, _))
diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs
index c271e498665..7fe76b946a4 100644
--- a/clippy_utils/src/ast_utils.rs
+++ b/clippy_utils/src/ast_utils.rs
@@ -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),
diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs
index 9b2bc8df1f3..c86362c427c 100644
--- a/clippy_utils/src/sugg.rs
+++ b/clippy_utils/src/sugg.rs
@@ -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(..)