Skip to content

Commit 5d5954c

Browse files
committed
Add classify::expr_requires_comma_to_be_match_arm
1 parent 53521fa commit 5d5954c

File tree

2 files changed

+52
-51
lines changed

2 files changed

+52
-51
lines changed

compiler/rustc_ast/src/util/classify.rs

+27-21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Routines the parser and pretty-printer use to classify AST nodes.
22
3+
use crate::ast::ExprKind::*;
34
use crate::{ast, token::Delimiter};
45

56
/// Does this expression require a semicolon to be treated as a statement?
@@ -14,9 +15,27 @@ use crate::{ast, token::Delimiter};
1415
/// ```
1516
///
1617
/// isn't parsed as `(if true {...} else {...} | x) | 5`.
18+
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
19+
match &e.kind {
20+
If(..)
21+
| Match(..)
22+
| Block(..)
23+
| While(..)
24+
| Loop(..)
25+
| ForLoop { .. }
26+
| TryBlock(..)
27+
| ConstBlock(..) => false,
28+
29+
MacCall(mac_call) => mac_call.args.delim != Delimiter::Brace,
30+
31+
_ => true,
32+
}
33+
}
34+
35+
/// Does this expression require a comma to separate it from the next match arm?
1736
///
18-
/// Nearly the same early bail-out also occurs in the right-hand side of match
19-
/// arms:
37+
/// The right-hand side of match arms use almost the same early bail-out as
38+
/// statements do (see `expr_requires_semi_to_be_stmt`):
2039
///
2140
/// ```ignore (illustrative)
2241
/// match i {
@@ -27,8 +46,9 @@ use crate::{ast, token::Delimiter};
2746
///
2847
/// Here the `|` is a leading vert in a second match arm. It is not a binary
2948
/// operator with the If as its left operand. If the first arm were some other
30-
/// expression for which `expr_requires_semi_to_be_stmt` returns true, then the
31-
/// `|` on the next line would be a binary operator (leading to a parse error).
49+
/// expression for which `expr_requires_comma_to_be_match_arm` returns true,
50+
/// then the `|` on the next line would instead be a binary operator (leading to
51+
/// a parse error).
3252
///
3353
/// The statement case and the match-arm case are "nearly" the same early
3454
/// bail-out because of 1 edge case. Macro calls with brace delimiter terminate
@@ -42,29 +62,15 @@ use crate::{ast, token::Delimiter};
4262
/// _ => m! {} - 1, // binary subtraction operator
4363
/// }
4464
/// ```
45-
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
46-
use ast::ExprKind::*;
47-
65+
pub fn expr_requires_comma_to_be_match_arm(e: &ast::Expr) -> bool {
4866
match &e.kind {
49-
If(..)
50-
| Match(..)
51-
| Block(..)
52-
| While(..)
53-
| Loop(..)
54-
| ForLoop { .. }
55-
| TryBlock(..)
56-
| ConstBlock(..) => false,
57-
58-
MacCall(mac_call) => mac_call.args.delim != Delimiter::Brace,
59-
60-
_ => true,
67+
MacCall(_) => true,
68+
_ => expr_requires_semi_to_be_stmt(e),
6169
}
6270
}
6371

6472
/// If an expression ends with `}`, returns the innermost expression ending in the `}`
6573
pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
66-
use ast::ExprKind::*;
67-
6874
loop {
6975
match &expr.kind {
7076
AddrOf(_, _, e)

compiler/rustc_parse/src/parser/expr.rs

+25-30
Original file line numberDiff line numberDiff line change
@@ -525,22 +525,19 @@ impl<'a> Parser<'a> {
525525
/// If $e is something like `{}` or `if … {}`, then terminate the current
526526
/// arm and parse a new arm.
527527
fn expr_is_complete(&self, e: &Expr) -> bool {
528+
// Surprising special case: even though braced macro calls like
529+
// `m! {}` normally introduce a statement boundary when found at
530+
// the head of a statement, in match arms they do not terminate
531+
// the arm.
532+
//
533+
// let _ = { m! {} () }; // macro call followed by unit
534+
//
535+
// match ... {
536+
// _ => m! {} (), // macro that expands to a function, which is then called
537+
// }
538+
//
528539
self.restrictions.contains(Restrictions::STMT_EXPR)
529-
&& match e.kind {
530-
// Surprising special case: even though braced macro calls like
531-
// `m! {}` normally introduce a statement boundary when found at
532-
// the head of a statement, in match arms they do not terminate
533-
// the arm.
534-
//
535-
// let _ = { m! {} () }; // macro call followed by unit
536-
//
537-
// match ... {
538-
// _ => m! {} (), // macro that expands to a function, which is then called
539-
// }
540-
//
541-
ExprKind::MacCall(_) => false,
542-
_ => !classify::expr_requires_semi_to_be_stmt(e),
543-
}
540+
&& !classify::expr_requires_comma_to_be_match_arm(e)
544541
}
545542

546543
/// Parses `x..y`, `x..=y`, and `x..`/`x..=`.
@@ -3203,21 +3200,19 @@ impl<'a> Parser<'a> {
32033200
err
32043201
})?;
32053202

3206-
let require_comma = match expr.kind {
3207-
// Special case: braced macro calls require comma in a match
3208-
// arm, even though they do not require semicolon in a
3209-
// statement.
3210-
//
3211-
// m! {} // okay without semicolon
3212-
//
3213-
// match ... {
3214-
// _ => m! {}, // requires comma
3215-
// _ => ...
3216-
// }
3217-
//
3218-
ExprKind::MacCall(_) => true,
3219-
_ => classify::expr_requires_semi_to_be_stmt(&expr),
3220-
} && this.token != token::CloseDelim(Delimiter::Brace);
3203+
// Special case: braced macro calls require comma in a match
3204+
// arm, even though they do not require semicolon in a
3205+
// statement.
3206+
//
3207+
// m! {} // okay without semicolon
3208+
//
3209+
// match ... {
3210+
// _ => m! {}, // requires comma
3211+
// _ => ...
3212+
// }
3213+
//
3214+
let require_comma = classify::expr_requires_comma_to_be_match_arm(&expr)
3215+
&& this.token != token::CloseDelim(Delimiter::Brace);
32213216

32223217
if !require_comma {
32233218
arm_body = Some(expr);

0 commit comments

Comments
 (0)