Skip to content

Commit 8c7c8fb

Browse files
committed
Rollup merge of rust-lang#48338 - estebank:match-missing-comma, r=petrochenkov
Fixes rust-lang#47311. r? @nrc
2 parents 8bf026d + 24be75d commit 8c7c8fb

11 files changed

+189
-37
lines changed

src/libsyntax/parse/parser.rs

+121-31
Original file line numberDiff line numberDiff line change
@@ -652,9 +652,11 @@ impl<'a> Parser<'a> {
652652
} else {
653653
let token_str = Parser::token_to_string(t);
654654
let this_token_str = self.this_token_to_string();
655-
Err(self.fatal(&format!("expected `{}`, found `{}`",
656-
token_str,
657-
this_token_str)))
655+
let mut err = self.fatal(&format!("expected `{}`, found `{}`",
656+
token_str,
657+
this_token_str));
658+
err.span_label(self.span, format!("expected `{}`", token_str));
659+
Err(err)
658660
}
659661
} else {
660662
self.expect_one_of(unsafe { slice::from_raw_parts(t, 1) }, &[])
@@ -1172,7 +1174,7 @@ impl<'a> Parser<'a> {
11721174
sep: SeqSep,
11731175
f: F)
11741176
-> PResult<'a, Vec<T>> where
1175-
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
1177+
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
11761178
{
11771179
self.expect(bra)?;
11781180
let result = self.parse_seq_to_before_end(ket, sep, f)?;
@@ -1190,7 +1192,7 @@ impl<'a> Parser<'a> {
11901192
sep: SeqSep,
11911193
f: F)
11921194
-> PResult<'a, Spanned<Vec<T>>> where
1193-
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
1195+
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
11941196
{
11951197
let lo = self.span;
11961198
self.expect(bra)?;
@@ -1485,7 +1487,10 @@ impl<'a> Parser<'a> {
14851487
}
14861488
_ => {
14871489
let token_str = self.this_token_to_string();
1488-
return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`", token_str)));
1490+
let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`",
1491+
token_str));
1492+
err.span_label(self.span, "expected `;` or `{`");
1493+
return Err(err);
14891494
}
14901495
};
14911496
(ident, ast::TraitItemKind::Method(sig, body), generics)
@@ -2216,7 +2221,12 @@ impl<'a> Parser<'a> {
22162221
TokenTree::Delimited(_, delimited) => Ok((delim, delimited.stream().into())),
22172222
_ => unreachable!(),
22182223
},
2219-
_ => Err(self.fatal("expected open delimiter")),
2224+
_ => {
2225+
let msg = "expected open delimiter";
2226+
let mut err = self.fatal(msg);
2227+
err.span_label(self.span, msg);
2228+
Err(err)
2229+
}
22202230
}
22212231
}
22222232

@@ -2349,7 +2359,10 @@ impl<'a> Parser<'a> {
23492359
if self.eat_keyword(keywords::Loop) {
23502360
return self.parse_loop_expr(Some(label), lo, attrs)
23512361
}
2352-
return Err(self.fatal("expected `while`, `for`, or `loop` after a label"))
2362+
let msg = "expected `while`, `for`, or `loop` after a label";
2363+
let mut err = self.fatal(msg);
2364+
err.span_label(self.span, msg);
2365+
return Err(err);
23532366
}
23542367
if self.eat_keyword(keywords::Loop) {
23552368
let lo = self.prev_span;
@@ -2408,6 +2421,7 @@ impl<'a> Parser<'a> {
24082421
// Catch this syntax error here, instead of in `parse_ident`, so
24092422
// that we can explicitly mention that let is not to be used as an expression
24102423
let mut db = self.fatal("expected expression, found statement (`let`)");
2424+
db.span_label(self.span, "expected expression");
24112425
db.note("variable declaration using `let` is a statement");
24122426
return Err(db);
24132427
} else if self.token.is_path_start() {
@@ -2443,7 +2457,9 @@ impl<'a> Parser<'a> {
24432457
self.cancel(&mut err);
24442458
let msg = format!("expected expression, found {}",
24452459
self.this_token_descr());
2446-
return Err(self.fatal(&msg));
2460+
let mut err = self.fatal(&msg);
2461+
err.span_label(self.span, "expected expression");
2462+
return Err(err);
24472463
}
24482464
}
24492465
}
@@ -2733,7 +2749,9 @@ impl<'a> Parser<'a> {
27332749
self.look_ahead(1, |t| t.is_ident()) => {
27342750
self.bump();
27352751
let name = match self.token { token::Ident(ident) => ident, _ => unreachable!() };
2736-
self.fatal(&format!("unknown macro variable `{}`", name)).emit();
2752+
let mut err = self.fatal(&format!("unknown macro variable `{}`", name));
2753+
err.span_label(self.span, "unknown macro variable");
2754+
err.emit();
27372755
return
27382756
}
27392757
token::Interpolated(ref nt) => {
@@ -3212,7 +3230,13 @@ impl<'a> Parser<'a> {
32123230
err.span_label(sp, "expected if condition here");
32133231
return Err(err)
32143232
}
3215-
let thn = self.parse_block()?;
3233+
let not_block = self.token != token::OpenDelim(token::Brace);
3234+
let thn = self.parse_block().map_err(|mut err| {
3235+
if not_block {
3236+
err.span_label(lo, "this `if` statement has a condition, but no block");
3237+
}
3238+
err
3239+
})?;
32163240
let mut els: Option<P<Expr>> = None;
32173241
let mut hi = thn.span;
32183242
if self.eat_keyword(keywords::Else) {
@@ -3404,14 +3428,52 @@ impl<'a> Parser<'a> {
34043428
} else {
34053429
None
34063430
};
3431+
let arrow_span = self.span;
34073432
self.expect(&token::FatArrow)?;
3408-
let expr = self.parse_expr_res(Restrictions::STMT_EXPR, None)?;
3433+
let arm_start_span = self.span;
3434+
3435+
let expr = self.parse_expr_res(Restrictions::STMT_EXPR, None)
3436+
.map_err(|mut err| {
3437+
err.span_label(arrow_span, "while parsing the `match` arm starting here");
3438+
err
3439+
})?;
34093440

34103441
let require_comma = classify::expr_requires_semi_to_be_stmt(&expr)
34113442
&& self.token != token::CloseDelim(token::Brace);
34123443

34133444
if require_comma {
3414-
self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)])?;
3445+
let cm = self.sess.codemap();
3446+
self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)])
3447+
.map_err(|mut err| {
3448+
match (cm.span_to_lines(expr.span), cm.span_to_lines(arm_start_span)) {
3449+
(Ok(ref expr_lines), Ok(ref arm_start_lines))
3450+
if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col
3451+
&& expr_lines.lines.len() == 2
3452+
&& self.token == token::FatArrow => {
3453+
// We check wether there's any trailing code in the parse span, if there
3454+
// isn't, we very likely have the following:
3455+
//
3456+
// X | &Y => "y"
3457+
// | -- - missing comma
3458+
// | |
3459+
// | arrow_span
3460+
// X | &X => "x"
3461+
// | - ^^ self.span
3462+
// | |
3463+
// | parsed until here as `"y" & X`
3464+
err.span_suggestion_short(
3465+
cm.next_point(arm_start_span),
3466+
"missing a comma here to end this `match` arm",
3467+
",".to_owned()
3468+
);
3469+
}
3470+
_ => {
3471+
err.span_label(arrow_span,
3472+
"while parsing the `match` arm starting here");
3473+
}
3474+
}
3475+
err
3476+
})?;
34153477
} else {
34163478
self.eat(&token::Comma);
34173479
}
@@ -3609,8 +3671,9 @@ impl<'a> Parser<'a> {
36093671
self.bump();
36103672
if self.token != token::CloseDelim(token::Brace) {
36113673
let token_str = self.this_token_to_string();
3612-
return Err(self.fatal(&format!("expected `{}`, found `{}`", "}",
3613-
token_str)))
3674+
let mut err = self.fatal(&format!("expected `{}`, found `{}`", "}", token_str));
3675+
err.span_label(self.span, "expected `}`");
3676+
return Err(err);
36143677
}
36153678
etc = true;
36163679
break;
@@ -3721,7 +3784,10 @@ impl<'a> Parser<'a> {
37213784
self.expect_and()?;
37223785
let mutbl = self.parse_mutability();
37233786
if let token::Lifetime(ident) = self.token {
3724-
return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident)));
3787+
let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern",
3788+
ident));
3789+
err.span_label(self.span, "unexpected lifetime");
3790+
return Err(err);
37253791
}
37263792
let subpat = self.parse_pat()?;
37273793
pat = PatKind::Ref(subpat, mutbl);
@@ -3806,7 +3872,10 @@ impl<'a> Parser<'a> {
38063872
}
38073873
token::OpenDelim(token::Brace) => {
38083874
if qself.is_some() {
3809-
return Err(self.fatal("unexpected `{` after qualified path"));
3875+
let msg = "unexpected `{` after qualified path";
3876+
let mut err = self.fatal(msg);
3877+
err.span_label(self.span, msg);
3878+
return Err(err);
38103879
}
38113880
// Parse struct pattern
38123881
self.bump();
@@ -3820,7 +3889,10 @@ impl<'a> Parser<'a> {
38203889
}
38213890
token::OpenDelim(token::Paren) => {
38223891
if qself.is_some() {
3823-
return Err(self.fatal("unexpected `(` after qualified path"));
3892+
let msg = "unexpected `(` after qualified path";
3893+
let mut err = self.fatal(msg);
3894+
err.span_label(self.span, msg);
3895+
return Err(err);
38243896
}
38253897
// Parse tuple struct or enum pattern
38263898
let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?;
@@ -3850,7 +3922,9 @@ impl<'a> Parser<'a> {
38503922
Err(mut err) => {
38513923
self.cancel(&mut err);
38523924
let msg = format!("expected pattern, found {}", self.this_token_descr());
3853-
return Err(self.fatal(&msg));
3925+
let mut err = self.fatal(&msg);
3926+
err.span_label(self.span, "expected pattern");
3927+
return Err(err);
38543928
}
38553929
}
38563930
}
@@ -4250,9 +4324,11 @@ impl<'a> Parser<'a> {
42504324
""
42514325
};
42524326
let tok_str = self.this_token_to_string();
4253-
return Err(self.fatal(&format!("expected {}`(` or `{{`, found `{}`",
4254-
ident_str,
4255-
tok_str)))
4327+
let mut err = self.fatal(&format!("expected {}`(` or `{{`, found `{}`",
4328+
ident_str,
4329+
tok_str));
4330+
err.span_label(self.span, format!("expected {}`(` or `{{`", ident_str));
4331+
return Err(err)
42564332
},
42574333
};
42584334

@@ -5559,8 +5635,12 @@ impl<'a> Parser<'a> {
55595635
body
55605636
} else {
55615637
let token_str = self.this_token_to_string();
5562-
return Err(self.fatal(&format!("expected `where`, `{{`, `(`, or `;` after struct \
5563-
name, found `{}`", token_str)))
5638+
let mut err = self.fatal(&format!(
5639+
"expected `where`, `{{`, `(`, or `;` after struct name, found `{}`",
5640+
token_str
5641+
));
5642+
err.span_label(self.span, "expected `where`, `{`, `(`, or `;` after struct name");
5643+
return Err(err);
55645644
};
55655645

55665646
Ok((class_name, ItemKind::Struct(vdata, generics), None))
@@ -5579,8 +5659,10 @@ impl<'a> Parser<'a> {
55795659
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
55805660
} else {
55815661
let token_str = self.this_token_to_string();
5582-
return Err(self.fatal(&format!("expected `where` or `{{` after union \
5583-
name, found `{}`", token_str)))
5662+
let mut err = self.fatal(&format!(
5663+
"expected `where` or `{{` after union name, found `{}`", token_str));
5664+
err.span_label(self.span, "expected `where` or `{` after union name");
5665+
return Err(err);
55845666
};
55855667

55865668
Ok((class_name, ItemKind::Union(vdata, generics), None))
@@ -5627,9 +5709,10 @@ impl<'a> Parser<'a> {
56275709
self.eat(&token::CloseDelim(token::Brace));
56285710
} else {
56295711
let token_str = self.this_token_to_string();
5630-
return Err(self.fatal(&format!("expected `where`, or `{{` after struct \
5631-
name, found `{}`",
5632-
token_str)));
5712+
let mut err = self.fatal(&format!(
5713+
"expected `where`, or `{{` after struct name, found `{}`", token_str));
5714+
err.span_label(self.span, "expected `where`, or `{` after struct name");
5715+
return Err(err);
56335716
}
56345717

56355718
Ok(fields)
@@ -5802,9 +5885,11 @@ impl<'a> Parser<'a> {
58025885
if !self.eat(term) {
58035886
let token_str = self.this_token_to_string();
58045887
let mut err = self.fatal(&format!("expected item, found `{}`", token_str));
5805-
let msg = "consider removing this semicolon";
58065888
if token_str == ";" {
5889+
let msg = "consider removing this semicolon";
58075890
err.span_suggestion_short(self.span, msg, "".to_string());
5891+
} else {
5892+
err.span_label(self.span, "expected item");
58085893
}
58095894
return Err(err);
58105895
}
@@ -6961,7 +7046,12 @@ impl<'a> Parser<'a> {
69617046
self.expect_no_suffix(sp, "string literal", suf);
69627047
Ok((s, style))
69637048
}
6964-
_ => Err(self.fatal("expected string literal"))
7049+
_ => {
7050+
let msg = "expected string literal";
7051+
let mut err = self.fatal(msg);
7052+
err.span_label(self.span, msg);
7053+
Err(err)
7054+
}
69657055
}
69667056
}
69677057
}

src/test/ui/cross-file-errors/main.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: expected expression, found `_`
22
--> $DIR/underscore.rs:18:9
33
|
44
LL | _
5-
| ^
5+
| ^ expected expression
66
|
77
::: $DIR/main.rs:15:5
88
|

src/test/ui/did_you_mean/issue-40006.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ error: expected `[`, found `#`
1919
--> $DIR/issue-40006.rs:20:17
2020
|
2121
LL | fn xxx() { ### } //~ ERROR missing
22-
| ^
22+
| ^ expected `[`
2323

2424
error: missing `fn`, `type`, or `const` for trait-item declaration
2525
--> $DIR/issue-40006.rs:20:21

src/test/ui/if-without-block.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let n = 1;
13+
if 5 == {
14+
//~^ NOTE this `if` statement has a condition, but no block
15+
println!("five");
16+
}
17+
}
18+
//~^ ERROR expected `{`, found `}`

src/test/ui/if-without-block.stderr

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: expected `{`, found `}`
2+
--> $DIR/if-without-block.rs:17:1
3+
|
4+
LL | if 5 == {
5+
| -- this `if` statement has a condition, but no block
6+
...
7+
LL | }
8+
| ^
9+
10+
error: aborting due to previous error
11+

src/test/ui/macro-context.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ error: expected expression, found reserved keyword `typeof`
3838
--> $DIR/macro-context.rs:13:17
3939
|
4040
LL | () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof`
41-
| ^^^^^^
41+
| ^^^^^^ expected expression
4242
...
4343
LL | m!();
4444
| ----- in this macro invocation

src/test/ui/missing-block-hint.stderr

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ error: expected `{`, found `=>`
22
--> $DIR/missing-block-hint.rs:13:18
33
|
44
LL | if (foo) => {} //~ ERROR expected `{`, found `=>`
5-
| ^^
5+
| -- ^^
6+
| |
7+
| this `if` statement has a condition, but no block
68

79
error: expected `{`, found `bar`
810
--> $DIR/missing-block-hint.rs:17:13
911
|
12+
LL | if (foo)
13+
| -- this `if` statement has a condition, but no block
1014
LL | bar; //~ ERROR expected `{`, found `bar`
1115
| ^^^-
1216
| |

src/test/ui/resolve/token-error-correct.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ error: expected expression, found `;`
2626
--> $DIR/token-error-correct.rs:14:13
2727
|
2828
LL | foo(bar(;
29-
| ^
29+
| ^ expected expression
3030

3131
error: aborting due to 3 previous errors
3232

0 commit comments

Comments
 (0)