Plumb awaitness of for loops
This commit is contained in:
parent
bf9229a2e3
commit
27d6539a46
26 changed files with 137 additions and 53 deletions
|
@ -1274,7 +1274,7 @@ impl Expr {
|
||||||
ExprKind::Let(..) => ExprPrecedence::Let,
|
ExprKind::Let(..) => ExprPrecedence::Let,
|
||||||
ExprKind::If(..) => ExprPrecedence::If,
|
ExprKind::If(..) => ExprPrecedence::If,
|
||||||
ExprKind::While(..) => ExprPrecedence::While,
|
ExprKind::While(..) => ExprPrecedence::While,
|
||||||
ExprKind::ForLoop(..) => ExprPrecedence::ForLoop,
|
ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
|
||||||
ExprKind::Loop(..) => ExprPrecedence::Loop,
|
ExprKind::Loop(..) => ExprPrecedence::Loop,
|
||||||
ExprKind::Match(..) => ExprPrecedence::Match,
|
ExprKind::Match(..) => ExprPrecedence::Match,
|
||||||
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
||||||
|
@ -1436,10 +1436,10 @@ pub enum ExprKind {
|
||||||
While(P<Expr>, P<Block>, Option<Label>),
|
While(P<Expr>, P<Block>, Option<Label>),
|
||||||
/// A `for` loop, with an optional 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.
|
/// 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`).
|
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
|
||||||
///
|
///
|
||||||
/// `'label: loop { block }`
|
/// `'label: loop { block }`
|
||||||
|
@ -1542,6 +1542,13 @@ pub enum ExprKind {
|
||||||
Err,
|
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.
|
/// Used to differentiate between `async {}` blocks and `gen {}` blocks.
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
|
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
|
||||||
pub enum GenBlockKind {
|
pub enum GenBlockKind {
|
||||||
|
|
|
@ -1389,7 +1389,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||||
vis.visit_block(body);
|
vis.visit_block(body);
|
||||||
visit_opt(label, |label| vis.visit_label(label));
|
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_pat(pat);
|
||||||
vis.visit_expr(iter);
|
vis.visit_expr(iter);
|
||||||
vis.visit_block(body);
|
vis.visit_block(body);
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
|
||||||
| ast::ExprKind::Block(..)
|
| ast::ExprKind::Block(..)
|
||||||
| ast::ExprKind::While(..)
|
| ast::ExprKind::While(..)
|
||||||
| ast::ExprKind::Loop(..)
|
| ast::ExprKind::Loop(..)
|
||||||
| ast::ExprKind::ForLoop(..)
|
| ast::ExprKind::ForLoop { .. }
|
||||||
| ast::ExprKind::TryBlock(..)
|
| ast::ExprKind::TryBlock(..)
|
||||||
| ast::ExprKind::ConstBlock(..)
|
| ast::ExprKind::ConstBlock(..)
|
||||||
)
|
)
|
||||||
|
@ -48,8 +48,16 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
||||||
Closure(closure) => {
|
Closure(closure) => {
|
||||||
expr = &closure.body;
|
expr = &closure.body;
|
||||||
}
|
}
|
||||||
Gen(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..)
|
Gen(..)
|
||||||
| TryBlock(..) | While(..) | ConstBlock(_) => break Some(expr),
|
| Block(..)
|
||||||
|
| ForLoop { .. }
|
||||||
|
| If(..)
|
||||||
|
| Loop(..)
|
||||||
|
| Match(..)
|
||||||
|
| Struct(..)
|
||||||
|
| TryBlock(..)
|
||||||
|
| While(..)
|
||||||
|
| ConstBlock(_) => break Some(expr),
|
||||||
|
|
||||||
// FIXME: These can end in `}`, but changing these would break stable code.
|
// FIXME: These can end in `}`, but changing these would break stable code.
|
||||||
InlineAsm(_) | OffsetOf(_, _) | MacCall(_) | IncludedBytes(_) | FormatArgs(_) => {
|
InlineAsm(_) | OffsetOf(_, _) | MacCall(_) | IncludedBytes(_) | FormatArgs(_) => {
|
||||||
|
|
|
@ -844,11 +844,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||||
visitor.visit_expr(subexpression);
|
visitor.visit_expr(subexpression);
|
||||||
visitor.visit_block(block);
|
visitor.visit_block(block);
|
||||||
}
|
}
|
||||||
ExprKind::ForLoop(pattern, subexpression, block, opt_label) => {
|
ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
|
||||||
walk_list!(visitor, visit_label, opt_label);
|
walk_list!(visitor, visit_label, label);
|
||||||
visitor.visit_pat(pattern);
|
visitor.visit_pat(pat);
|
||||||
visitor.visit_expr(subexpression);
|
visitor.visit_expr(iter);
|
||||||
visitor.visit_block(block);
|
visitor.visit_block(body);
|
||||||
}
|
}
|
||||||
ExprKind::Loop(block, opt_label, _) => {
|
ExprKind::Loop(block, opt_label, _) => {
|
||||||
walk_list!(visitor, visit_label, opt_label);
|
walk_list!(visitor, visit_label, opt_label);
|
||||||
|
|
|
@ -56,12 +56,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
return ex;
|
return ex;
|
||||||
}
|
}
|
||||||
// Desugar `ExprForLoop`
|
// 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
|
// 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.
|
// correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.
|
||||||
ExprKind::ForLoop(pat, head, body, opt_label) => {
|
ExprKind::ForLoop { pat, iter, body, label, kind } => {
|
||||||
return self.lower_expr_for(e, pat, head, body, *opt_label);
|
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::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
|
||||||
|
|
||||||
ExprKind::Paren(_) | ExprKind::ForLoop(..) => {
|
ExprKind::Paren(_) | ExprKind::ForLoop{..} => {
|
||||||
unreachable!("already handled")
|
unreachable!("already handled")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1673,6 +1673,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
head: &Expr,
|
head: &Expr,
|
||||||
body: &Block,
|
body: &Block,
|
||||||
opt_label: Option<Label>,
|
opt_label: Option<Label>,
|
||||||
|
_loop_kind: ForLoopKind,
|
||||||
) -> hir::Expr<'hir> {
|
) -> hir::Expr<'hir> {
|
||||||
let head = self.lower_expr_mut(head);
|
let head = self.lower_expr_mut(head);
|
||||||
let pat = self.lower_pat(pat);
|
let pat = self.lower_pat(pat);
|
||||||
|
|
|
@ -526,6 +526,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
"async closures are unstable",
|
"async closures are unstable",
|
||||||
"to use an async block, remove the `||`: `async {`"
|
"to use an async block, remove the `||`: `async {`"
|
||||||
);
|
);
|
||||||
|
gate_all!(async_for_loop, "`for await` loops are experimental");
|
||||||
gate_all!(
|
gate_all!(
|
||||||
closure_lifetime_binder,
|
closure_lifetime_binder,
|
||||||
"`for<...>` binders for closures are experimental",
|
"`for<...>` binders for closures are experimental",
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::pp::Breaks::Inconsistent;
|
use crate::pp::Breaks::Inconsistent;
|
||||||
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
|
use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
|
||||||
|
use ast::ForLoopKind;
|
||||||
use itertools::{Itertools, Position};
|
use itertools::{Itertools, Position};
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token;
|
use rustc_ast::token;
|
||||||
|
@ -418,20 +419,23 @@ impl<'a> State<'a> {
|
||||||
self.space();
|
self.space();
|
||||||
self.print_block_with_attrs(blk, attrs);
|
self.print_block_with_attrs(blk, attrs);
|
||||||
}
|
}
|
||||||
ast::ExprKind::ForLoop(pat, iter, blk, opt_label) => {
|
ast::ExprKind::ForLoop { pat, iter, body, label, kind } => {
|
||||||
if let Some(label) = opt_label {
|
if let Some(label) = label {
|
||||||
self.print_ident(label.ident);
|
self.print_ident(label.ident);
|
||||||
self.word_space(":");
|
self.word_space(":");
|
||||||
}
|
}
|
||||||
self.cbox(0);
|
self.cbox(0);
|
||||||
self.ibox(0);
|
self.ibox(0);
|
||||||
self.word_nbsp("for");
|
self.word_nbsp("for");
|
||||||
|
if kind == &ForLoopKind::ForAwait {
|
||||||
|
self.word_nbsp("await");
|
||||||
|
}
|
||||||
self.print_pat(pat);
|
self.print_pat(pat);
|
||||||
self.space();
|
self.space();
|
||||||
self.word_space("in");
|
self.word_space("in");
|
||||||
self.print_expr_as_cond(iter);
|
self.print_expr_as_cond(iter);
|
||||||
self.space();
|
self.space();
|
||||||
self.print_block_with_attrs(blk, attrs);
|
self.print_block_with_attrs(body, attrs);
|
||||||
}
|
}
|
||||||
ast::ExprKind::Loop(blk, opt_label, _) => {
|
ast::ExprKind::Loop(blk, opt_label, _) => {
|
||||||
if let Some(label) = opt_label {
|
if let Some(label) = opt_label {
|
||||||
|
|
|
@ -303,7 +303,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
||||||
| ExprKind::Continue(_)
|
| ExprKind::Continue(_)
|
||||||
| ExprKind::Err
|
| ExprKind::Err
|
||||||
| ExprKind::Field(_, _)
|
| ExprKind::Field(_, _)
|
||||||
| ExprKind::ForLoop(_, _, _, _)
|
| ExprKind::ForLoop {..}
|
||||||
| ExprKind::FormatArgs(_)
|
| ExprKind::FormatArgs(_)
|
||||||
| ExprKind::IncludedBytes(..)
|
| ExprKind::IncludedBytes(..)
|
||||||
| ExprKind::InlineAsm(_)
|
| ExprKind::InlineAsm(_)
|
||||||
|
|
|
@ -357,6 +357,8 @@ declare_features! (
|
||||||
(unstable, async_closure, "1.37.0", Some(62290)),
|
(unstable, async_closure, "1.37.0", Some(62290)),
|
||||||
/// Allows `#[track_caller]` on async functions.
|
/// Allows `#[track_caller]` on async functions.
|
||||||
(unstable, async_fn_track_caller, "1.73.0", Some(110011)),
|
(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
|
/// Allows builtin # foo() syntax
|
||||||
(unstable, builtin_syntax, "1.71.0", Some(110680)),
|
(unstable, builtin_syntax, "1.71.0", Some(110680)),
|
||||||
/// Treat `extern "C"` function as nounwind.
|
/// Treat `extern "C"` function as nounwind.
|
||||||
|
|
|
@ -852,8 +852,8 @@ trait UnusedDelimLint {
|
||||||
(cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right), true)
|
(cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
ForLoop(_, ref cond, ref block, ..) => {
|
ForLoop { ref iter, ref body, .. } => {
|
||||||
(cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()), true)
|
(iter, UnusedDelimsCtx::ForIterExpr, true, None, Some(body.span.lo()), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
|
Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
|
||||||
|
@ -1085,7 +1085,7 @@ impl EarlyLintPass for UnusedParens {
|
||||||
}
|
}
|
||||||
|
|
||||||
match e.kind {
|
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));
|
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
|
// We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
|
||||||
|
|
|
@ -10,7 +10,7 @@ use super::{
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::maybe_recover_from_interpolated_ty_qpath;
|
use crate::maybe_recover_from_interpolated_ty_qpath;
|
||||||
use ast::mut_visit::{noop_visit_expr, MutVisitor};
|
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 core::mem;
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||||
|
@ -1801,7 +1801,7 @@ impl<'a> Parser<'a> {
|
||||||
&& matches!(
|
&& matches!(
|
||||||
expr.kind,
|
expr.kind,
|
||||||
ExprKind::While(_, _, None)
|
ExprKind::While(_, _, None)
|
||||||
| ExprKind::ForLoop(_, _, _, None)
|
| ExprKind::ForLoop { label: None, .. }
|
||||||
| ExprKind::Loop(_, None, _)
|
| ExprKind::Loop(_, None, _)
|
||||||
| ExprKind::Block(_, None)
|
| ExprKind::Block(_, None)
|
||||||
)
|
)
|
||||||
|
@ -2682,8 +2682,16 @@ impl<'a> Parser<'a> {
|
||||||
Ok((pat, expr))
|
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>> {
|
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()?;
|
let (pat, expr) = self.parse_for_head()?;
|
||||||
// Recover from missing expression in `for` loop
|
// Recover from missing expression in `for` loop
|
||||||
if matches!(expr.kind, ExprKind::Block(..))
|
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);
|
let block = self.mk_block(thin_vec![], BlockCheckMode::Default, self.prev_token.span);
|
||||||
return Ok(self.mk_expr(
|
return Ok(self.mk_expr(
|
||||||
lo.to(self.prev_token.span),
|
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 (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)?;
|
self.recover_loop_else("for", lo)?;
|
||||||
|
|
||||||
|
@ -3798,7 +3806,7 @@ impl MutVisitor for CondChecker<'_> {
|
||||||
| ExprKind::Lit(_)
|
| ExprKind::Lit(_)
|
||||||
| ExprKind::If(_, _, _)
|
| ExprKind::If(_, _, _)
|
||||||
| ExprKind::While(_, _, _)
|
| ExprKind::While(_, _, _)
|
||||||
| ExprKind::ForLoop(_, _, _, _)
|
| ExprKind::ForLoop { .. }
|
||||||
| ExprKind::Loop(_, _, _)
|
| ExprKind::Loop(_, _, _)
|
||||||
| ExprKind::Match(_, _)
|
| ExprKind::Match(_, _)
|
||||||
| ExprKind::Closure(_)
|
| ExprKind::Closure(_)
|
||||||
|
|
|
@ -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) => {
|
ExprKind::ForLoop { ref pat, ref iter, ref body, label, kind: _ } => {
|
||||||
self.visit_expr(iter_expr);
|
self.visit_expr(iter);
|
||||||
self.with_rib(ValueNS, RibKind::Normal, |this| {
|
self.with_rib(ValueNS, RibKind::Normal, |this| {
|
||||||
this.resolve_pattern_top(pat, PatternSource::For);
|
this.resolve_pattern_top(pat, PatternSource::For);
|
||||||
this.resolve_labeled_block(label, expr.id, block);
|
this.resolve_labeled_block(label, expr.id, body);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1409,7 +1409,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
| ExprKind::Unary(..)
|
| ExprKind::Unary(..)
|
||||||
| ExprKind::If(..)
|
| ExprKind::If(..)
|
||||||
| ExprKind::While(..)
|
| ExprKind::While(..)
|
||||||
| ExprKind::ForLoop(..)
|
| ExprKind::ForLoop { .. }
|
||||||
| ExprKind::Match(..),
|
| ExprKind::Match(..),
|
||||||
..
|
..
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -426,6 +426,7 @@ symbols! {
|
||||||
async_closure,
|
async_closure,
|
||||||
async_fn_in_trait,
|
async_fn_in_trait,
|
||||||
async_fn_track_caller,
|
async_fn_track_caller,
|
||||||
|
async_for_loop,
|
||||||
async_iterator,
|
async_iterator,
|
||||||
atomic,
|
atomic,
|
||||||
atomic_mod,
|
atomic_mod,
|
||||||
|
|
|
@ -220,7 +220,11 @@ where
|
||||||
F: FnMut(&ast::Block, Option<&ast::Label>),
|
F: FnMut(&ast::Block, Option<&ast::Label>),
|
||||||
{
|
{
|
||||||
if let ast::ExprKind::While(_, loop_block, 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
|
| ast::ExprKind::Loop(loop_block, label, ..) = &expr.kind
|
||||||
{
|
{
|
||||||
func(loop_block, label.as_ref());
|
func(loop_block, label.as_ref());
|
||||||
|
|
|
@ -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(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els),
|
||||||
ExprKind::If(_, _, None)
|
ExprKind::If(_, _, None)
|
||||||
// ignore loops for simplicity
|
// ignore loops for simplicity
|
||||||
| ExprKind::While(..) | ExprKind::ForLoop(..) | ExprKind::Loop(..) => false,
|
| ExprKind::While(..) | ExprKind::ForLoop { .. } | ExprKind::Loop(..) => false,
|
||||||
_ => {
|
_ => {
|
||||||
walk_expr(self, expr);
|
walk_expr(self, expr);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -554,7 +554,7 @@ fn ident_difference_expr_with_base_location(
|
||||||
| (Closure(_), Closure(_))
|
| (Closure(_), Closure(_))
|
||||||
| (Match(_, _), Match(_, _))
|
| (Match(_, _), Match(_, _))
|
||||||
| (Loop(_, _, _), Loop(_, _, _))
|
| (Loop(_, _, _), Loop(_, _, _))
|
||||||
| (ForLoop(_, _, _, _), ForLoop(_, _, _, _))
|
| (ForLoop { .. }, ForLoop { .. })
|
||||||
| (While(_, _, _), While(_, _, _))
|
| (While(_, _, _), While(_, _, _))
|
||||||
| (If(_, _, _), If(_, _, _))
|
| (If(_, _, _), If(_, _, _))
|
||||||
| (Let(_, _, _, _), Let(_, _, _, _))
|
| (Let(_, _, _, _), Let(_, _, _, _))
|
||||||
|
|
|
@ -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),
|
(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),
|
(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),
|
(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),
|
(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),
|
(Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb),
|
||||||
(TryBlock(l), TryBlock(r)) => eq_block(l, r),
|
(TryBlock(l), TryBlock(r)) => eq_block(l, r),
|
||||||
|
|
|
@ -197,7 +197,7 @@ impl<'a> Sugg<'a> {
|
||||||
| ast::ExprKind::Continue(..)
|
| ast::ExprKind::Continue(..)
|
||||||
| ast::ExprKind::Yield(..)
|
| ast::ExprKind::Yield(..)
|
||||||
| ast::ExprKind::Field(..)
|
| ast::ExprKind::Field(..)
|
||||||
| ast::ExprKind::ForLoop(..)
|
| ast::ExprKind::ForLoop { .. }
|
||||||
| ast::ExprKind::Index(..)
|
| ast::ExprKind::Index(..)
|
||||||
| ast::ExprKind::InlineAsm(..)
|
| ast::ExprKind::InlineAsm(..)
|
||||||
| ast::ExprKind::OffsetOf(..)
|
| ast::ExprKind::OffsetOf(..)
|
||||||
|
|
|
@ -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 {
|
fn is_block_closure_forced_inner(expr: &ast::Expr, version: Version) -> bool {
|
||||||
match expr.kind {
|
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::Loop(..) if version == Version::Two => true,
|
||||||
ast::ExprKind::AddrOf(_, _, ref expr)
|
ast::ExprKind::AddrOf(_, _, ref expr)
|
||||||
| ast::ExprKind::Try(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::Block(..)
|
||||||
| ast::ExprKind::While(..)
|
| ast::ExprKind::While(..)
|
||||||
| ast::ExprKind::Loop(..)
|
| ast::ExprKind::Loop(..)
|
||||||
| ast::ExprKind::ForLoop(..)
|
| ast::ExprKind::ForLoop { .. }
|
||||||
| ast::ExprKind::TryBlock(..) => false,
|
| ast::ExprKind::TryBlock(..) => false,
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::cmp::min;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_ast::token::{Delimiter, Lit, LitKind};
|
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 rustc_span::{BytePos, Span};
|
||||||
|
|
||||||
use crate::chains::rewrite_chain;
|
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::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr),
|
||||||
ast::ExprKind::If(..)
|
ast::ExprKind::If(..)
|
||||||
| ast::ExprKind::ForLoop(..)
|
| ast::ExprKind::ForLoop { .. }
|
||||||
| ast::ExprKind::Loop(..)
|
| ast::ExprKind::Loop(..)
|
||||||
| ast::ExprKind::While(..) => to_control_flow(expr, expr_type)
|
| ast::ExprKind::While(..) => to_control_flow(expr, expr_type)
|
||||||
.and_then(|control_flow| control_flow.rewrite(context, shape)),
|
.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,
|
expr.span,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
ast::ExprKind::ForLoop(ref pat, ref cond, ref block, label) => {
|
ast::ExprKind::ForLoop {
|
||||||
Some(ControlFlow::new_for(pat, cond, block, label, expr.span))
|
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, _) => {
|
ast::ExprKind::Loop(ref block, label, _) => {
|
||||||
Some(ControlFlow::new_loop(block, label, expr.span))
|
Some(ControlFlow::new_loop(block, label, expr.span))
|
||||||
}
|
}
|
||||||
|
@ -771,6 +777,7 @@ impl<'a> ControlFlow<'a> {
|
||||||
block: &'a ast::Block,
|
block: &'a ast::Block,
|
||||||
label: Option<ast::Label>,
|
label: Option<ast::Label>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
kind: ForLoopKind,
|
||||||
) -> ControlFlow<'a> {
|
) -> ControlFlow<'a> {
|
||||||
ControlFlow {
|
ControlFlow {
|
||||||
cond: Some(cond),
|
cond: Some(cond),
|
||||||
|
@ -778,7 +785,10 @@ impl<'a> ControlFlow<'a> {
|
||||||
else_block: None,
|
else_block: None,
|
||||||
label,
|
label,
|
||||||
pat: Some(pat),
|
pat: Some(pat),
|
||||||
keyword: "for",
|
keyword: match kind {
|
||||||
|
ForLoopKind::For => "for",
|
||||||
|
ForLoopKind::ForAwait => "for await",
|
||||||
|
},
|
||||||
matcher: "",
|
matcher: "",
|
||||||
connector: " in",
|
connector: " in",
|
||||||
allow_single_line: false,
|
allow_single_line: false,
|
||||||
|
@ -1364,7 +1374,7 @@ pub(crate) fn can_be_overflowed_expr(
|
||||||
|| context.config.overflow_delimited_expr()
|
|| context.config.overflow_delimited_expr()
|
||||||
}
|
}
|
||||||
ast::ExprKind::If(..)
|
ast::ExprKind::If(..)
|
||||||
| ast::ExprKind::ForLoop(..)
|
| ast::ExprKind::ForLoop { .. }
|
||||||
| ast::ExprKind::Loop(..)
|
| ast::ExprKind::Loop(..)
|
||||||
| ast::ExprKind::While(..) => {
|
| ast::ExprKind::While(..) => {
|
||||||
context.config.combine_control_expr() && context.use_block_indent() && args_len == 1
|
context.config.combine_control_expr() && context.use_block_indent() && args_len == 1
|
||||||
|
|
|
@ -591,7 +591,7 @@ fn can_flatten_block_around_this(body: &ast::Expr) -> bool {
|
||||||
ast::ExprKind::If(..) => false,
|
ast::ExprKind::If(..) => false,
|
||||||
// We do not allow collapsing a block around expression with condition
|
// We do not allow collapsing a block around expression with condition
|
||||||
// to avoid it being cluttered with match arm.
|
// 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::Loop(..)
|
||||||
| ast::ExprKind::Match(..)
|
| ast::ExprKind::Match(..)
|
||||||
| ast::ExprKind::Block(..)
|
| ast::ExprKind::Block(..)
|
||||||
|
|
|
@ -409,7 +409,7 @@ impl<'a> Context<'a> {
|
||||||
// When overflowing the expressions which consists of a control flow
|
// When overflowing the expressions which consists of a control flow
|
||||||
// expression, avoid condition to use multi line.
|
// expression, avoid condition to use multi line.
|
||||||
ast::ExprKind::If(..)
|
ast::ExprKind::If(..)
|
||||||
| ast::ExprKind::ForLoop(..)
|
| ast::ExprKind::ForLoop { .. }
|
||||||
| ast::ExprKind::Loop(..)
|
| ast::ExprKind::Loop(..)
|
||||||
| ast::ExprKind::While(..)
|
| ast::ExprKind::While(..)
|
||||||
| ast::ExprKind::Match(..) => {
|
| ast::ExprKind::Match(..) => {
|
||||||
|
|
|
@ -295,7 +295,7 @@ pub(crate) fn semicolon_for_stmt(
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
ast::StmtKind::Semi(ref expr) => match expr.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
|
false
|
||||||
}
|
}
|
||||||
ast::ExprKind::Break(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Ret(..) => {
|
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::ConstBlock(..)
|
||||||
| ast::ExprKind::Gen(..)
|
| ast::ExprKind::Gen(..)
|
||||||
| ast::ExprKind::Loop(..)
|
| ast::ExprKind::Loop(..)
|
||||||
| ast::ExprKind::ForLoop(..)
|
| ast::ExprKind::ForLoop { .. }
|
||||||
| ast::ExprKind::TryBlock(..)
|
| ast::ExprKind::TryBlock(..)
|
||||||
| ast::ExprKind::Match(..) => repr.contains('\n'),
|
| ast::ExprKind::Match(..) => repr.contains('\n'),
|
||||||
ast::ExprKind::Paren(ref expr)
|
ast::ExprKind::Paren(ref expr)
|
||||||
|
|
14
tests/ui/async-await/feature-async-for-loop.rs
Normal file
14
tests/ui/async-await/feature-async-for-loop.rs
Normal file
|
@ -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() {}
|
11
tests/ui/async-await/feature-async-for-loop.stderr
Normal file
11
tests/ui/async-await/feature-async-for-loop.stderr
Normal file
|
@ -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`.
|
Loading…
Add table
Add a link
Reference in a new issue