Skip to content

Commit 97c3433

Browse files
committed
Parse a pattern with no arm
1 parent caa488b commit 97c3433

31 files changed

+398
-266
lines changed

compiler/rustc_ast/src/ast.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,24 @@ impl Pat {
658658
pub fn is_rest(&self) -> bool {
659659
matches!(self.kind, PatKind::Rest)
660660
}
661+
662+
/// Could this be a never pattern? I.e. is it a never pattern modulo macro invocations that
663+
/// might return never patterns?
664+
pub fn could_be_never_pattern(&self) -> bool {
665+
let mut could_be_never_pattern = false;
666+
self.walk(&mut |pat| match &pat.kind {
667+
PatKind::Never | PatKind::MacCall(_) => {
668+
could_be_never_pattern = true;
669+
false
670+
}
671+
PatKind::Or(s) => {
672+
could_be_never_pattern = s.iter().all(|p| p.could_be_never_pattern());
673+
false
674+
}
675+
_ => true,
676+
});
677+
could_be_never_pattern
678+
}
661679
}
662680

663681
/// A single field in a struct pattern.
@@ -1080,8 +1098,8 @@ pub struct Arm {
10801098
pub pat: P<Pat>,
10811099
/// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`
10821100
pub guard: Option<P<Expr>>,
1083-
/// Match arm body.
1084-
pub body: P<Expr>,
1101+
/// Match arm body. Omitted if the pattern is a never pattern.
1102+
pub body: Option<P<Expr>>,
10851103
pub span: Span,
10861104
pub id: NodeId,
10871105
pub is_placeholder: bool,

compiler/rustc_ast/src/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
453453
vis.visit_id(id);
454454
vis.visit_pat(pat);
455455
visit_opt(guard, |guard| vis.visit_expr(guard));
456-
vis.visit_expr(body);
456+
visit_opt(body, |body| vis.visit_expr(body));
457457
vis.visit_span(span);
458458
smallvec![arm]
459459
}

compiler/rustc_ast/src/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,7 @@ pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) {
951951
pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
952952
visitor.visit_pat(&arm.pat);
953953
walk_list!(visitor, visit_expr, &arm.guard);
954-
visitor.visit_expr(&arm.body);
954+
walk_list!(visitor, visit_expr, &arm.body);
955955
walk_list!(visitor, visit_attribute, &arm.attrs);
956956
}
957957

compiler/rustc_ast_lowering/src/expr.rs

+22-7
Original file line numberDiff line numberDiff line change
@@ -566,13 +566,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
566566
});
567567
let hir_id = self.next_id();
568568
self.lower_attrs(hir_id, &arm.attrs);
569-
hir::Arm {
570-
hir_id,
571-
pat,
572-
guard,
573-
body: self.lower_expr(&arm.body),
574-
span: self.lower_span(arm.span),
575-
}
569+
let body = if let Some(body) = &arm.body {
570+
self.lower_expr(body)
571+
} else {
572+
// An arm without a body, meant for never patterns.
573+
// We add a fake `loop {}` arm body so that it typecks to `!`.
574+
// FIXME(never_patterns): Desugar into a call to `unreachable_unchecked`.
575+
let span = pat.span;
576+
let block = self.arena.alloc(hir::Block {
577+
stmts: &[],
578+
expr: None,
579+
hir_id: self.next_id(),
580+
rules: hir::BlockCheckMode::DefaultBlock,
581+
span,
582+
targeted_by_break: false,
583+
});
584+
self.arena.alloc(hir::Expr {
585+
hir_id: self.next_id(),
586+
kind: hir::ExprKind::Loop(block, None, hir::LoopSource::Loop, span),
587+
span,
588+
})
589+
};
590+
hir::Arm { hir_id, pat, guard, body, span: self.lower_span(arm.span) }
576591
}
577592

578593
/// Lower an `async` construct to a coroutine that implements `Future`.

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

+21-16
Original file line numberDiff line numberDiff line change
@@ -631,28 +631,33 @@ impl<'a> State<'a> {
631631
self.print_expr(e);
632632
self.space();
633633
}
634-
self.word_space("=>");
635634

636-
match &arm.body.kind {
637-
ast::ExprKind::Block(blk, opt_label) => {
638-
if let Some(label) = opt_label {
639-
self.print_ident(label.ident);
640-
self.word_space(":");
641-
}
635+
if let Some(body) = &arm.body {
636+
self.word_space("=>");
637+
638+
match &body.kind {
639+
ast::ExprKind::Block(blk, opt_label) => {
640+
if let Some(label) = opt_label {
641+
self.print_ident(label.ident);
642+
self.word_space(":");
643+
}
642644

643-
// The block will close the pattern's ibox.
644-
self.print_block_unclosed_indent(blk);
645+
// The block will close the pattern's ibox.
646+
self.print_block_unclosed_indent(blk);
645647

646-
// If it is a user-provided unsafe block, print a comma after it.
647-
if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
648+
// If it is a user-provided unsafe block, print a comma after it.
649+
if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
650+
self.word(",");
651+
}
652+
}
653+
_ => {
654+
self.end(); // Close the ibox for the pattern.
655+
self.print_expr(body);
648656
self.word(",");
649657
}
650658
}
651-
_ => {
652-
self.end(); // Close the ibox for the pattern.
653-
self.print_expr(&arm.body);
654-
self.word(",");
655-
}
659+
} else {
660+
self.word(",");
656661
}
657662
self.end(); // Close enclosing cbox.
658663
}

compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ fn cs_partial_cmp(
136136
&& let Some(last) = arms.last_mut()
137137
&& let PatKind::Wild = last.pat.kind
138138
{
139-
last.body = expr2;
139+
last.body = Some(expr2);
140140
expr1
141141
} else {
142142
let eq_arm = cx.arm(

compiler/rustc_expand/src/build.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ impl<'a> ExtCtxt<'a> {
505505
attrs: AttrVec::new(),
506506
pat,
507507
guard: None,
508-
body: expr,
508+
body: Some(expr),
509509
span,
510510
id: ast::DUMMY_NODE_ID,
511511
is_placeholder: false,

compiler/rustc_expand/src/placeholders.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ pub fn placeholder(
119119
}]),
120120
AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm {
121121
attrs: Default::default(),
122-
body: expr_placeholder(),
122+
body: Some(expr_placeholder()),
123123
guard: None,
124124
id,
125125
pat: pat(),

compiler/rustc_lint/src/builtin.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1000,8 +1000,10 @@ impl EarlyLintPass for UnusedDocComment {
10001000
}
10011001

10021002
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
1003-
let arm_span = arm.pat.span.with_hi(arm.body.span.hi());
1004-
warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
1003+
if let Some(body) = &arm.body {
1004+
let arm_span = arm.pat.span.with_hi(body.span.hi());
1005+
warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
1006+
}
10051007
}
10061008

10071009
fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {

compiler/rustc_lint/src/unused.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -1113,15 +1113,17 @@ impl EarlyLintPass for UnusedParens {
11131113
}
11141114
ExprKind::Match(ref _expr, ref arm) => {
11151115
for a in arm {
1116-
self.check_unused_delims_expr(
1117-
cx,
1118-
&a.body,
1119-
UnusedDelimsCtx::MatchArmExpr,
1120-
false,
1121-
None,
1122-
None,
1123-
true,
1124-
);
1116+
if let Some(body) = &a.body {
1117+
self.check_unused_delims_expr(
1118+
cx,
1119+
body,
1120+
UnusedDelimsCtx::MatchArmExpr,
1121+
false,
1122+
None,
1123+
None,
1124+
true,
1125+
);
1126+
}
11251127
}
11261128
}
11271129
_ => {}

0 commit comments

Comments
 (0)