parent
795a934b51
commit
ae494d147a
4 changed files with 334 additions and 1 deletions
|
@ -1973,6 +1973,102 @@ impl<'a> Parser<'a> {
|
||||||
Ok(self.mk_expr(lo.to(hi), ExprKind::Match(scrutinee, arms), attrs))
|
Ok(self.mk_expr(lo.to(hi), ExprKind::Match(scrutinee, arms), attrs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempt to recover from match arm body with statements and no surrounding braces.
|
||||||
|
fn parse_arm_body_missing_braces(
|
||||||
|
&mut self,
|
||||||
|
first_expr: &P<Expr>,
|
||||||
|
arrow_span: Span,
|
||||||
|
) -> Option<P<Expr>> {
|
||||||
|
if self.token.kind != token::Semi {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let start_snapshot = self.clone();
|
||||||
|
let semi_sp = self.token.span;
|
||||||
|
self.bump(); // `;`
|
||||||
|
let mut stmts =
|
||||||
|
vec![self.mk_stmt(first_expr.span, ast::StmtKind::Expr(first_expr.clone()))];
|
||||||
|
let err = |this: &mut Parser<'_>, stmts: Vec<ast::Stmt>| {
|
||||||
|
let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
|
||||||
|
let mut err = this.struct_span_err(span, "`match` arm body without braces");
|
||||||
|
let (these, s, are) =
|
||||||
|
if stmts.len() > 1 { ("these", "s", "are") } else { ("this", "", "is") };
|
||||||
|
err.span_label(
|
||||||
|
span,
|
||||||
|
&format!(
|
||||||
|
"{these} statement{s} {are} not surrounded by a body",
|
||||||
|
these = these,
|
||||||
|
s = s,
|
||||||
|
are = are
|
||||||
|
),
|
||||||
|
);
|
||||||
|
err.span_label(arrow_span, "while parsing the `match` arm starting here");
|
||||||
|
if stmts.len() > 1 {
|
||||||
|
err.multipart_suggestion(
|
||||||
|
&format!("surround the statement{} with a body", s),
|
||||||
|
vec![
|
||||||
|
(span.shrink_to_lo(), "{ ".to_string()),
|
||||||
|
(span.shrink_to_hi(), " }".to_string()),
|
||||||
|
],
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
err.span_suggestion(
|
||||||
|
semi_sp,
|
||||||
|
"use a comma to end a `match` arm expression",
|
||||||
|
",".to_string(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
this.mk_expr_err(span)
|
||||||
|
};
|
||||||
|
// We might have either a `,` -> `;` typo, or a block without braces. We need
|
||||||
|
// a more subtle parsing strategy.
|
||||||
|
loop {
|
||||||
|
if self.token.kind == token::CloseDelim(token::Brace) {
|
||||||
|
// We have reached the closing brace of the `match` expression.
|
||||||
|
return Some(err(self, stmts));
|
||||||
|
}
|
||||||
|
if self.token.kind == token::Comma {
|
||||||
|
*self = start_snapshot;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let pre_pat_snapshot = self.clone();
|
||||||
|
match self.parse_pat_no_top_alt(None) {
|
||||||
|
Ok(_pat) => {
|
||||||
|
if self.token.kind == token::FatArrow {
|
||||||
|
// Reached arm end.
|
||||||
|
*self = pre_pat_snapshot;
|
||||||
|
return Some(err(self, stmts));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(mut err) => {
|
||||||
|
err.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*self = pre_pat_snapshot;
|
||||||
|
match self.parse_stmt_without_recovery(true, ForceCollect::No) {
|
||||||
|
// Consume statements for as long as possible.
|
||||||
|
Ok(Some(stmt)) => {
|
||||||
|
stmts.push(stmt);
|
||||||
|
}
|
||||||
|
Ok(None) => {
|
||||||
|
*self = start_snapshot;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// We couldn't parse either yet another statement missing it's
|
||||||
|
// enclosing block nor the next arm's pattern or closing brace.
|
||||||
|
Err(mut stmt_err) => {
|
||||||
|
stmt_err.cancel();
|
||||||
|
*self = start_snapshot;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
|
pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
|
||||||
let attrs = self.parse_outer_attributes()?;
|
let attrs = self.parse_outer_attributes()?;
|
||||||
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
|
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
|
||||||
|
@ -2007,6 +2103,21 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
if require_comma {
|
if require_comma {
|
||||||
let sm = this.sess.source_map();
|
let sm = this.sess.source_map();
|
||||||
|
if let Some(body) = this.parse_arm_body_missing_braces(&expr, arrow_span) {
|
||||||
|
let span = body.span;
|
||||||
|
return Ok((
|
||||||
|
ast::Arm {
|
||||||
|
attrs,
|
||||||
|
pat,
|
||||||
|
guard,
|
||||||
|
body,
|
||||||
|
span,
|
||||||
|
id: DUMMY_NODE_ID,
|
||||||
|
is_placeholder: false,
|
||||||
|
},
|
||||||
|
TrailingToken::None,
|
||||||
|
));
|
||||||
|
}
|
||||||
this.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)]).map_err(
|
this.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)]).map_err(
|
||||||
|mut err| {
|
|mut err| {
|
||||||
match (sm.span_to_lines(expr.span), sm.span_to_lines(arm_start_span)) {
|
match (sm.span_to_lines(expr.span), sm.span_to_lines(arm_start_span)) {
|
||||||
|
|
|
@ -34,7 +34,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// If `force_capture` is true, forces collection of tokens regardless of whether
|
/// If `force_capture` is true, forces collection of tokens regardless of whether
|
||||||
/// or not we have attributes
|
/// or not we have attributes
|
||||||
fn parse_stmt_without_recovery(
|
crate fn parse_stmt_without_recovery(
|
||||||
&mut self,
|
&mut self,
|
||||||
capture_semi: bool,
|
capture_semi: bool,
|
||||||
force_collect: ForceCollect,
|
force_collect: ForceCollect,
|
||||||
|
|
87
src/test/ui/parser/match-arm-without-braces.rs
Normal file
87
src/test/ui/parser/match-arm-without-braces.rs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
fn get<K, V: Default>(_: K) -> Option<V> {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Val {
|
||||||
|
Foo,
|
||||||
|
Bar,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Val {
|
||||||
|
fn default() -> Self {
|
||||||
|
Val::Foo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match S::get(1) {
|
||||||
|
Some(Val::Foo) => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
match S::get(2) {
|
||||||
|
Some(Val::Foo) => 3; //~ ERROR `match` arm body without braces
|
||||||
|
_ => 4,
|
||||||
|
}
|
||||||
|
match S::get(5) {
|
||||||
|
Some(Val::Foo) =>
|
||||||
|
7; //~ ERROR `match` arm body without braces
|
||||||
|
8;
|
||||||
|
_ => 9,
|
||||||
|
}
|
||||||
|
match S::get(10) {
|
||||||
|
Some(Val::Foo) =>
|
||||||
|
11; //~ ERROR `match` arm body without braces
|
||||||
|
12;
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
match S::get(13) {
|
||||||
|
None => {}
|
||||||
|
Some(Val::Foo) =>
|
||||||
|
14; //~ ERROR `match` arm body without braces
|
||||||
|
15;
|
||||||
|
}
|
||||||
|
match S::get(16) {
|
||||||
|
Some(Val::Foo) => 17
|
||||||
|
_ => 18, //~ ERROR expected one of
|
||||||
|
}
|
||||||
|
match S::get(19) {
|
||||||
|
Some(Val::Foo) =>
|
||||||
|
20; //~ ERROR `match` arm body without braces
|
||||||
|
21
|
||||||
|
_ => 22,
|
||||||
|
}
|
||||||
|
match S::get(23) {
|
||||||
|
Some(Val::Foo) =>
|
||||||
|
24; //~ ERROR `match` arm body without braces
|
||||||
|
25
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
match S::get(26) {
|
||||||
|
None => {}
|
||||||
|
Some(Val::Foo) =>
|
||||||
|
27; //~ ERROR `match` arm body without braces
|
||||||
|
28
|
||||||
|
}
|
||||||
|
match S::get(29) {
|
||||||
|
Some(Val::Foo) =>
|
||||||
|
30; //~ ERROR expected one of
|
||||||
|
31,
|
||||||
|
_ => 32,
|
||||||
|
}
|
||||||
|
match S::get(33) {
|
||||||
|
Some(Val::Foo) =>
|
||||||
|
34; //~ ERROR expected one of
|
||||||
|
35,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
match S::get(36) {
|
||||||
|
None => {}
|
||||||
|
Some(Val::Foo) =>
|
||||||
|
37; //~ ERROR expected one of
|
||||||
|
38,
|
||||||
|
}
|
||||||
|
}
|
135
src/test/ui/parser/match-arm-without-braces.stderr
Normal file
135
src/test/ui/parser/match-arm-without-braces.stderr
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
error: `match` arm body without braces
|
||||||
|
--> $DIR/match-arm-without-braces.rs:26:27
|
||||||
|
|
|
||||||
|
LL | Some(Val::Foo) => 3;
|
||||||
|
| -- ^- help: use a comma to end a `match` arm expression: `,`
|
||||||
|
| | |
|
||||||
|
| | this statement is not surrounded by a body
|
||||||
|
| while parsing the `match` arm starting here
|
||||||
|
|
||||||
|
error: `match` arm body without braces
|
||||||
|
--> $DIR/match-arm-without-braces.rs:31:11
|
||||||
|
|
|
||||||
|
LL | Some(Val::Foo) =>
|
||||||
|
| -- while parsing the `match` arm starting here
|
||||||
|
LL | / 7;
|
||||||
|
LL | | 8;
|
||||||
|
| |____________^ these statements are not surrounded by a body
|
||||||
|
|
|
||||||
|
help: surround the statements with a body
|
||||||
|
|
|
||||||
|
LL | { 7;
|
||||||
|
LL | 8; }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `match` arm body without braces
|
||||||
|
--> $DIR/match-arm-without-braces.rs:37:11
|
||||||
|
|
|
||||||
|
LL | Some(Val::Foo) =>
|
||||||
|
| -- while parsing the `match` arm starting here
|
||||||
|
LL | / 11;
|
||||||
|
LL | | 12;
|
||||||
|
| |_____________^ these statements are not surrounded by a body
|
||||||
|
|
|
||||||
|
help: surround the statements with a body
|
||||||
|
|
|
||||||
|
LL | { 11;
|
||||||
|
LL | 12; }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `match` arm body without braces
|
||||||
|
--> $DIR/match-arm-without-braces.rs:44:11
|
||||||
|
|
|
||||||
|
LL | Some(Val::Foo) =>
|
||||||
|
| -- while parsing the `match` arm starting here
|
||||||
|
LL | / 14;
|
||||||
|
LL | | 15;
|
||||||
|
| |_____________^ these statements are not surrounded by a body
|
||||||
|
|
|
||||||
|
help: surround the statements with a body
|
||||||
|
|
|
||||||
|
LL | { 14;
|
||||||
|
LL | 15; }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: expected one of `,`, `.`, `?`, `}`, or an operator, found reserved identifier `_`
|
||||||
|
--> $DIR/match-arm-without-braces.rs:49:9
|
||||||
|
|
|
||||||
|
LL | Some(Val::Foo) => 17
|
||||||
|
| -- - expected one of `,`, `.`, `?`, `}`, or an operator
|
||||||
|
| |
|
||||||
|
| while parsing the `match` arm starting here
|
||||||
|
LL | _ => 18,
|
||||||
|
| ^ unexpected token
|
||||||
|
|
||||||
|
error: `match` arm body without braces
|
||||||
|
--> $DIR/match-arm-without-braces.rs:53:11
|
||||||
|
|
|
||||||
|
LL | Some(Val::Foo) =>
|
||||||
|
| -- while parsing the `match` arm starting here
|
||||||
|
LL | / 20;
|
||||||
|
LL | | 21
|
||||||
|
| |____________^ these statements are not surrounded by a body
|
||||||
|
|
|
||||||
|
help: surround the statements with a body
|
||||||
|
|
|
||||||
|
LL | { 20;
|
||||||
|
LL | 21 }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `match` arm body without braces
|
||||||
|
--> $DIR/match-arm-without-braces.rs:59:11
|
||||||
|
|
|
||||||
|
LL | Some(Val::Foo) =>
|
||||||
|
| -- while parsing the `match` arm starting here
|
||||||
|
LL | / 24;
|
||||||
|
LL | | 25
|
||||||
|
| |____________^ these statements are not surrounded by a body
|
||||||
|
|
|
||||||
|
help: surround the statements with a body
|
||||||
|
|
|
||||||
|
LL | { 24;
|
||||||
|
LL | 25 }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: `match` arm body without braces
|
||||||
|
--> $DIR/match-arm-without-braces.rs:66:11
|
||||||
|
|
|
||||||
|
LL | Some(Val::Foo) =>
|
||||||
|
| -- while parsing the `match` arm starting here
|
||||||
|
LL | / 27;
|
||||||
|
LL | | 28
|
||||||
|
| |____________^ these statements are not surrounded by a body
|
||||||
|
|
|
||||||
|
help: surround the statements with a body
|
||||||
|
|
|
||||||
|
LL | { 27;
|
||||||
|
LL | 28 }
|
||||||
|
|
|
||||||
|
|
||||||
|
error: expected one of `,`, `.`, `?`, `}`, or an operator, found `;`
|
||||||
|
--> $DIR/match-arm-without-braces.rs:71:13
|
||||||
|
|
|
||||||
|
LL | Some(Val::Foo) =>
|
||||||
|
| -- while parsing the `match` arm starting here
|
||||||
|
LL | 30;
|
||||||
|
| ^ expected one of `,`, `.`, `?`, `}`, or an operator
|
||||||
|
|
||||||
|
error: expected one of `,`, `.`, `?`, `}`, or an operator, found `;`
|
||||||
|
--> $DIR/match-arm-without-braces.rs:77:13
|
||||||
|
|
|
||||||
|
LL | Some(Val::Foo) =>
|
||||||
|
| -- while parsing the `match` arm starting here
|
||||||
|
LL | 34;
|
||||||
|
| ^ expected one of `,`, `.`, `?`, `}`, or an operator
|
||||||
|
|
||||||
|
error: expected one of `,`, `.`, `?`, `}`, or an operator, found `;`
|
||||||
|
--> $DIR/match-arm-without-braces.rs:84:13
|
||||||
|
|
|
||||||
|
LL | Some(Val::Foo) =>
|
||||||
|
| -- while parsing the `match` arm starting here
|
||||||
|
LL | 37;
|
||||||
|
| ^ expected one of `,`, `.`, `?`, `}`, or an operator
|
||||||
|
|
||||||
|
error: aborting due to 11 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue