diff options
| author | Eric Holk <ericholk@microsoft.com> | 2023-12-08 14:51:50 -0800 |
|---|---|---|
| committer | Eric Holk <ericholk@microsoft.com> | 2023-12-19 12:26:20 -0800 |
| commit | 27d6539a46123dcdb6fae6e043b8c1c12b3e0d6f (patch) | |
| tree | b57c35ff3b5d0f5ddd5ff8060acdcf1d8f0f2ace | |
| parent | bf9229a2e366b4c311f059014a4aa08af16de5d8 (diff) | |
| download | rust-27d6539a46123dcdb6fae6e043b8c1c12b3e0d6f.tar.gz rust-27d6539a46123dcdb6fae6e043b8c1c12b3e0d6f.zip | |
Plumb awaitness of for loops
26 files changed, 137 insertions, 53 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 9d543563c0f..8a0fbdd1357 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1274,7 +1274,7 @@ impl Expr { ExprKind::Let(..) => ExprPrecedence::Let, ExprKind::If(..) => ExprPrecedence::If, ExprKind::While(..) => ExprPrecedence::While, - ExprKind::ForLoop(..) => ExprPrecedence::ForLoop, + ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop, ExprKind::Loop(..) => ExprPrecedence::Loop, ExprKind::Match(..) => ExprPrecedence::Match, ExprKind::Closure(..) => ExprPrecedence::Closure, @@ -1436,10 +1436,10 @@ pub enum ExprKind { While(P<Expr>, P<Block>, Option<Label>), /// A `for` loop, with an optional label. /// - /// `'label: for pat in expr { block }` + /// `'label: for await? pat in iter { block }` /// /// This is desugared to a combination of `loop` and `match` expressions. - ForLoop(P<Pat>, P<Expr>, P<Block>, Option<Label>), + ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind }, /// Conditionless loop (can be exited with `break`, `continue`, or `return`). /// /// `'label: loop { block }` @@ -1542,6 +1542,13 @@ pub enum ExprKind { Err, } +/// Used to differentiate between `for` loops and `for await` loops. +#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq, Eq)] +pub enum ForLoopKind { + For, + ForAwait, +} + /// Used to differentiate between `async {}` blocks and `gen {}` blocks. #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum GenBlockKind { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 10b2025f937..d0afd90e5e7 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1389,7 +1389,7 @@ pub fn noop_visit_expr<T: MutVisitor>( vis.visit_block(body); visit_opt(label, |label| vis.visit_label(label)); } - ExprKind::ForLoop(pat, iter, body, label) => { + ExprKind::ForLoop { pat, iter, body, label, kind: _ } => { vis.visit_pat(pat); vis.visit_expr(iter); vis.visit_block(body); diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 4dece079783..65036bcdc36 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -19,7 +19,7 @@ pub 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(..) | ast::ExprKind::ConstBlock(..) ) @@ -48,8 +48,16 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> { Closure(closure) => { expr = &closure.body; } - Gen(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..) - | TryBlock(..) | While(..) | ConstBlock(_) => break Some(expr), + Gen(..) + | Block(..) + | ForLoop { .. } + | If(..) + | Loop(..) + | Match(..) + | Struct(..) + | TryBlock(..) + | While(..) + | ConstBlock(_) => break Some(expr), // FIXME: These can end in `}`, but changing these would break stable code. InlineAsm(_) | OffsetOf(_, _) | MacCall(_) | IncludedBytes(_) | FormatArgs(_) => { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 27f1b84f372..45261ca48fc 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -844,11 +844,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(subexpression); visitor.visit_block(block); } - ExprKind::ForLoop(pattern, subexpression, block, opt_label) => { - walk_list!(visitor, visit_label, opt_label); - visitor.visit_pat(pattern); - visitor.visit_expr(subexpression); - visitor.visit_block(block); + ExprKind::ForLoop { pat, iter, body, label, kind: _ } => { + walk_list!(visitor, visit_label, label); + visitor.visit_pat(pat); + visitor.visit_expr(iter); + visitor.visit_block(body); } ExprKind::Loop(block, opt_label, _) => { walk_list!(visitor, visit_label, opt_label); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 11b5131b8d7..c2d91b09453 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -56,12 +56,12 @@ impl<'hir> LoweringContext<'_, 'hir> { return ex; } // Desugar `ExprForLoop` - // from: `[opt_ident]: for <pat> in <head> <body>` + // from: `[opt_ident]: for await? <pat> in <iter> <body>` // // This also needs special handling because the HirId of the returned `hir::Expr` will not // correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself. - ExprKind::ForLoop(pat, head, body, opt_label) => { - return self.lower_expr_for(e, pat, head, body, *opt_label); + ExprKind::ForLoop { pat, iter, body, label, kind } => { + return self.lower_expr_for(e, pat, iter, body, *label, *kind); } _ => (), } @@ -337,7 +337,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr), - ExprKind::Paren(_) | ExprKind::ForLoop(..) => { + ExprKind::Paren(_) | ExprKind::ForLoop{..} => { unreachable!("already handled") } @@ -1673,6 +1673,7 @@ impl<'hir> LoweringContext<'_, 'hir> { head: &Expr, body: &Block, opt_label: Option<Label>, + _loop_kind: ForLoopKind, ) -> hir::Expr<'hir> { let head = self.lower_expr_mut(head); let pat = self.lower_pat(pat); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 142cdd15e64..411c10df0c2 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -526,6 +526,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { "async closures are unstable", "to use an async block, remove the `||`: `async {`" ); + gate_all!(async_for_loop, "`for await` loops are experimental"); gate_all!( closure_lifetime_binder, "`for<...>` binders for closures are experimental", diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index f5ffcddb83d..f868beec812 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -1,5 +1,6 @@ use crate::pp::Breaks::Inconsistent; use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; +use ast::ForLoopKind; use itertools::{Itertools, Position}; use rustc_ast::ptr::P; use rustc_ast::token; @@ -418,20 +419,23 @@ impl<'a> State<'a> { self.space(); self.print_block_with_attrs(blk, attrs); } - ast::ExprKind::ForLoop(pat, iter, blk, opt_label) => { - if let Some(label) = opt_label { + ast::ExprKind::ForLoop { pat, iter, body, label, kind } => { + if let Some(label) = label { self.print_ident(label.ident); self.word_space(":"); } self.cbox(0); self.ibox(0); self.word_nbsp("for"); + if kind == &ForLoopKind::ForAwait { + self.word_nbsp("await"); + } self.print_pat(pat); self.space(); self.word_space("in"); self.print_expr_as_cond(iter); self.space(); - self.print_block_with_attrs(blk, attrs); + self.print_block_with_attrs(body, attrs); } ast::ExprKind::Loop(blk, opt_label, _) => { if let Some(label) = opt_label { diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index b54e119189a..4e07122a5c4 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -303,7 +303,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Continue(_) | ExprKind::Err | ExprKind::Field(_, _) - | ExprKind::ForLoop(_, _, _, _) + | ExprKind::ForLoop {..} | ExprKind::FormatArgs(_) | ExprKind::IncludedBytes(..) | ExprKind::InlineAsm(_) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index bbf5e031175..fdd4bb755e4 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -357,6 +357,8 @@ declare_features! ( (unstable, async_closure, "1.37.0", Some(62290)), /// Allows `#[track_caller]` on async functions. (unstable, async_fn_track_caller, "1.73.0", Some(110011)), + /// Allows `for await` loops. + (unstable, async_for_loop, "CURRENT_RUSTC_VERSION", None), /// Allows builtin # foo() syntax (unstable, builtin_syntax, "1.71.0", Some(110680)), /// Treat `extern "C"` function as nounwind. diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 34cdee4ec5c..0386f2ec56c 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -852,8 +852,8 @@ trait UnusedDelimLint { (cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right), true) } - ForLoop(_, ref cond, ref block, ..) => { - (cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()), true) + ForLoop { ref iter, ref body, .. } => { + (iter, UnusedDelimsCtx::ForIterExpr, true, None, Some(body.span.lo()), true) } Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { @@ -1085,7 +1085,7 @@ impl EarlyLintPass for UnusedParens { } match e.kind { - ExprKind::Let(ref pat, _, _, _) | ExprKind::ForLoop(ref pat, ..) => { + ExprKind::Let(ref pat, _, _, _) | ExprKind::ForLoop { ref pat, .. } => { self.check_unused_parens_pat(cx, pat, false, false, (true, true)); } // We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index cd3e8b92f2f..f424040e4ea 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -10,7 +10,7 @@ use super::{ use crate::errors; use crate::maybe_recover_from_interpolated_ty_qpath; use ast::mut_visit::{noop_visit_expr, MutVisitor}; -use ast::{CoroutineKind, GenBlockKind, Pat, Path, PathSegment}; +use ast::{CoroutineKind, ForLoopKind, GenBlockKind, Pat, Path, PathSegment}; use core::mem; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; @@ -1801,7 +1801,7 @@ impl<'a> Parser<'a> { && matches!( expr.kind, ExprKind::While(_, _, None) - | ExprKind::ForLoop(_, _, _, None) + | ExprKind::ForLoop { label: None, .. } | ExprKind::Loop(_, None, _) | ExprKind::Block(_, None) ) @@ -2682,8 +2682,16 @@ impl<'a> Parser<'a> { Ok((pat, expr)) } - /// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten). + /// Parses `for await? <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten). fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> { + let is_await = self.eat_keyword(kw::Await); + + if is_await { + self.sess.gated_spans.gate(sym::async_for_loop, self.prev_token.span); + } + + let kind = if is_await { ForLoopKind::ForAwait } else { ForLoopKind::For }; + let (pat, expr) = self.parse_for_head()?; // Recover from missing expression in `for` loop if matches!(expr.kind, ExprKind::Block(..)) @@ -2696,13 +2704,13 @@ impl<'a> Parser<'a> { let block = self.mk_block(thin_vec![], BlockCheckMode::Default, self.prev_token.span); return Ok(self.mk_expr( lo.to(self.prev_token.span), - ExprKind::ForLoop(pat, err_expr, block, opt_label), + ExprKind::ForLoop { pat, iter: err_expr, body: block, label: opt_label, kind }, )); } let (attrs, loop_block) = self.parse_inner_attrs_and_block()?; - let kind = ExprKind::ForLoop(pat, expr, loop_block, opt_label); + let kind = ExprKind::ForLoop { pat, iter: expr, body: loop_block, label: opt_label, kind }; self.recover_loop_else("for", lo)?; @@ -3798,7 +3806,7 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::Lit(_) | ExprKind::If(_, _, _) | ExprKind::While(_, _, _) - | ExprKind::ForLoop(_, _, _, _) + | ExprKind::ForLoop { .. } | ExprKind::Loop(_, _, _) | ExprKind::Match(_, _) | ExprKind::Closure(_) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 037179350f0..7e275a207e7 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4252,11 +4252,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { }); } - ExprKind::ForLoop(ref pat, ref iter_expr, ref block, label) => { - self.visit_expr(iter_expr); + ExprKind::ForLoop { ref pat, ref iter, ref body, label, kind: _ } => { + self.visit_expr(iter); self.with_rib(ValueNS, RibKind::Normal, |this| { this.resolve_pattern_top(pat, PatternSource::For); - this.resolve_labeled_block(label, expr.id, block); + this.resolve_labeled_block(label, expr.id, body); }); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d767ed74139..b4dc9d35b42 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1409,7 +1409,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { | ExprKind::Unary(..) | ExprKind::If(..) | ExprKind::While(..) - | ExprKind::ForLoop(..) + | ExprKind::ForLoop { .. } | ExprKind::Match(..), .. }), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0333b5f04c3..2e7037532b5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -426,6 +426,7 @@ symbols! { async_closure, async_fn_in_trait, async_fn_track_caller, + async_for_loop, async_iterator, atomic, atomic_mod, diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs index 4b9ab50e4fd..ff72b5e69ef 100644 --- a/src/tools/clippy/clippy_lints/src/needless_continue.rs +++ b/src/tools/clippy/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/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs index 001686c84f8..fb434fb7450 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_else.rs +++ b/src/tools/clippy/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/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index 8b9d9bade91..60e9d262e7e 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/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/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index e36f2fa87a7..be3c418ef70 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/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/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 9b2bc8df1f3..c86362c427c 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/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(..) diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs index f698f494ae5..5bf29441b54 100644 --- a/src/tools/rustfmt/src/closures.rs +++ b/src/tools/rustfmt/src/closures.rs @@ -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, } diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index a68bd6694ba..7808f891336 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -3,7 +3,7 @@ use std::cmp::min; 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 @@ impl<'a> ControlFlow<'a> { block: &'a ast::Block, label: Option<ast::Label>, span: Span, + kind: ForLoopKind, ) -> ControlFlow<'a> { ControlFlow { cond: Some(cond), @@ -778,7 +785,10 @@ impl<'a> ControlFlow<'a> { 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 diff --git a/src/tools/rustfmt/src/matches.rs b/src/tools/rustfmt/src/matches.rs index ef509b56837..5a00984d4c0 100644 --- a/src/tools/rustfmt/src/matches.rs +++ b/src/tools/rustfmt/src/matches.rs @@ -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(..) diff --git a/src/tools/rustfmt/src/overflow.rs b/src/tools/rustfmt/src/overflow.rs index d81bf24dbd1..f46583b1c89 100644 --- a/src/tools/rustfmt/src/overflow.rs +++ b/src/tools/rustfmt/src/overflow.rs @@ -409,7 +409,7 @@ impl<'a> Context<'a> { // 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(..) => { diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 7d7bbf11529..642b6603b1e 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -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) diff --git a/tests/ui/async-await/feature-async-for-loop.rs b/tests/ui/async-await/feature-async-for-loop.rs new file mode 100644 index 00000000000..6d32b3ca700 --- /dev/null +++ b/tests/ui/async-await/feature-async-for-loop.rs @@ -0,0 +1,14 @@ +// edition:2021 +// gate-test-async_for_loop + +#![feature(async_iter_from_iter, async_iterator)] + +fn f() { + let _ = async { + for await _i in core::async_iter::from_iter(0..3) { + //~^ ERROR `for await` loops are experimental + } + }; +} + +fn main() {} diff --git a/tests/ui/async-await/feature-async-for-loop.stderr b/tests/ui/async-await/feature-async-for-loop.stderr new file mode 100644 index 00000000000..7e6d83fe5b6 --- /dev/null +++ b/tests/ui/async-await/feature-async-for-loop.stderr @@ -0,0 +1,11 @@ +error[E0658]: `for await` loops are experimental + --> $DIR/feature-async-for-loop.rs:8:13 + | +LL | for await _i in core::async_iter::from_iter(0..3) { + | ^^^^^ + | + = help: add `#![feature(async_for_loop)]` to the crate attributes to enable + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. |
