Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide context for missing comma in match arm and if statement without block #48338

Merged
merged 5 commits into from
Mar 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 121 additions & 31 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,9 +652,11 @@ impl<'a> Parser<'a> {
} else {
let token_str = Parser::token_to_string(t);
let this_token_str = self.this_token_to_string();
Err(self.fatal(&format!("expected `{}`, found `{}`",
token_str,
this_token_str)))
let mut err = self.fatal(&format!("expected `{}`, found `{}`",
token_str,
this_token_str));
err.span_label(self.span, format!("expected `{}`", token_str));
Err(err)
}
} else {
self.expect_one_of(unsafe { slice::from_raw_parts(t, 1) }, &[])
Expand Down Expand Up @@ -1172,7 +1174,7 @@ impl<'a> Parser<'a> {
sep: SeqSep,
f: F)
-> PResult<'a, Vec<T>> where
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
{
self.expect(bra)?;
let result = self.parse_seq_to_before_end(ket, sep, f)?;
Expand All @@ -1190,7 +1192,7 @@ impl<'a> Parser<'a> {
sep: SeqSep,
f: F)
-> PResult<'a, Spanned<Vec<T>>> where
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
{
let lo = self.span;
self.expect(bra)?;
Expand Down Expand Up @@ -1485,7 +1487,10 @@ impl<'a> Parser<'a> {
}
_ => {
let token_str = self.this_token_to_string();
return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`", token_str)));
let mut err = self.fatal(&format!("expected `;` or `{{`, found `{}`",
token_str));
err.span_label(self.span, "expected `;` or `{`");
return Err(err);
}
};
(ident, ast::TraitItemKind::Method(sig, body), generics)
Expand Down Expand Up @@ -2216,7 +2221,12 @@ impl<'a> Parser<'a> {
TokenTree::Delimited(_, delimited) => Ok((delim, delimited.stream().into())),
_ => unreachable!(),
},
_ => Err(self.fatal("expected open delimiter")),
_ => {
let msg = "expected open delimiter";
let mut err = self.fatal(msg);
err.span_label(self.span, msg);
Err(err)
}
}
}

Expand Down Expand Up @@ -2349,7 +2359,10 @@ impl<'a> Parser<'a> {
if self.eat_keyword(keywords::Loop) {
return self.parse_loop_expr(Some(label), lo, attrs)
}
return Err(self.fatal("expected `while`, `for`, or `loop` after a label"))
let msg = "expected `while`, `for`, or `loop` after a label";
let mut err = self.fatal(msg);
err.span_label(self.span, msg);
return Err(err);
}
if self.eat_keyword(keywords::Loop) {
let lo = self.prev_span;
Expand Down Expand Up @@ -2408,6 +2421,7 @@ impl<'a> Parser<'a> {
// Catch this syntax error here, instead of in `parse_ident`, so
// that we can explicitly mention that let is not to be used as an expression
let mut db = self.fatal("expected expression, found statement (`let`)");
db.span_label(self.span, "expected expression");
db.note("variable declaration using `let` is a statement");
return Err(db);
} else if self.token.is_path_start() {
Expand Down Expand Up @@ -2443,7 +2457,9 @@ impl<'a> Parser<'a> {
self.cancel(&mut err);
let msg = format!("expected expression, found {}",
self.this_token_descr());
return Err(self.fatal(&msg));
let mut err = self.fatal(&msg);
err.span_label(self.span, "expected expression");
return Err(err);
}
}
}
Expand Down Expand Up @@ -2733,7 +2749,9 @@ impl<'a> Parser<'a> {
self.look_ahead(1, |t| t.is_ident()) => {
self.bump();
let name = match self.token { token::Ident(ident) => ident, _ => unreachable!() };
self.fatal(&format!("unknown macro variable `{}`", name)).emit();
let mut err = self.fatal(&format!("unknown macro variable `{}`", name));
err.span_label(self.span, "unknown macro variable");
err.emit();
return
}
token::Interpolated(ref nt) => {
Expand Down Expand Up @@ -3212,7 +3230,13 @@ impl<'a> Parser<'a> {
err.span_label(sp, "expected if condition here");
return Err(err)
}
let thn = self.parse_block()?;
let not_block = self.token != token::OpenDelim(token::Brace);
let thn = self.parse_block().map_err(|mut err| {
if not_block {
err.span_label(lo, "this `if` statement has a condition, but no block");
}
err
})?;
let mut els: Option<P<Expr>> = None;
let mut hi = thn.span;
if self.eat_keyword(keywords::Else) {
Expand Down Expand Up @@ -3404,14 +3428,52 @@ impl<'a> Parser<'a> {
} else {
None
};
let arrow_span = self.span;
self.expect(&token::FatArrow)?;
let expr = self.parse_expr_res(Restrictions::STMT_EXPR, None)?;
let arm_start_span = self.span;

let expr = self.parse_expr_res(Restrictions::STMT_EXPR, None)
.map_err(|mut err| {
err.span_label(arrow_span, "while parsing the `match` arm starting here");
err
})?;

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

if require_comma {
self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)])?;
let cm = self.sess.codemap();
self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)])
.map_err(|mut err| {
match (cm.span_to_lines(expr.span), cm.span_to_lines(arm_start_span)) {
(Ok(ref expr_lines), Ok(ref arm_start_lines))
if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col
&& expr_lines.lines.len() == 2
&& self.token == token::FatArrow => {
// We check wether there's any trailing code in the parse span, if there
// isn't, we very likely have the following:
//
// X | &Y => "y"
// | -- - missing comma
// | |
// | arrow_span
// X | &X => "x"
// | - ^^ self.span
// | |
// | parsed until here as `"y" & X`
err.span_suggestion_short(
cm.next_point(arm_start_span),
"missing a comma here to end this `match` arm",
",".to_owned()
);
}
_ => {
err.span_label(arrow_span,
"while parsing the `match` arm starting here");
}
}
err
})?;
} else {
self.eat(&token::Comma);
}
Expand Down Expand Up @@ -3595,8 +3657,9 @@ impl<'a> Parser<'a> {
self.bump();
if self.token != token::CloseDelim(token::Brace) {
let token_str = self.this_token_to_string();
return Err(self.fatal(&format!("expected `{}`, found `{}`", "}",
token_str)))
let mut err = self.fatal(&format!("expected `{}`, found `{}`", "}", token_str));
err.span_label(self.span, "expected `}`");
return Err(err);
}
etc = true;
break;
Expand Down Expand Up @@ -3707,7 +3770,10 @@ impl<'a> Parser<'a> {
self.expect_and()?;
let mutbl = self.parse_mutability();
if let token::Lifetime(ident) = self.token {
return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident)));
let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern",
ident));
err.span_label(self.span, "unexpected lifetime");
return Err(err);
}
let subpat = self.parse_pat()?;
pat = PatKind::Ref(subpat, mutbl);
Expand Down Expand Up @@ -3790,7 +3856,10 @@ impl<'a> Parser<'a> {
}
token::OpenDelim(token::Brace) => {
if qself.is_some() {
return Err(self.fatal("unexpected `{` after qualified path"));
let msg = "unexpected `{` after qualified path";
let mut err = self.fatal(msg);
err.span_label(self.span, msg);
return Err(err);
}
// Parse struct pattern
self.bump();
Expand All @@ -3804,7 +3873,10 @@ impl<'a> Parser<'a> {
}
token::OpenDelim(token::Paren) => {
if qself.is_some() {
return Err(self.fatal("unexpected `(` after qualified path"));
let msg = "unexpected `(` after qualified path";
let mut err = self.fatal(msg);
err.span_label(self.span, msg);
return Err(err);
}
// Parse tuple struct or enum pattern
self.bump();
Expand Down Expand Up @@ -3836,7 +3908,9 @@ impl<'a> Parser<'a> {
Err(mut err) => {
self.cancel(&mut err);
let msg = format!("expected pattern, found {}", self.this_token_descr());
return Err(self.fatal(&msg));
let mut err = self.fatal(&msg);
err.span_label(self.span, "expected pattern");
return Err(err);
}
}
}
Expand Down Expand Up @@ -4236,9 +4310,11 @@ impl<'a> Parser<'a> {
""
};
let tok_str = self.this_token_to_string();
return Err(self.fatal(&format!("expected {}`(` or `{{`, found `{}`",
ident_str,
tok_str)))
let mut err = self.fatal(&format!("expected {}`(` or `{{`, found `{}`",
ident_str,
tok_str));
err.span_label(self.span, format!("expected {}`(` or `{{`", ident_str));
return Err(err)
},
};

Expand Down Expand Up @@ -5545,8 +5621,12 @@ impl<'a> Parser<'a> {
body
} else {
let token_str = self.this_token_to_string();
return Err(self.fatal(&format!("expected `where`, `{{`, `(`, or `;` after struct \
name, found `{}`", token_str)))
let mut err = self.fatal(&format!(
"expected `where`, `{{`, `(`, or `;` after struct name, found `{}`",
token_str
));
err.span_label(self.span, "expected `where`, `{`, `(`, or `;` after struct name");
return Err(err);
};

Ok((class_name, ItemKind::Struct(vdata, generics), None))
Expand All @@ -5565,8 +5645,10 @@ impl<'a> Parser<'a> {
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
} else {
let token_str = self.this_token_to_string();
return Err(self.fatal(&format!("expected `where` or `{{` after union \
name, found `{}`", token_str)))
let mut err = self.fatal(&format!(
"expected `where` or `{{` after union name, found `{}`", token_str));
err.span_label(self.span, "expected `where` or `{` after union name");
return Err(err);
};

Ok((class_name, ItemKind::Union(vdata, generics), None))
Expand Down Expand Up @@ -5613,9 +5695,10 @@ impl<'a> Parser<'a> {
self.eat(&token::CloseDelim(token::Brace));
} else {
let token_str = self.this_token_to_string();
return Err(self.fatal(&format!("expected `where`, or `{{` after struct \
name, found `{}`",
token_str)));
let mut err = self.fatal(&format!(
"expected `where`, or `{{` after struct name, found `{}`", token_str));
err.span_label(self.span, "expected `where`, or `{` after struct name");
return Err(err);
}

Ok(fields)
Expand Down Expand Up @@ -5788,9 +5871,11 @@ impl<'a> Parser<'a> {
if !self.eat(term) {
let token_str = self.this_token_to_string();
let mut err = self.fatal(&format!("expected item, found `{}`", token_str));
let msg = "consider removing this semicolon";
if token_str == ";" {
let msg = "consider removing this semicolon";
err.span_suggestion_short(self.span, msg, "".to_string());
} else {
err.span_label(self.span, "expected item");
}
return Err(err);
}
Expand Down Expand Up @@ -6947,7 +7032,12 @@ impl<'a> Parser<'a> {
self.expect_no_suffix(sp, "string literal", suf);
Ok((s, style))
}
_ => Err(self.fatal("expected string literal"))
_ => {
let msg = "expected string literal";
let mut err = self.fatal(msg);
err.span_label(self.span, msg);
Err(err)
}
}
}
}
2 changes: 1 addition & 1 deletion src/test/ui/cross-file-errors/main.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error: expected expression, found `_`
--> $DIR/underscore.rs:18:9
|
LL | _
| ^
| ^ expected expression
|
::: $DIR/main.rs:15:5
|
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/did_you_mean/issue-40006.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ error: expected `[`, found `#`
--> $DIR/issue-40006.rs:20:17
|
LL | fn xxx() { ### } //~ ERROR missing
| ^
| ^ expected `[`

error: missing `fn`, `type`, or `const` for trait-item declaration
--> $DIR/issue-40006.rs:20:21
Expand Down
18 changes: 18 additions & 0 deletions src/test/ui/if-without-block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
let n = 1;
if 5 == {
//~^ NOTE this `if` statement has a condition, but no block
println!("five");
}
}
//~^ ERROR expected `{`, found `}`
11 changes: 11 additions & 0 deletions src/test/ui/if-without-block.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: expected `{`, found `}`
--> $DIR/if-without-block.rs:17:1
|
LL | if 5 == {
| -- this `if` statement has a condition, but no block
...
LL | }
| ^

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/macro-context.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ error: expected expression, found reserved keyword `typeof`
--> $DIR/macro-context.rs:13:17
|
LL | () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof`
| ^^^^^^
| ^^^^^^ expected expression
...
LL | m!();
| ----- in this macro invocation
Expand Down
6 changes: 5 additions & 1 deletion src/test/ui/missing-block-hint.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ error: expected `{`, found `=>`
--> $DIR/missing-block-hint.rs:13:18
|
LL | if (foo) => {} //~ ERROR expected `{`, found `=>`
| ^^
| -- ^^
| |
| this `if` statement has a condition, but no block

error: expected `{`, found `bar`
--> $DIR/missing-block-hint.rs:17:13
|
LL | if (foo)
| -- this `if` statement has a condition, but no block
LL | bar; //~ ERROR expected `{`, found `bar`
| ^^^-
| |
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/resolve/token-error-correct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ error: expected expression, found `;`
--> $DIR/token-error-correct.rs:14:13
|
LL | foo(bar(;
| ^
| ^ expected expression

error: aborting due to 3 previous errors

Loading