-
Notifications
You must be signed in to change notification settings - Fork 13.4k
struct
pattern parsing and diagnostic tweaks
#47242
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -609,14 +609,21 @@ impl<'a> Parser<'a> { | |
Parser::token_to_string(&self.token) | ||
} | ||
|
||
pub fn token_descr(&self) -> Option<&'static str> { | ||
Some(match &self.token { | ||
t if t.is_special_ident() => "reserved identifier", | ||
t if t.is_used_keyword() => "keyword", | ||
t if t.is_unused_keyword() => "reserved keyword", | ||
_ => return None, | ||
}) | ||
} | ||
|
||
pub fn this_token_descr(&self) -> String { | ||
let prefix = match &self.token { | ||
t if t.is_special_ident() => "reserved identifier ", | ||
t if t.is_used_keyword() => "keyword ", | ||
t if t.is_unused_keyword() => "reserved keyword ", | ||
_ => "", | ||
}; | ||
format!("{}`{}`", prefix, self.this_token_to_string()) | ||
if let Some(prefix) = self.token_descr() { | ||
format!("{} `{}`", prefix, self.this_token_to_string()) | ||
} else { | ||
format!("`{}`", self.this_token_to_string()) | ||
} | ||
} | ||
|
||
pub fn unexpected_last<T>(&self, t: &token::Token) -> PResult<'a, T> { | ||
|
@@ -752,11 +759,27 @@ impl<'a> Parser<'a> { | |
} | ||
|
||
pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { | ||
self.parse_ident_common(true) | ||
} | ||
|
||
fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> { | ||
match self.token { | ||
token::Ident(i) => { | ||
if self.token.is_reserved_ident() { | ||
self.span_err(self.span, &format!("expected identifier, found {}", | ||
self.this_token_descr())); | ||
let mut err = self.struct_span_err(self.span, | ||
&format!("expected identifier, found {}", | ||
self.this_token_descr())); | ||
if let Some(token_descr) = self.token_descr() { | ||
err.span_label(self.span, format!("expected identifier, found {}", | ||
token_descr)); | ||
} else { | ||
err.span_label(self.span, "expected identifier"); | ||
} | ||
if recover { | ||
err.emit(); | ||
} else { | ||
return Err(err); | ||
} | ||
} | ||
self.bump(); | ||
Ok(i) | ||
|
@@ -767,6 +790,12 @@ impl<'a> Parser<'a> { | |
} else { | ||
let mut err = self.fatal(&format!("expected identifier, found `{}`", | ||
self.this_token_to_string())); | ||
if let Some(token_descr) = self.token_descr() { | ||
err.span_label(self.span, format!("expected identifier, found {}", | ||
token_descr)); | ||
} else { | ||
err.span_label(self.span, "expected identifier"); | ||
} | ||
if self.token == token::Underscore { | ||
err.note("`_` is a wildcard pattern, not an identifier"); | ||
} | ||
|
@@ -2056,7 +2085,7 @@ impl<'a> Parser<'a> { | |
self.bump(); | ||
Ok(Ident::with_empty_ctxt(name)) | ||
} else { | ||
self.parse_ident() | ||
self.parse_ident_common(false) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should fix this in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you provide incorrect code that you'd expect to fail to be addressed by this PR? I'm confused, as currently (and after this PR) other types of statements will have the expected behavior (continue and point out the lack of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, for the record, I'm slowly going through the parser looking for places where the span of an error is context dependent on the current state parser, in this case for example, the reason a non reserved ident was found is because we're parsing a struct, in the case where fn main() {
if 3 == {
4
}
} is expecting Do you feel this is too heavy handed? The main advantage I see of this is 1) these are easy enough mistakes to make and 2) the diagnostic doesn't show you enough context as it is now to identify why the problem is happening in the first place. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought we get a fatal error from |
||
} | ||
} | ||
|
||
|
@@ -2073,7 +2102,7 @@ impl<'a> Parser<'a> { | |
hi = self.prev_span; | ||
(fieldname, self.parse_expr()?, false) | ||
} else { | ||
let fieldname = self.parse_ident()?; | ||
let fieldname = self.parse_ident_common(false)?; | ||
hi = self.prev_span; | ||
|
||
// Mimic `x: x` for the `x` field shorthand. | ||
|
@@ -2424,6 +2453,7 @@ impl<'a> Parser<'a> { | |
|
||
fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Attribute>) | ||
-> PResult<'a, P<Expr>> { | ||
let struct_sp = lo.to(self.prev_span); | ||
self.bump(); | ||
let mut fields = Vec::new(); | ||
let mut base = None; | ||
|
@@ -2458,6 +2488,7 @@ impl<'a> Parser<'a> { | |
match self.parse_field() { | ||
Ok(f) => fields.push(f), | ||
Err(mut e) => { | ||
e.span_label(struct_sp, "while parsing this struct"); | ||
e.emit(); | ||
self.recover_stmt(); | ||
break; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ error: expected identifier, found keyword `true` | |
--> $DIR/issue-44406.rs:18:10 | ||
| | ||
18 | foo!(true); //~ ERROR expected type, found keyword | ||
| ^^^^ | ||
| ^^^^ expected identifier, found keyword | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This case looks interesting. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A previous commit in a separate PR actually removed this incorrect issue (mostly by accident), but it broke too many things to be mergeable. The macro is expecting a token tree as an argument, so I'm sure it's coming from that. Both cases should probably be pointing at There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
My eyes deceive me, we expect an identifier (but this is not related to |
||
|
||
error: expected type, found keyword `true` | ||
--> $DIR/issue-44406.rs:18:10 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// 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. | ||
|
||
use std::io; | ||
|
||
fn main(){ | ||
let x: io::IoResult<()> = Ok(()); | ||
//~^ ERROR cannot find type `IoResult` in module `io` | ||
//~| NOTE did you mean `Result`? | ||
match x { | ||
Err(ref e) if e.kind == io::EndOfFile { | ||
//~^ NOTE while parsing this struct | ||
return | ||
//~^ ERROR expected identifier, found keyword `return` | ||
//~| NOTE expected identifier, found keyword | ||
} | ||
//~^ NOTE expected one of `.`, `=>`, `?`, or an operator here | ||
_ => {} | ||
//~^ ERROR expected one of `.`, `=>`, `?`, or an operator, found `_` | ||
//~| NOTE unexpected token | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
error: expected identifier, found keyword `return` | ||
--> $DIR/issue-15980.rs:20:13 | ||
| | ||
18 | Err(ref e) if e.kind == io::EndOfFile { | ||
| ------------- while parsing this struct | ||
19 | //~^ NOTE while parsing this struct | ||
20 | return | ||
| ^^^^^^ expected identifier, found keyword | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was the only line originally being emitted for this input. Now it correctly complains about missing |
||
|
||
error: expected one of `.`, `=>`, `?`, or an operator, found `_` | ||
--> $DIR/issue-15980.rs:25:9 | ||
| | ||
23 | } | ||
| - expected one of `.`, `=>`, `?`, or an operator here | ||
24 | //~^ NOTE expected one of `.`, `=>`, `?`, or an operator here | ||
25 | _ => {} | ||
| ^ unexpected token | ||
|
||
error[E0412]: cannot find type `IoResult` in module `io` | ||
--> $DIR/issue-15980.rs:14:16 | ||
| | ||
14 | let x: io::IoResult<()> = Ok(()); | ||
| ^^^^^^^^ did you mean `Result`? | ||
|
||
error: aborting due to 3 previous errors | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see much point in a label that duplicates the primary message exactly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There have been (off hand) talks about RLS and other tools being able to reliably show only the error message or the label and although the message works better in isolation, the primary span (should) works better when pointing at the code, and should be shorter as they don't have to duplicate the code's context.
I also want to accommodate people that we might have been "training" to ignore the error message in lieu of the primary label (I know I have that behavior at times).
Because of those reasons, I've been trying to move away from errors that have highlighted spans devoid of labels.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, sounds reasonable.