Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 27d6539

Browse files
committed
Plumb awaitness of for loops
1 parent bf9229a commit 27d6539

File tree

26 files changed

+137
-53
lines changed

26 files changed

+137
-53
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,7 +1274,7 @@ impl Expr {
12741274
ExprKind::Let(..) => ExprPrecedence::Let,
12751275
ExprKind::If(..) => ExprPrecedence::If,
12761276
ExprKind::While(..) => ExprPrecedence::While,
1277-
ExprKind::ForLoop(..) => ExprPrecedence::ForLoop,
1277+
ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
12781278
ExprKind::Loop(..) => ExprPrecedence::Loop,
12791279
ExprKind::Match(..) => ExprPrecedence::Match,
12801280
ExprKind::Closure(..) => ExprPrecedence::Closure,
@@ -1436,10 +1436,10 @@ pub enum ExprKind {
14361436
While(P<Expr>, P<Block>, Option<Label>),
14371437
/// A `for` loop, with an optional label.
14381438
///
1439-
/// `'label: for pat in expr { block }`
1439+
/// `'label: for await? pat in iter { block }`
14401440
///
14411441
/// This is desugared to a combination of `loop` and `match` expressions.
1442-
ForLoop(P<Pat>, P<Expr>, P<Block>, Option<Label>),
1442+
ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind },
14431443
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
14441444
///
14451445
/// `'label: loop { block }`
@@ -1542,6 +1542,13 @@ pub enum ExprKind {
15421542
Err,
15431543
}
15441544

1545+
/// Used to differentiate between `for` loops and `for await` loops.
1546+
#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq, Eq)]
1547+
pub enum ForLoopKind {
1548+
For,
1549+
ForAwait,
1550+
}
1551+
15451552
/// Used to differentiate between `async {}` blocks and `gen {}` blocks.
15461553
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
15471554
pub enum GenBlockKind {

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1389,7 +1389,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
13891389
vis.visit_block(body);
13901390
visit_opt(label, |label| vis.visit_label(label));
13911391
}
1392-
ExprKind::ForLoop(pat, iter, body, label) => {
1392+
ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
13931393
vis.visit_pat(pat);
13941394
vis.visit_expr(iter);
13951395
vis.visit_block(body);

compiler/rustc_ast/src/util/classify.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
1919
| ast::ExprKind::Block(..)
2020
| ast::ExprKind::While(..)
2121
| ast::ExprKind::Loop(..)
22-
| ast::ExprKind::ForLoop(..)
22+
| ast::ExprKind::ForLoop { .. }
2323
| ast::ExprKind::TryBlock(..)
2424
| ast::ExprKind::ConstBlock(..)
2525
)
@@ -48,8 +48,16 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
4848
Closure(closure) => {
4949
expr = &closure.body;
5050
}
51-
Gen(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..)
52-
| TryBlock(..) | While(..) | ConstBlock(_) => break Some(expr),
51+
Gen(..)
52+
| Block(..)
53+
| ForLoop { .. }
54+
| If(..)
55+
| Loop(..)
56+
| Match(..)
57+
| Struct(..)
58+
| TryBlock(..)
59+
| While(..)
60+
| ConstBlock(_) => break Some(expr),
5361

5462
// FIXME: These can end in `}`, but changing these would break stable code.
5563
InlineAsm(_) | OffsetOf(_, _) | MacCall(_) | IncludedBytes(_) | FormatArgs(_) => {

compiler/rustc_ast/src/visit.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -844,11 +844,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
844844
visitor.visit_expr(subexpression);
845845
visitor.visit_block(block);
846846
}
847-
ExprKind::ForLoop(pattern, subexpression, block, opt_label) => {
848-
walk_list!(visitor, visit_label, opt_label);
849-
visitor.visit_pat(pattern);
850-
visitor.visit_expr(subexpression);
851-
visitor.visit_block(block);
847+
ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
848+
walk_list!(visitor, visit_label, label);
849+
visitor.visit_pat(pat);
850+
visitor.visit_expr(iter);
851+
visitor.visit_block(body);
852852
}
853853
ExprKind::Loop(block, opt_label, _) => {
854854
walk_list!(visitor, visit_label, opt_label);

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
5656
return ex;
5757
}
5858
// Desugar `ExprForLoop`
59-
// from: `[opt_ident]: for <pat> in <head> <body>`
59+
// from: `[opt_ident]: for await? <pat> in <iter> <body>`
6060
//
6161
// This also needs special handling because the HirId of the returned `hir::Expr` will not
6262
// correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.
63-
ExprKind::ForLoop(pat, head, body, opt_label) => {
64-
return self.lower_expr_for(e, pat, head, body, *opt_label);
63+
ExprKind::ForLoop { pat, iter, body, label, kind } => {
64+
return self.lower_expr_for(e, pat, iter, body, *label, *kind);
6565
}
6666
_ => (),
6767
}
@@ -337,7 +337,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
337337
),
338338
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
339339

340-
ExprKind::Paren(_) | ExprKind::ForLoop(..) => {
340+
ExprKind::Paren(_) | ExprKind::ForLoop{..} => {
341341
unreachable!("already handled")
342342
}
343343

@@ -1673,6 +1673,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
16731673
head: &Expr,
16741674
body: &Block,
16751675
opt_label: Option<Label>,
1676+
_loop_kind: ForLoopKind,
16761677
) -> hir::Expr<'hir> {
16771678
let head = self.lower_expr_mut(head);
16781679
let pat = self.lower_pat(pat);

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
526526
"async closures are unstable",
527527
"to use an async block, remove the `||`: `async {`"
528528
);
529+
gate_all!(async_for_loop, "`for await` loops are experimental");
529530
gate_all!(
530531
closure_lifetime_binder,
531532
"`for<...>` binders for closures are experimental",

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::pp::Breaks::Inconsistent;
22
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
3+
use ast::ForLoopKind;
34
use itertools::{Itertools, Position};
45
use rustc_ast::ptr::P;
56
use rustc_ast::token;
@@ -418,20 +419,23 @@ impl<'a> State<'a> {
418419
self.space();
419420
self.print_block_with_attrs(blk, attrs);
420421
}
421-
ast::ExprKind::ForLoop(pat, iter, blk, opt_label) => {
422-
if let Some(label) = opt_label {
422+
ast::ExprKind::ForLoop { pat, iter, body, label, kind } => {
423+
if let Some(label) = label {
423424
self.print_ident(label.ident);
424425
self.word_space(":");
425426
}
426427
self.cbox(0);
427428
self.ibox(0);
428429
self.word_nbsp("for");
430+
if kind == &ForLoopKind::ForAwait {
431+
self.word_nbsp("await");
432+
}
429433
self.print_pat(pat);
430434
self.space();
431435
self.word_space("in");
432436
self.print_expr_as_cond(iter);
433437
self.space();
434-
self.print_block_with_attrs(blk, attrs);
438+
self.print_block_with_attrs(body, attrs);
435439
}
436440
ast::ExprKind::Loop(blk, opt_label, _) => {
437441
if let Some(label) = opt_label {

compiler/rustc_builtin_macros/src/assert/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
303303
| ExprKind::Continue(_)
304304
| ExprKind::Err
305305
| ExprKind::Field(_, _)
306-
| ExprKind::ForLoop(_, _, _, _)
306+
| ExprKind::ForLoop {..}
307307
| ExprKind::FormatArgs(_)
308308
| ExprKind::IncludedBytes(..)
309309
| ExprKind::InlineAsm(_)

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ declare_features! (
357357
(unstable, async_closure, "1.37.0", Some(62290)),
358358
/// Allows `#[track_caller]` on async functions.
359359
(unstable, async_fn_track_caller, "1.73.0", Some(110011)),
360+
/// Allows `for await` loops.
361+
(unstable, async_for_loop, "CURRENT_RUSTC_VERSION", None),
360362
/// Allows builtin # foo() syntax
361363
(unstable, builtin_syntax, "1.71.0", Some(110680)),
362364
/// Treat `extern "C"` function as nounwind.

compiler/rustc_lint/src/unused.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -852,8 +852,8 @@ trait UnusedDelimLint {
852852
(cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right), true)
853853
}
854854

855-
ForLoop(_, ref cond, ref block, ..) => {
856-
(cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()), true)
855+
ForLoop { ref iter, ref body, .. } => {
856+
(iter, UnusedDelimsCtx::ForIterExpr, true, None, Some(body.span.lo()), true)
857857
}
858858

859859
Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
@@ -1085,7 +1085,7 @@ impl EarlyLintPass for UnusedParens {
10851085
}
10861086

10871087
match e.kind {
1088-
ExprKind::Let(ref pat, _, _, _) | ExprKind::ForLoop(ref pat, ..) => {
1088+
ExprKind::Let(ref pat, _, _, _) | ExprKind::ForLoop { ref pat, .. } => {
10891089
self.check_unused_parens_pat(cx, pat, false, false, (true, true));
10901090
}
10911091
// We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already

0 commit comments

Comments
 (0)