diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 881e3e412d4..92584f5b519 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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) }, &[]) @@ -1172,7 +1174,7 @@ impl<'a> Parser<'a> { sep: SeqSep, f: F) -> PResult<'a, Vec> 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)?; @@ -1190,7 +1192,7 @@ impl<'a> Parser<'a> { sep: SeqSep, f: F) -> PResult<'a, Spanned>> where - F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, + F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { let lo = self.span; self.expect(bra)?; @@ -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) @@ -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) + } } } @@ -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; @@ -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() { @@ -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); } } } @@ -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) => { @@ -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> = None; let mut hi = thn.span; if self.eat_keyword(keywords::Else) { @@ -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); } @@ -3609,8 +3671,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; @@ -3721,7 +3784,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); @@ -3806,7 +3872,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(); @@ -3820,7 +3889,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 let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?; @@ -3850,7 +3922,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); } } } @@ -4250,9 +4324,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) }, }; @@ -5559,8 +5635,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)) @@ -5579,8 +5659,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)) @@ -5627,9 +5709,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) @@ -5802,9 +5885,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); } @@ -6961,7 +7046,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) + } } } } diff --git a/src/test/ui/cross-file-errors/main.stderr b/src/test/ui/cross-file-errors/main.stderr index 9eeea28be8f..a9db5214e6a 100644 --- a/src/test/ui/cross-file-errors/main.stderr +++ b/src/test/ui/cross-file-errors/main.stderr @@ -2,7 +2,7 @@ error: expected expression, found `_` --> $DIR/underscore.rs:18:9 | LL | _ - | ^ + | ^ expected expression | ::: $DIR/main.rs:15:5 | diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 301441c5622..e576393500f 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -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 diff --git a/src/test/ui/if-without-block.rs b/src/test/ui/if-without-block.rs new file mode 100644 index 00000000000..ce3de3b302d --- /dev/null +++ b/src/test/ui/if-without-block.rs @@ -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 or the MIT license +// , 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 `}` diff --git a/src/test/ui/if-without-block.stderr b/src/test/ui/if-without-block.stderr new file mode 100644 index 00000000000..bc8e7310ce3 --- /dev/null +++ b/src/test/ui/if-without-block.stderr @@ -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 + diff --git a/src/test/ui/macro-context.stderr b/src/test/ui/macro-context.stderr index 65bbe09a212..4dc6bbe4d65 100644 --- a/src/test/ui/macro-context.stderr +++ b/src/test/ui/macro-context.stderr @@ -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 diff --git a/src/test/ui/missing-block-hint.stderr b/src/test/ui/missing-block-hint.stderr index 54f394a4220..a48eff890b3 100644 --- a/src/test/ui/missing-block-hint.stderr +++ b/src/test/ui/missing-block-hint.stderr @@ -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` | ^^^- | | diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 344c288b596..c6d32c6726e 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -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 diff --git a/src/test/ui/suggestions/missing-comma-in-match.rs b/src/test/ui/suggestions/missing-comma-in-match.rs new file mode 100644 index 00000000000..6f86cdea3cf --- /dev/null +++ b/src/test/ui/suggestions/missing-comma-in-match.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + match &Some(3) { + &None => 1 + &Some(2) => { 3 } + //~^ ERROR expected one of `,`, `.`, `?`, `}`, or an operator, found `=>` + //~| NOTE expected one of `,`, `.`, `?`, `}`, or an operator here + _ => 2 + }; +} diff --git a/src/test/ui/suggestions/missing-comma-in-match.stderr b/src/test/ui/suggestions/missing-comma-in-match.stderr new file mode 100644 index 00000000000..b71a50b6631 --- /dev/null +++ b/src/test/ui/suggestions/missing-comma-in-match.stderr @@ -0,0 +1,10 @@ +error: expected one of `,`, `.`, `?`, `}`, or an operator, found `=>` + --> $DIR/missing-comma-in-match.rs:14:18 + | +LL | &None => 1 + | - help: missing a comma here to end this `match` arm +LL | &Some(2) => { 3 } + | ^^ expected one of `,`, `.`, `?`, `}`, or an operator here + +error: aborting due to previous error + diff --git a/src/test/ui/token/issue-10636-2.stderr b/src/test/ui/token/issue-10636-2.stderr index fcd2c10594a..26816ca0ca2 100644 --- a/src/test/ui/token/issue-10636-2.stderr +++ b/src/test/ui/token/issue-10636-2.stderr @@ -20,7 +20,7 @@ error: expected expression, found `)` --> $DIR/issue-10636-2.rs:18:1 | LL | } //~ ERROR: incorrect close delimiter - | ^ + | ^ expected expression error[E0601]: main function not found