Auto merge of #67112 - Centril:expr-polish, r=estebank

Refactor expression parsing thoroughly

Based on https://github.com/rust-lang/rust/pull/66994 together with which this has refactored basically the entirety of `expr.rs`.

r? @estebank
This commit is contained in:
bors 2019-12-29 19:30:53 +00:00
commit da3629b05f
31 changed files with 589 additions and 541 deletions

View File

@ -2,6 +2,7 @@ use super::{Parser, PathStyle, TokenType};
use rustc_errors::PResult;
use syntax::ast;
use syntax::attr;
use syntax::print::pprust;
use syntax::token::{self, Nonterminal};
use syntax::util::comments;
use syntax_pos::{Span, Symbol};
@ -154,7 +155,7 @@ impl<'a> Parser<'a> {
(attr_sp, item, style)
}
_ => {
let token_str = self.this_token_to_string();
let token_str = pprust::token_to_string(&self.token);
return Err(self.fatal(&format!("expected `#`, found `{}`", token_str)));
}
};
@ -329,7 +330,7 @@ impl<'a> Parser<'a> {
Err(ref mut err) => err.cancel(),
}
let found = self.this_token_to_string();
let found = pprust::token_to_string(&self.token);
let msg = format!("expected unsuffixed literal or identifier, found `{}`", found);
Err(self.diagnostic().struct_span_err(self.token.span, &msg))
}

View File

@ -200,7 +200,7 @@ impl<'a> Parser<'a> {
pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a> {
let mut err = self.struct_span_err(
self.token.span,
&format!("expected identifier, found {}", self.this_token_descr()),
&format!("expected identifier, found {}", super::token_descr(&self.token)),
);
let valid_follow = &[
TokenKind::Eq,
@ -225,7 +225,7 @@ impl<'a> Parser<'a> {
);
}
}
if let Some(token_descr) = self.token_descr() {
if let Some(token_descr) = super::token_descr_opt(&self.token) {
err.span_label(self.token.span, format!("expected identifier, found {}", token_descr));
} else {
err.span_label(self.token.span, "expected identifier");
@ -272,7 +272,7 @@ impl<'a> Parser<'a> {
expected.sort_by_cached_key(|x| x.to_string());
expected.dedup();
let expect = tokens_to_string(&expected[..]);
let actual = self.this_token_descr();
let actual = super::token_descr(&self.token);
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
let short_expect = if expected.len() > 6 {
format!("{} possible tokens", expected.len())
@ -815,7 +815,7 @@ impl<'a> Parser<'a> {
t: &TokenKind,
) -> PResult<'a, bool /* recovered */> {
let token_str = pprust::token_kind_to_string(t);
let this_token_str = self.this_token_descr();
let this_token_str = super::token_descr(&self.token);
let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {
// Point at the end of the macro call when reaching end of macro arguments.
(token::Eof, Some(_)) => {
@ -862,7 +862,7 @@ impl<'a> Parser<'a> {
return Ok(());
}
let sm = self.sess.source_map();
let msg = format!("expected `;`, found `{}`", self.this_token_descr());
let msg = format!("expected `;`, found `{}`", super::token_descr(&self.token));
let appl = Applicability::MachineApplicable;
if self.token.span == DUMMY_SP || self.prev_span == DUMMY_SP {
// Likely inside a macro, can't provide meaninful suggestions.
@ -1270,7 +1270,7 @@ impl<'a> Parser<'a> {
}
pub(super) fn expected_semi_or_open_brace<T>(&mut self) -> PResult<'a, T> {
let token_str = self.this_token_descr();
let token_str = super::token_descr(&self.token);
let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str));
err.span_label(self.token.span, "expected `;` or `{`");
Err(err)
@ -1447,7 +1447,7 @@ impl<'a> Parser<'a> {
}
_ => (
self.token.span,
format!("expected expression, found {}", self.this_token_descr(),),
format!("expected expression, found {}", super::token_descr(&self.token),),
),
};
let mut err = self.struct_span_err(span, &msg);

File diff suppressed because it is too large Load Diff

View File

@ -1348,7 +1348,7 @@ impl<'a> Parser<'a> {
self.expect_semi()?;
body
} else {
let token_str = self.this_token_descr();
let token_str = super::token_descr(&self.token);
let mut err = self.fatal(&format!(
"expected `where`, `{{`, `(`, or `;` after struct name, found {}",
token_str
@ -1374,7 +1374,7 @@ impl<'a> Parser<'a> {
let (fields, recovered) = self.parse_record_struct_body()?;
VariantData::Struct(fields, recovered)
} else {
let token_str = self.this_token_descr();
let token_str = super::token_descr(&self.token);
let mut err = self
.fatal(&format!("expected `where` or `{{` after union name, found {}", token_str));
err.span_label(self.token.span, "expected `where` or `{` after union name");
@ -1411,7 +1411,7 @@ impl<'a> Parser<'a> {
}
self.eat(&token::CloseDelim(token::Brace));
} else {
let token_str = self.this_token_descr();
let token_str = super::token_descr(&self.token);
let mut err = self.fatal(&format!(
"expected `where`, or `{{` after struct name, found {}",
token_str
@ -1498,7 +1498,7 @@ impl<'a> Parser<'a> {
let sp = self.sess.source_map().next_point(self.prev_span);
let mut err = self.struct_span_err(
sp,
&format!("expected `,`, or `}}`, found {}", self.this_token_descr()),
&format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
);
if self.token.is_ident() {
// This is likely another field; emit the diagnostic and keep going

View File

@ -354,6 +354,24 @@ pub enum FollowedByType {
No,
}
fn token_descr_opt(token: &Token) -> Option<&'static str> {
Some(match token.kind {
_ if token.is_special_ident() => "reserved identifier",
_ if token.is_used_keyword() => "keyword",
_ if token.is_unused_keyword() => "reserved keyword",
token::DocComment(..) => "doc comment",
_ => return None,
})
}
pub(super) fn token_descr(token: &Token) -> String {
let token_str = pprust::token_to_string(token);
match token_descr_opt(token) {
Some(prefix) => format!("{} `{}`", prefix, token_str),
_ => format!("`{}`", token_str),
}
}
impl<'a> Parser<'a> {
pub fn new(
sess: &'a ParseSess,
@ -422,29 +440,6 @@ impl<'a> Parser<'a> {
next
}
/// Converts the current token to a string using `self`'s reader.
pub fn this_token_to_string(&self) -> String {
pprust::token_to_string(&self.token)
}
fn token_descr(&self) -> Option<&'static str> {
Some(match &self.token.kind {
_ if self.token.is_special_ident() => "reserved identifier",
_ if self.token.is_used_keyword() => "keyword",
_ if self.token.is_unused_keyword() => "reserved keyword",
token::DocComment(..) => "doc comment",
_ => return None,
})
}
pub(super) fn this_token_descr(&self) -> String {
if let Some(prefix) = self.token_descr() {
format!("{} `{}`", prefix, self.this_token_to_string())
} else {
format!("`{}`", self.this_token_to_string())
}
}
crate fn unexpected<T>(&mut self) -> PResult<'a, T> {
match self.expect_one_of(&[], &[]) {
Err(e) => Err(e),

View File

@ -79,7 +79,7 @@ impl<'a> Parser<'a> {
}
if !self.eat(term) {
let token_str = self.this_token_descr();
let token_str = super::token_descr(&self.token);
if !self.maybe_consume_incorrect_semicolon(&items) {
let mut err = self.fatal(&format!("expected item, found {}", token_str));
err.span_label(self.token.span, "expected item");

View File

@ -671,7 +671,7 @@ impl<'a> Parser<'a> {
err.cancel();
let expected = expected.unwrap_or("pattern");
let msg = format!("expected {}, found {}", expected, self.this_token_descr());
let msg = format!("expected {}, found {}", expected, super::token_descr(&self.token));
let mut err = self.fatal(&msg);
err.span_label(self.token.span, format!("expected {}", expected));
@ -876,7 +876,7 @@ impl<'a> Parser<'a> {
etc_span = Some(etc_sp);
break;
}
let token_str = self.this_token_descr();
let token_str = super::token_descr(&self.token);
let mut err = self.fatal(&format!("expected `}}`, found {}", token_str));
err.span_label(self.token.span, "expected `}`");

View File

@ -323,7 +323,7 @@ impl<'a> Parser<'a> {
fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
let sp = self.token.span;
let tok = self.this_token_descr();
let tok = super::token_descr(&self.token);
let mut e = self.span_fatal(sp, &format!("expected `{{`, found {}", tok));
let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
@ -411,7 +411,7 @@ impl<'a> Parser<'a> {
continue;
};
}
Ok(P(ast::Block { stmts, id: DUMMY_NODE_ID, rules: s, span: lo.to(self.prev_span) }))
Ok(self.mk_block(stmts, s, lo.to(self.prev_span)))
}
/// Parses a statement, including the trailing semicolon.
@ -463,7 +463,7 @@ impl<'a> Parser<'a> {
fn warn_missing_semicolon(&self) {
self.diagnostic()
.struct_span_warn(self.token.span, {
&format!("expected `;`, found {}", self.this_token_descr())
&format!("expected `;`, found {}", super::token_descr(&self.token))
})
.note({
"this was erroneously allowed and will become a hard error in a future release"
@ -471,7 +471,11 @@ impl<'a> Parser<'a> {
.emit();
}
fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {
pub(super) fn mk_block(&self, stmts: Vec<Stmt>, rules: BlockCheckMode, span: Span) -> P<Block> {
P(Block { stmts, id: DUMMY_NODE_ID, rules, span })
}
pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {
Stmt { id: DUMMY_NODE_ID, kind, span }
}
}

View File

@ -135,7 +135,7 @@ impl<'a> Parser<'a> {
TyKind::Err
}
} else {
let msg = format!("expected type, found {}", self.this_token_descr());
let msg = format!("expected type, found {}", super::token_descr(&self.token));
let mut err = self.struct_span_err(self.token.span, &msg);
err.span_label(self.token.span, "expected type");
self.maybe_annotate_with_ascription(&mut err, true);

View File

@ -904,10 +904,8 @@ pub fn ensure_complete_parse<'a>(
span: Span,
) {
if this.token != token::Eof {
let msg = format!(
"macro expansion ignores token `{}` and any following",
this.this_token_to_string()
);
let token = pprust::token_to_string(&this.token);
let msg = format!("macro expansion ignores token `{}` and any following", token);
// Avoid emitting backtrace info twice.
let def_site_span = this.token.span.with_ctxt(SyntaxContext::root());
let mut err = this.struct_span_err(def_site_span, &msg);

View File

@ -133,15 +133,17 @@ pub fn expand_include<'cx>(
while self.p.token != token::Eof {
match panictry!(self.p.parse_item()) {
Some(item) => ret.push(item),
None => self
.p
.sess
.span_diagnostic
.span_fatal(
self.p.token.span,
&format!("expected item, found `{}`", self.p.this_token_to_string()),
)
.raise(),
None => {
let token = pprust::token_to_string(&self.p.token);
self.p
.sess
.span_diagnostic
.span_fatal(
self.p.token.span,
&format!("expected item, found `{}`", token),
)
.raise();
}
}
}
Some(ret)

View File

@ -26,7 +26,7 @@ error: expected `{`, found `;`
--> $DIR/issue-46836-identifier-not-instead-of-negation.rs:20:31
|
LL | if not // lack of braces is [sic]
| -- this `if` statement has a condition, but no block
| -- this `if` expression has a condition, but no block
LL | println!("Then when?");
| ^
| |

View File

@ -2,7 +2,7 @@ warning: irrefutable if-let pattern
--> $DIR/if-let.rs:6:13
|
LL | if let $p = $e $b
| ^^
| ^^^^^^^^^^^^^^^^^
...
LL | / foo!(a, 1, {
LL | | println!("irrefutable pattern");
@ -15,7 +15,7 @@ warning: irrefutable if-let pattern
--> $DIR/if-let.rs:6:13
|
LL | if let $p = $e $b
| ^^
| ^^^^^^^^^^^^^^^^^
...
LL | / bar!(a, 1, {
LL | | println!("irrefutable pattern");

View File

@ -1,7 +1,7 @@
fn main() {
let n = 1;
if 5 == {
//~^ NOTE this `if` statement has a condition, but no block
//~^ NOTE this `if` expression has a condition, but no block
println!("five");
}
}

View File

@ -2,7 +2,7 @@ error: expected `{`, found `}`
--> $DIR/if-without-block.rs:7:1
|
LL | if 5 == {
| -- this `if` statement has a condition, but no block
| -- this `if` expression has a condition, but no block
...
LL | }
| ^ expected `{`

View File

@ -1,6 +1,7 @@
fn main() {
if true {
} else if { //~ ERROR missing condition
//~^ ERROR mismatched types
} else {
}
}
@ -8,6 +9,7 @@ fn main() {
fn foo() {
if true {
} else if { //~ ERROR missing condition
//~^ ERROR mismatched types
}
bar();
}

View File

@ -5,10 +5,29 @@ LL | } else if {
| ^ expected if condition here
error: missing condition for `if` expression
--> $DIR/issue-13483.rs:10:14
--> $DIR/issue-13483.rs:11:14
|
LL | } else if {
| ^ expected if condition here
error: aborting due to 2 previous errors
error[E0308]: mismatched types
--> $DIR/issue-13483.rs:3:15
|
LL | } else if {
| _______________^
LL | |
LL | | } else {
| |_____^ expected `bool`, found `()`
error[E0308]: mismatched types
--> $DIR/issue-13483.rs:11:15
|
LL | } else if {
| _______________^
LL | |
LL | | }
| |_____^ expected `bool`, found `()`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -4,7 +4,7 @@ error: expected `{`, found `foo`
LL | if $tgt.has_$field() {}
| -- -- help: try placing this code inside a block: `{ () }`
| |
| this `if` statement has a condition, but no block
| this `if` expression has a condition, but no block
...
LL | get_opt!(bar, foo);
| ^^^ expected `{`

View File

@ -4,7 +4,7 @@ error: expected `{`, found keyword `in`
LL | if i in 1..10 {
| -- ^^ expected `{`
| |
| this `if` statement has a condition, but no block
| this `if` expression has a condition, but no block
error: aborting due to previous error

View File

@ -4,7 +4,7 @@ error: expected `{`, found `)`
LL | (if foobar)
| -- ^ expected `{`
| |
| this `if` statement has a condition, but no block
| this `if` expression has a condition, but no block
error: aborting due to previous error

View File

@ -17,7 +17,7 @@ error: expected `{`, found `macro_rules`
LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 {
| -- ^^^^^^^^^^^ expected `{`
| |
| this `if` statement has a condition, but no block
| this `if` expression has a condition, but no block
|
help: try placing this code inside a block
|

View File

@ -12,7 +12,7 @@ LL | if true 'b: {}
| | |
| | expected `{`
| | help: try placing this code inside a block: `{ 'b: {} }`
| this `if` statement has a condition, but no block
| this `if` expression has a condition, but no block
error: expected `{`, found `'b`
--> $DIR/label_break_value_illegal_uses.rs:14:21

View File

@ -4,13 +4,13 @@ error: expected `{`, found `=>`
LL | if (foo) => {}
| -- ^^ expected `{`
| |
| this `if` statement has a condition, but no block
| this `if` expression has a condition, but no block
error: expected `{`, found `bar`
--> $DIR/missing-block-hint.rs:7:13
|
LL | if (foo)
| -- this `if` statement has a condition, but no block
| -- this `if` expression has a condition, but no block
LL | bar;
| ^^^-
| |

View File

@ -1,2 +0,0 @@
#[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
//~^ ERROR unexpected token: `#`

View File

@ -1,8 +0,0 @@
error: unexpected token: `#`
--> $DIR/attr-stmt-expr-attr-bad-2.rs:1:34
|
LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
| ^
error: aborting due to previous error

View File

@ -1,2 +0,0 @@
#[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
//~^ ERROR unexpected token: `#`

View File

@ -1,8 +0,0 @@
error: unexpected token: `#`
--> $DIR/attr-stmt-expr-attr-bad-3.rs:1:34
|
LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
| ^
error: aborting due to previous error

View File

@ -101,6 +101,13 @@ fn main() {}
//~^ ERROR `X..=` range patterns are not supported
//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
#[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
//~^ ERROR unexpected token: `#`
//~| ERROR expected one of `.`
#[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
//~^ ERROR unexpected token: `#`
//~| ERROR expected one of `.`
// make sure we don't catch this bug again...
#[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } }
//~^ ERROR expected statement after outer attribute

View File

@ -149,7 +149,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
| | |
| | expected `{`
| this `if` statement has a condition, but no block
| this `if` expression has a condition, but no block
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:43:38
@ -202,7 +202,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
| | |
| | expected `{`
| this `if` statement has a condition, but no block
| this `if` expression has a condition, but no block
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:56:51
@ -225,7 +225,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
| | |
| | expected `{`
| this `if` statement has a condition, but no block
| this `if` expression has a condition, but no block
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:62:46
@ -278,7 +278,7 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
| | |
| | expected `{`
| this `if` statement has a condition, but no block
| this `if` expression has a condition, but no block
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:75:67
@ -380,11 +380,35 @@ error: expected one of `=>`, `if`, or `|`, found `#`
LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
| ^ expected one of `=>`, `if`, or `|`
error: unexpected token: `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:104:34
|
LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
| ^
error: expected one of `.`, `;`, `?`, or an operator, found `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:104:34
|
LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
| ^ expected one of `.`, `;`, `?`, or an operator
error: unexpected token: `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:107:34
|
LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
| ^
error: expected one of `.`, `;`, `?`, or an operator, found `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:107:34
|
LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
| ^ expected one of `.`, `;`, `?`, or an operator
error: expected statement after outer attribute
--> $DIR/attr-stmt-expr-attr-bad.rs:105:44
--> $DIR/attr-stmt-expr-attr-bad.rs:112:44
|
LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } }
| ^
error: aborting due to 52 previous errors
error: aborting due to 56 previous errors

View File

@ -4,7 +4,7 @@ error: expected `{`, found doc comment `/*!*/`
LL | if true /*!*/ {}
| -- ^^^^^ expected `{`
| |
| this `if` statement has a condition, but no block
| this `if` expression has a condition, but no block
error: aborting due to previous error

View File

@ -2,7 +2,7 @@ warning: irrefutable while-let pattern
--> $DIR/while-let.rs:7:13
|
LL | while let $p = $e $b
| ^^^^^
| ^^^^^^^^^^^^^^^^^^^^
...
LL | / foo!(_a, 1, {
LL | | println!("irrefutable pattern");
@ -15,7 +15,7 @@ warning: irrefutable while-let pattern
--> $DIR/while-let.rs:7:13
|
LL | while let $p = $e $b
| ^^^^^
| ^^^^^^^^^^^^^^^^^^^^
...
LL | / bar!(_a, 1, {
LL | | println!("irrefutable pattern");