Skip to content

Commit 3688e9a

Browse files
committed
Add classify::expr_requires_comma_to_be_match_arm
1 parent 082de5e commit 3688e9a

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
@@ -511,22 +511,19 @@ impl<'a> Parser<'a> {
511511
/// If $e is something like `{}` or `if … {}`, then terminate the current
512512
/// arm and parse a new arm.
513513
fn expr_is_complete(&self, e: &Expr) -> bool {
514+
// Surprising special case: even though braced macro calls like
515+
// `m! {}` normally introduce a statement boundary when found at
516+
// the head of a statement, in match arms they do not terminate
517+
// the arm.
518+
//
519+
// let _ = { m! {} () }; // macro call followed by unit
520+
//
521+
// match ... {
522+
// _ => m! {} (), // macro that expands to a function, which is then called
523+
// }
524+
//
514525
self.restrictions.contains(Restrictions::STMT_EXPR)
515-
&& match e.kind {
516-
// Surprising special case: even though braced macro calls like
517-
// `m! {}` normally introduce a statement boundary when found at
518-
// the head of a statement, in match arms they do not terminate
519-
// the arm.
520-
//
521-
// let _ = { m! {} () }; // macro call followed by unit
522-
//
523-
// match ... {
524-
// _ => m! {} (), // macro that expands to a function, which is then called
525-
// }
526-
//
527-
ExprKind::MacCall(_) => false,
528-
_ => !classify::expr_requires_semi_to_be_stmt(e),
529-
}
526+
&& !classify::expr_requires_comma_to_be_match_arm(e)
530527
}
531528

532529
/// Parses `x..y`, `x..=y`, and `x..`/`x..=`.
@@ -3181,21 +3178,19 @@ impl<'a> Parser<'a> {
31813178
err
31823179
})?;
31833180

3184-
let require_comma = match expr.kind {
3185-
// Special case: braced macro calls require comma in a match
3186-
// arm, even though they do not require semicolon in a
3187-
// statement.
3188-
//
3189-
// m! {} // okay without semicolon
3190-
//
3191-
// match ... {
3192-
// _ => m! {}, // requires comma
3193-
// _ => ...
3194-
// }
3195-
//
3196-
ExprKind::MacCall(_) => true,
3197-
_ => classify::expr_requires_semi_to_be_stmt(&expr),
3198-
} && this.token != token::CloseDelim(Delimiter::Brace);
3181+
// Special case: braced macro calls require comma in a match
3182+
// arm, even though they do not require semicolon in a
3183+
// statement.
3184+
//
3185+
// m! {} // okay without semicolon
3186+
//
3187+
// match ... {
3188+
// _ => m! {}, // requires comma
3189+
// _ => ...
3190+
// }
3191+
//
3192+
let require_comma = classify::expr_requires_comma_to_be_match_arm(&expr)
3193+
&& this.token != token::CloseDelim(Delimiter::Brace);
31993194

32003195
if !require_comma {
32013196
arm_body = Some(expr);

0 commit comments

Comments
 (0)