summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_parse/src/parser/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src/parser/mod.rs')
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs142
1 files changed, 95 insertions, 47 deletions
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 5fe29062b..bebb01266 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -22,10 +22,11 @@ use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::AttributesData;
use rustc_ast::tokenstream::{self, DelimSpan, Spacing};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_ast::util::case::Case;
use rustc_ast::AttrId;
use rustc_ast::DUMMY_NODE_ID;
-use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, Extern};
-use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacArgsEq, MacDelimiter, Mutability, StrLit};
+use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, DelimArgs, Extern};
+use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutability, StrLit};
use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
@@ -104,6 +105,7 @@ macro_rules! maybe_whole {
macro_rules! maybe_recover_from_interpolated_ty_qpath {
($self: expr, $allow_qpath_recovery: expr) => {
if $allow_qpath_recovery
+ && $self.may_recover()
&& $self.look_ahead(1, |t| t == &token::ModSep)
&& let token::Interpolated(nt) = &$self.token.kind
&& let token::NtTy(ty) = &**nt
@@ -382,8 +384,8 @@ enum TokenType {
impl TokenType {
fn to_string(&self) -> String {
- match *self {
- TokenType::Token(ref t) => format!("`{}`", pprust::token_kind_to_string(t)),
+ match self {
+ TokenType::Token(t) => format!("`{}`", pprust::token_kind_to_string(t)),
TokenType::Keyword(kw) => format!("`{}`", kw),
TokenType::Operator => "an operator".to_string(),
TokenType::Lifetime => "lifetime".to_string(),
@@ -501,8 +503,8 @@ impl<'a> Parser<'a> {
parser
}
- pub fn forbid_recovery(mut self) -> Self {
- self.recovery = Recovery::Forbidden;
+ pub fn recovery(mut self, recovery: Recovery) -> Self {
+ self.recovery = recovery;
self
}
@@ -635,6 +637,20 @@ impl<'a> Parser<'a> {
self.token.is_keyword(kw)
}
+ fn check_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
+ if self.check_keyword(kw) {
+ return true;
+ }
+
+ if case == Case::Insensitive
+ && let Some((ident, /* is_raw */ false)) = self.token.ident()
+ && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() {
+ true
+ } else {
+ false
+ }
+ }
+
/// If the next token is the given keyword, eats it and returns `true`.
/// Otherwise, returns `false`. An expectation is also added for diagnostics purposes.
// Public for rustfmt usage.
@@ -647,6 +663,33 @@ impl<'a> Parser<'a> {
}
}
+ /// Eats a keyword, optionally ignoring the case.
+ /// If the case differs (and is ignored) an error is issued.
+ /// This is useful for recovery.
+ fn eat_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
+ if self.eat_keyword(kw) {
+ return true;
+ }
+
+ if case == Case::Insensitive
+ && let Some((ident, /* is_raw */ false)) = self.token.ident()
+ && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() {
+ self
+ .struct_span_err(ident.span, format!("keyword `{kw}` is written in a wrong case"))
+ .span_suggestion(
+ ident.span,
+ "write it in the correct case",
+ kw,
+ Applicability::MachineApplicable
+ ).emit();
+
+ self.bump();
+ return true;
+ }
+
+ false
+ }
+
fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool {
if self.token.is_keyword(kw) {
self.bump();
@@ -695,8 +738,8 @@ impl<'a> Parser<'a> {
fn check_inline_const(&self, dist: usize) -> bool {
self.is_keyword_ahead(dist, &[kw::Const])
- && self.look_ahead(dist + 1, |t| match t.kind {
- token::Interpolated(ref nt) => matches!(**nt, token::NtBlock(..)),
+ && self.look_ahead(dist + 1, |t| match &t.kind {
+ token::Interpolated(nt) => matches!(**nt, token::NtBlock(..)),
token::OpenDelim(Delimiter::Brace) => true,
_ => false,
})
@@ -817,7 +860,7 @@ impl<'a> Parser<'a> {
if let token::CloseDelim(..) | token::Eof = self.token.kind {
break;
}
- if let Some(ref t) = sep.sep {
+ if let Some(t) = &sep.sep {
if first {
first = false;
} else {
@@ -852,7 +895,7 @@ impl<'a> Parser<'a> {
_ => {
// Attempt to keep parsing if it was a similar separator.
- if let Some(ref tokens) = t.similar_tokens() {
+ if let Some(tokens) = t.similar_tokens() {
if tokens.contains(&self.token.kind) && !unclosed_delims {
self.bump();
}
@@ -900,6 +943,10 @@ impl<'a> Parser<'a> {
Err(e) => {
// Parsing failed, therefore it must be something more serious
// than just a missing separator.
+ for xx in &e.children {
+ // propagate the help message from sub error 'e' to main error 'expect_err;
+ expect_err.children.push(xx.clone());
+ }
expect_err.emit();
e.cancel();
@@ -1126,8 +1173,8 @@ impl<'a> Parser<'a> {
}
/// Parses asyncness: `async` or nothing.
- fn parse_asyncness(&mut self) -> Async {
- if self.eat_keyword(kw::Async) {
+ fn parse_asyncness(&mut self, case: Case) -> Async {
+ if self.eat_keyword_case(kw::Async, case) {
let span = self.prev_token.uninterpolated_span();
Async::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
} else {
@@ -1136,8 +1183,8 @@ impl<'a> Parser<'a> {
}
/// Parses unsafety: `unsafe` or nothing.
- fn parse_unsafety(&mut self) -> Unsafe {
- if self.eat_keyword(kw::Unsafe) {
+ fn parse_unsafety(&mut self, case: Case) -> Unsafe {
+ if self.eat_keyword_case(kw::Unsafe, case) {
Unsafe::Yes(self.prev_token.uninterpolated_span())
} else {
Unsafe::No
@@ -1145,10 +1192,10 @@ impl<'a> Parser<'a> {
}
/// Parses constness: `const` or nothing.
- fn parse_constness(&mut self) -> Const {
+ fn parse_constness(&mut self, case: Case) -> Const {
// Avoid const blocks to be parsed as const items
if self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace))
- && self.eat_keyword(kw::Const)
+ && self.eat_keyword_case(kw::Const, case)
{
Const::Yes(self.prev_token.uninterpolated_span())
} else {
@@ -1206,39 +1253,40 @@ impl<'a> Parser<'a> {
}
}
- fn parse_mac_args(&mut self) -> PResult<'a, P<MacArgs>> {
- self.parse_mac_args_common(true).map(P)
+ fn parse_delim_args(&mut self) -> PResult<'a, P<DelimArgs>> {
+ if let Some(args) = self.parse_delim_args_inner() { Ok(P(args)) } else { self.unexpected() }
}
- fn parse_attr_args(&mut self) -> PResult<'a, MacArgs> {
- self.parse_mac_args_common(false)
+ fn parse_attr_args(&mut self) -> PResult<'a, AttrArgs> {
+ Ok(if let Some(args) = self.parse_delim_args_inner() {
+ AttrArgs::Delimited(args)
+ } else {
+ if self.eat(&token::Eq) {
+ let eq_span = self.prev_token.span;
+ AttrArgs::Eq(eq_span, AttrArgsEq::Ast(self.parse_expr_force_collect()?))
+ } else {
+ AttrArgs::Empty
+ }
+ })
}
- fn parse_mac_args_common(&mut self, delimited_only: bool) -> PResult<'a, MacArgs> {
- Ok(
- if self.check(&token::OpenDelim(Delimiter::Parenthesis))
- || self.check(&token::OpenDelim(Delimiter::Bracket))
- || self.check(&token::OpenDelim(Delimiter::Brace))
- {
- match self.parse_token_tree() {
- TokenTree::Delimited(dspan, delim, tokens) =>
- // We've confirmed above that there is a delimiter so unwrapping is OK.
- {
- MacArgs::Delimited(dspan, MacDelimiter::from_token(delim).unwrap(), tokens)
- }
- _ => unreachable!(),
- }
- } else if !delimited_only {
- if self.eat(&token::Eq) {
- let eq_span = self.prev_token.span;
- MacArgs::Eq(eq_span, MacArgsEq::Ast(self.parse_expr_force_collect()?))
- } else {
- MacArgs::Empty
- }
- } else {
- return self.unexpected();
- },
- )
+ fn parse_delim_args_inner(&mut self) -> Option<DelimArgs> {
+ if self.check(&token::OpenDelim(Delimiter::Parenthesis))
+ || self.check(&token::OpenDelim(Delimiter::Bracket))
+ || self.check(&token::OpenDelim(Delimiter::Brace))
+ {
+ match self.parse_token_tree() {
+ // We've confirmed above that there is a delimiter so unwrapping is OK.
+ TokenTree::Delimited(dspan, delim, tokens) => Some(DelimArgs {
+ dspan,
+ delim: MacDelimiter::from_token(delim).unwrap(),
+ tokens,
+ }),
+ _ => unreachable!(),
+ }
+ } else {
+ None
+ }
}
fn parse_or_use_outer_attributes(
@@ -1403,8 +1451,8 @@ impl<'a> Parser<'a> {
}
/// Parses `extern string_literal?`.
- fn parse_extern(&mut self) -> Extern {
- if self.eat_keyword(kw::Extern) {
+ fn parse_extern(&mut self, case: Case) -> Extern {
+ if self.eat_keyword_case(kw::Extern, case) {
let mut extern_span = self.prev_token.span;
let abi = self.parse_abi();
if let Some(abi) = abi {