Skip to content

Commit 9b2f8ac

Browse files
committed
Auto merge of #47242 - estebank:issue-15980, r=petrochenkov
`struct` pattern parsing and diagnostic tweaks - Recover from struct parse error on match and point out missing match body. - Point at struct when finding non-identifier while parsing its fields. - Add label to "expected identifier, found {}" error. Fix #15980.
2 parents ca09293 + d17e38f commit 9b2f8ac

File tree

8 files changed

+102
-15
lines changed

8 files changed

+102
-15
lines changed

src/libsyntax/parse/parser.rs

+42-11
Original file line numberDiff line numberDiff line change
@@ -609,14 +609,21 @@ impl<'a> Parser<'a> {
609609
Parser::token_to_string(&self.token)
610610
}
611611

612+
pub fn token_descr(&self) -> Option<&'static str> {
613+
Some(match &self.token {
614+
t if t.is_special_ident() => "reserved identifier",
615+
t if t.is_used_keyword() => "keyword",
616+
t if t.is_unused_keyword() => "reserved keyword",
617+
_ => return None,
618+
})
619+
}
620+
612621
pub fn this_token_descr(&self) -> String {
613-
let prefix = match &self.token {
614-
t if t.is_special_ident() => "reserved identifier ",
615-
t if t.is_used_keyword() => "keyword ",
616-
t if t.is_unused_keyword() => "reserved keyword ",
617-
_ => "",
618-
};
619-
format!("{}`{}`", prefix, self.this_token_to_string())
622+
if let Some(prefix) = self.token_descr() {
623+
format!("{} `{}`", prefix, self.this_token_to_string())
624+
} else {
625+
format!("`{}`", self.this_token_to_string())
626+
}
620627
}
621628

622629
pub fn unexpected_last<T>(&self, t: &token::Token) -> PResult<'a, T> {
@@ -752,11 +759,27 @@ impl<'a> Parser<'a> {
752759
}
753760

754761
pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
762+
self.parse_ident_common(true)
763+
}
764+
765+
fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> {
755766
match self.token {
756767
token::Ident(i) => {
757768
if self.token.is_reserved_ident() {
758-
self.span_err(self.span, &format!("expected identifier, found {}",
759-
self.this_token_descr()));
769+
let mut err = self.struct_span_err(self.span,
770+
&format!("expected identifier, found {}",
771+
self.this_token_descr()));
772+
if let Some(token_descr) = self.token_descr() {
773+
err.span_label(self.span, format!("expected identifier, found {}",
774+
token_descr));
775+
} else {
776+
err.span_label(self.span, "expected identifier");
777+
}
778+
if recover {
779+
err.emit();
780+
} else {
781+
return Err(err);
782+
}
760783
}
761784
self.bump();
762785
Ok(i)
@@ -767,6 +790,12 @@ impl<'a> Parser<'a> {
767790
} else {
768791
let mut err = self.fatal(&format!("expected identifier, found `{}`",
769792
self.this_token_to_string()));
793+
if let Some(token_descr) = self.token_descr() {
794+
err.span_label(self.span, format!("expected identifier, found {}",
795+
token_descr));
796+
} else {
797+
err.span_label(self.span, "expected identifier");
798+
}
770799
if self.token == token::Underscore {
771800
err.note("`_` is a wildcard pattern, not an identifier");
772801
}
@@ -2058,7 +2087,7 @@ impl<'a> Parser<'a> {
20582087
self.bump();
20592088
Ok(Ident::with_empty_ctxt(name))
20602089
} else {
2061-
self.parse_ident()
2090+
self.parse_ident_common(false)
20622091
}
20632092
}
20642093

@@ -2075,7 +2104,7 @@ impl<'a> Parser<'a> {
20752104
hi = self.prev_span;
20762105
(fieldname, self.parse_expr()?, false)
20772106
} else {
2078-
let fieldname = self.parse_ident()?;
2107+
let fieldname = self.parse_ident_common(false)?;
20792108
hi = self.prev_span;
20802109

20812110
// Mimic `x: x` for the `x` field shorthand.
@@ -2426,6 +2455,7 @@ impl<'a> Parser<'a> {
24262455

24272456
fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Attribute>)
24282457
-> PResult<'a, P<Expr>> {
2458+
let struct_sp = lo.to(self.prev_span);
24292459
self.bump();
24302460
let mut fields = Vec::new();
24312461
let mut base = None;
@@ -2460,6 +2490,7 @@ impl<'a> Parser<'a> {
24602490
match self.parse_field() {
24612491
Ok(f) => fields.push(f),
24622492
Err(mut e) => {
2493+
e.span_label(struct_sp, "while parsing this struct");
24632494
e.emit();
24642495
self.recover_stmt();
24652496
break;

src/test/compile-fail/issue-28433.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
enum bird {
1414
pub duck,
1515
//~^ ERROR: expected identifier, found keyword `pub`
16-
//~^^ ERROR: expected
16+
//~| ERROR: expected
1717
goose
1818
}
1919

src/test/parse-fail/issue-32501.rs

+1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ fn main() {
1818
let mut _b = 0;
1919
let mut _ = 0; //~ ERROR expected identifier, found `_`
2020
//~^ NOTE `_` is a wildcard pattern, not an identifier
21+
//~| NOTE expected identifier
2122
}

src/test/ui/issue-44406.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: expected identifier, found keyword `true`
22
--> $DIR/issue-44406.rs:18:10
33
|
44
18 | foo!(true); //~ ERROR expected type, found keyword
5-
| ^^^^
5+
| ^^^^ expected identifier, found keyword
66

77
error: expected type, found keyword `true`
88
--> $DIR/issue-44406.rs:18:10

src/test/ui/pub/pub-restricted-error.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: expected identifier, found `(`
22
--> $DIR/pub-restricted-error.rs:16:16
33
|
44
16 | pub(crate) () foo: usize, //~ ERROR expected identifier
5-
| ^
5+
| ^ expected identifier
66

77
error: aborting due to previous error
88

src/test/ui/pub/pub-restricted-non-path.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: expected identifier, found `.`
22
--> $DIR/pub-restricted-non-path.rs:13:6
33
|
44
13 | pub (.) fn afn() {} //~ ERROR expected identifier
5-
| ^
5+
| ^ expected identifier
66

77
error: aborting due to previous error
88

src/test/ui/token/issue-15980.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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+
use std::io;
12+
13+
fn main(){
14+
let x: io::IoResult<()> = Ok(());
15+
//~^ ERROR cannot find type `IoResult` in module `io`
16+
//~| NOTE did you mean `Result`?
17+
match x {
18+
Err(ref e) if e.kind == io::EndOfFile {
19+
//~^ NOTE while parsing this struct
20+
return
21+
//~^ ERROR expected identifier, found keyword `return`
22+
//~| NOTE expected identifier, found keyword
23+
}
24+
//~^ NOTE expected one of `.`, `=>`, `?`, or an operator here
25+
_ => {}
26+
//~^ ERROR expected one of `.`, `=>`, `?`, or an operator, found `_`
27+
//~| NOTE unexpected token
28+
}
29+
}

src/test/ui/token/issue-15980.stderr

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: expected identifier, found keyword `return`
2+
--> $DIR/issue-15980.rs:20:13
3+
|
4+
18 | Err(ref e) if e.kind == io::EndOfFile {
5+
| ------------- while parsing this struct
6+
19 | //~^ NOTE while parsing this struct
7+
20 | return
8+
| ^^^^^^ expected identifier, found keyword
9+
10+
error: expected one of `.`, `=>`, `?`, or an operator, found `_`
11+
--> $DIR/issue-15980.rs:25:9
12+
|
13+
23 | }
14+
| - expected one of `.`, `=>`, `?`, or an operator here
15+
24 | //~^ NOTE expected one of `.`, `=>`, `?`, or an operator here
16+
25 | _ => {}
17+
| ^ unexpected token
18+
19+
error[E0412]: cannot find type `IoResult` in module `io`
20+
--> $DIR/issue-15980.rs:14:16
21+
|
22+
14 | let x: io::IoResult<()> = Ok(());
23+
| ^^^^^^^^ did you mean `Result`?
24+
25+
error: aborting due to 3 previous errors
26+

0 commit comments

Comments
 (0)