Disallow an arm without a body (except for never patterns)
Parsing now accepts a match arm without a body, so we must make sure to only accept that if the pattern is a never pattern.
This commit is contained in:
parent
0bfebc6105
commit
a2dcb3a6d9
@ -659,8 +659,8 @@ pub fn is_rest(&self) -> bool {
|
|||||||
matches!(self.kind, PatKind::Rest)
|
matches!(self.kind, PatKind::Rest)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Could this be a never pattern? I.e. is it a never pattern modulo macro invocations that
|
/// Whether this could be a never pattern, taking into account that a macro invocation can
|
||||||
/// might return never patterns?
|
/// return a never pattern. Used to inform errors during parsing.
|
||||||
pub fn could_be_never_pattern(&self) -> bool {
|
pub fn could_be_never_pattern(&self) -> bool {
|
||||||
let mut could_be_never_pattern = false;
|
let mut could_be_never_pattern = false;
|
||||||
self.walk(&mut |pat| match &pat.kind {
|
self.walk(&mut |pat| match &pat.kind {
|
||||||
|
@ -91,6 +91,10 @@ ast_lowering_invalid_register =
|
|||||||
ast_lowering_invalid_register_class =
|
ast_lowering_invalid_register_class =
|
||||||
invalid register class `{$reg_class}`: {$error}
|
invalid register class `{$reg_class}`: {$error}
|
||||||
|
|
||||||
|
ast_lowering_match_arm_with_no_body =
|
||||||
|
`match` arm with no body
|
||||||
|
.suggestion = add a body after the pattern
|
||||||
|
|
||||||
ast_lowering_misplaced_assoc_ty_binding =
|
ast_lowering_misplaced_assoc_ty_binding =
|
||||||
associated type bounds are only allowed in where clauses and function signatures, not in {$position}
|
associated type bounds are only allowed in where clauses and function signatures, not in {$position}
|
||||||
|
|
||||||
|
@ -340,6 +340,15 @@ pub struct NotSupportedForLifetimeBinderAsyncClosure {
|
|||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(ast_lowering_match_arm_with_no_body)]
|
||||||
|
pub struct MatchArmWithNoBody {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[suggestion(code = " => todo!(),", applicability = "has-placeholders")]
|
||||||
|
pub suggestion: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic, Clone, Copy)]
|
#[derive(Diagnostic, Clone, Copy)]
|
||||||
#[diag(ast_lowering_arbitrary_expression_in_pattern)]
|
#[diag(ast_lowering_arbitrary_expression_in_pattern)]
|
||||||
pub struct ArbitraryExpressionInPattern {
|
pub struct ArbitraryExpressionInPattern {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::errors::{
|
use super::errors::{
|
||||||
AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
|
AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
|
||||||
BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters,
|
BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters,
|
||||||
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd,
|
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
|
||||||
NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign,
|
NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign,
|
||||||
};
|
};
|
||||||
use super::ResolverAstLoweringExt;
|
use super::ResolverAstLoweringExt;
|
||||||
@ -565,14 +565,21 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
let hir_id = self.next_id();
|
let hir_id = self.next_id();
|
||||||
|
let span = self.lower_span(arm.span);
|
||||||
self.lower_attrs(hir_id, &arm.attrs);
|
self.lower_attrs(hir_id, &arm.attrs);
|
||||||
let body = if let Some(body) = &arm.body {
|
let body = if let Some(body) = &arm.body {
|
||||||
|
// FIXME(never_patterns): Disallow never pattern with a body or guard
|
||||||
self.lower_expr(body)
|
self.lower_expr(body)
|
||||||
} else {
|
} else {
|
||||||
|
if !pat.is_never_pattern() {
|
||||||
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.emit_err(MatchArmWithNoBody { span, suggestion: span.shrink_to_hi() });
|
||||||
|
}
|
||||||
|
|
||||||
// An arm without a body, meant for never patterns.
|
// An arm without a body, meant for never patterns.
|
||||||
// We add a fake `loop {}` arm body so that it typecks to `!`.
|
// We add a fake `loop {}` arm body so that it typecks to `!`.
|
||||||
// FIXME(never_patterns): Desugar into a call to `unreachable_unchecked`.
|
// FIXME(never_patterns): Desugar into a call to `unreachable_unchecked`.
|
||||||
let span = pat.span;
|
|
||||||
let block = self.arena.alloc(hir::Block {
|
let block = self.arena.alloc(hir::Block {
|
||||||
stmts: &[],
|
stmts: &[],
|
||||||
expr: None,
|
expr: None,
|
||||||
@ -587,7 +594,7 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
|
|||||||
span,
|
span,
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
hir::Arm { hir_id, pat, guard, body, span: self.lower_span(arm.span) }
|
hir::Arm { hir_id, pat, guard, body, span }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lower an `async` construct to a coroutine that implements `Future`.
|
/// Lower an `async` construct to a coroutine that implements `Future`.
|
||||||
|
@ -1055,6 +1055,23 @@ pub fn walk_always(&self, mut it: impl FnMut(&Pat<'_>)) {
|
|||||||
true
|
true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether this a never pattern.
|
||||||
|
pub fn is_never_pattern(&self) -> bool {
|
||||||
|
let mut is_never_pattern = false;
|
||||||
|
self.walk(|pat| match &pat.kind {
|
||||||
|
PatKind::Never => {
|
||||||
|
is_never_pattern = true;
|
||||||
|
false
|
||||||
|
}
|
||||||
|
PatKind::Or(s) => {
|
||||||
|
is_never_pattern = s.iter().all(|p| p.is_never_pattern());
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
});
|
||||||
|
is_never_pattern
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single field in a struct pattern.
|
/// A single field in a struct pattern.
|
||||||
|
@ -13,6 +13,7 @@ fn main() {
|
|||||||
Some(1) => {},
|
Some(1) => {},
|
||||||
arm!(None => {}),
|
arm!(None => {}),
|
||||||
//~^ NOTE caused by the macro expansion here
|
//~^ NOTE caused by the macro expansion here
|
||||||
|
//~| ERROR `match` arm with no body
|
||||||
Some(2) => {},
|
Some(2) => {},
|
||||||
_ => {},
|
_ => {},
|
||||||
};
|
};
|
||||||
|
@ -10,5 +10,11 @@ LL | arm!(None => {}),
|
|||||||
= note: the usage of `arm!` is likely invalid in pattern context
|
= note: the usage of `arm!` is likely invalid in pattern context
|
||||||
= note: macros cannot expand to match arms
|
= note: macros cannot expand to match arms
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: `match` arm with no body
|
||||||
|
--> $DIR/macro-expand-to-match-arm.rs:14:9
|
||||||
|
|
|
||||||
|
LL | arm!(None => {}),
|
||||||
|
| ^^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ macro_rules! pat {
|
|||||||
fn main() {
|
fn main() {
|
||||||
match Some(false) {
|
match Some(false) {
|
||||||
Some(_)
|
Some(_)
|
||||||
|
//~^ ERROR `match` arm with no body
|
||||||
|
//~| HELP add a body after the pattern
|
||||||
}
|
}
|
||||||
match Some(false) {
|
match Some(false) {
|
||||||
Some(_)
|
Some(_)
|
||||||
@ -26,6 +28,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
match Some(false) {
|
match Some(false) {
|
||||||
Some(_) if true
|
Some(_) if true
|
||||||
|
//~^ ERROR `match` arm with no body
|
||||||
|
//~| HELP add a body after the pattern
|
||||||
}
|
}
|
||||||
match Some(false) {
|
match Some(false) {
|
||||||
Some(_) if true
|
Some(_) if true
|
||||||
@ -34,28 +38,42 @@ fn main() {
|
|||||||
}
|
}
|
||||||
match Some(false) {
|
match Some(false) {
|
||||||
Some(_) if true,
|
Some(_) if true,
|
||||||
|
//~^ ERROR `match` arm with no body
|
||||||
|
//~| HELP add a body after the pattern
|
||||||
}
|
}
|
||||||
match Some(false) {
|
match Some(false) {
|
||||||
Some(_) if true,
|
Some(_) if true,
|
||||||
|
//~^ ERROR `match` arm with no body
|
||||||
|
//~| HELP add a body after the pattern
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
match Some(false) {
|
match Some(false) {
|
||||||
pat!()
|
pat!()
|
||||||
|
//~^ ERROR `match` arm with no body
|
||||||
|
//~| HELP add a body after the pattern
|
||||||
}
|
}
|
||||||
match Some(false) {
|
match Some(false) {
|
||||||
pat!(),
|
pat!(),
|
||||||
|
//~^ ERROR `match` arm with no body
|
||||||
|
//~| HELP add a body after the pattern
|
||||||
}
|
}
|
||||||
match Some(false) {
|
match Some(false) {
|
||||||
pat!() if true,
|
pat!() if true,
|
||||||
|
//~^ ERROR `match` arm with no body
|
||||||
|
//~| HELP add a body after the pattern
|
||||||
}
|
}
|
||||||
match Some(false) {
|
match Some(false) {
|
||||||
pat!()
|
pat!()
|
||||||
//~^ ERROR expected `,` following `match` arm
|
//~^ ERROR expected `,` following `match` arm
|
||||||
//~| HELP missing a comma here
|
//~| HELP missing a comma here
|
||||||
|
//~| ERROR `match` arm with no body
|
||||||
|
//~| HELP add a body after the pattern
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
match Some(false) {
|
match Some(false) {
|
||||||
pat!(),
|
pat!(),
|
||||||
|
//~^ ERROR `match` arm with no body
|
||||||
|
//~| HELP add a body after the pattern
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: expected one of `,`, `=>`, `if`, `|`, or `}`, found reserved identifier `_`
|
error: expected one of `,`, `=>`, `if`, `|`, or `}`, found reserved identifier `_`
|
||||||
--> $DIR/match-arm-without-body.rs:11:9
|
--> $DIR/match-arm-without-body.rs:13:9
|
||||||
|
|
|
|
||||||
LL | Some(_)
|
LL | Some(_)
|
||||||
| - expected one of `,`, `=>`, `if`, `|`, or `}`
|
| - expected one of `,`, `=>`, `if`, `|`, or `}`
|
||||||
@ -7,7 +7,7 @@ LL | _ => {}
|
|||||||
| ^ unexpected token
|
| ^ unexpected token
|
||||||
|
|
||||||
error: unexpected `,` in pattern
|
error: unexpected `,` in pattern
|
||||||
--> $DIR/match-arm-without-body.rs:15:16
|
--> $DIR/match-arm-without-body.rs:17:16
|
||||||
|
|
|
|
||||||
LL | Some(_),
|
LL | Some(_),
|
||||||
| ^
|
| ^
|
||||||
@ -22,7 +22,7 @@ LL | Some(_) |
|
|||||||
|
|
|
|
||||||
|
|
||||||
error: unexpected `,` in pattern
|
error: unexpected `,` in pattern
|
||||||
--> $DIR/match-arm-without-body.rs:21:16
|
--> $DIR/match-arm-without-body.rs:23:16
|
||||||
|
|
|
|
||||||
LL | Some(_),
|
LL | Some(_),
|
||||||
| ^
|
| ^
|
||||||
@ -45,7 +45,7 @@ LL ~ _ => {}
|
|||||||
|
|
|
|
||||||
|
|
||||||
error: expected one of `,`, `.`, `=>`, `?`, `}`, or an operator, found reserved identifier `_`
|
error: expected one of `,`, `.`, `=>`, `?`, `}`, or an operator, found reserved identifier `_`
|
||||||
--> $DIR/match-arm-without-body.rs:32:9
|
--> $DIR/match-arm-without-body.rs:36:9
|
||||||
|
|
|
|
||||||
LL | Some(_) if true
|
LL | Some(_) if true
|
||||||
| - expected one of `,`, `.`, `=>`, `?`, `}`, or an operator
|
| - expected one of `,`, `.`, `=>`, `?`, `}`, or an operator
|
||||||
@ -53,10 +53,64 @@ LL | _ => {}
|
|||||||
| ^ unexpected token
|
| ^ unexpected token
|
||||||
|
|
||||||
error: expected `,` following `match` arm
|
error: expected `,` following `match` arm
|
||||||
--> $DIR/match-arm-without-body.rs:52:15
|
--> $DIR/match-arm-without-body.rs:66:15
|
||||||
|
|
|
|
||||||
LL | pat!()
|
LL | pat!()
|
||||||
| ^ help: missing a comma here to end this `match` arm: `,`
|
| ^ help: missing a comma here to end this `match` arm: `,`
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error: `match` arm with no body
|
||||||
|
--> $DIR/match-arm-without-body.rs:7:9
|
||||||
|
|
|
||||||
|
LL | Some(_)
|
||||||
|
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
|
||||||
|
|
||||||
|
error: `match` arm with no body
|
||||||
|
--> $DIR/match-arm-without-body.rs:30:9
|
||||||
|
|
|
||||||
|
LL | Some(_) if true
|
||||||
|
| ^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
|
||||||
|
|
||||||
|
error: `match` arm with no body
|
||||||
|
--> $DIR/match-arm-without-body.rs:40:9
|
||||||
|
|
|
||||||
|
LL | Some(_) if true,
|
||||||
|
| ^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
|
||||||
|
|
||||||
|
error: `match` arm with no body
|
||||||
|
--> $DIR/match-arm-without-body.rs:45:9
|
||||||
|
|
|
||||||
|
LL | Some(_) if true,
|
||||||
|
| ^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
|
||||||
|
|
||||||
|
error: `match` arm with no body
|
||||||
|
--> $DIR/match-arm-without-body.rs:51:9
|
||||||
|
|
|
||||||
|
LL | pat!()
|
||||||
|
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
|
||||||
|
|
||||||
|
error: `match` arm with no body
|
||||||
|
--> $DIR/match-arm-without-body.rs:56:9
|
||||||
|
|
|
||||||
|
LL | pat!(),
|
||||||
|
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
|
||||||
|
|
||||||
|
error: `match` arm with no body
|
||||||
|
--> $DIR/match-arm-without-body.rs:61:9
|
||||||
|
|
|
||||||
|
LL | pat!() if true,
|
||||||
|
| ^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
|
||||||
|
|
||||||
|
error: `match` arm with no body
|
||||||
|
--> $DIR/match-arm-without-body.rs:66:9
|
||||||
|
|
|
||||||
|
LL | pat!()
|
||||||
|
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
|
||||||
|
|
||||||
|
error: `match` arm with no body
|
||||||
|
--> $DIR/match-arm-without-body.rs:74:9
|
||||||
|
|
|
||||||
|
LL | pat!(),
|
||||||
|
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
|
||||||
|
|
||||||
|
error: aborting due to 14 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user