Add newtype for parser recovery
This commit is contained in:
parent
f5d0d087ad
commit
4850ae8442
6 changed files with 57 additions and 44 deletions
|
@ -10,6 +10,7 @@ use rustc_ast::{
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan, PResult, SingleLabelManySpans};
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_parse::parser::Recovered;
|
||||
use rustc_parse_format as parse;
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::{BytePos, InnerSpan, Span};
|
||||
|
@ -111,9 +112,8 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
|||
_ => return Err(err),
|
||||
}
|
||||
}
|
||||
Ok(recovered) => {
|
||||
assert!(recovered);
|
||||
}
|
||||
Ok(Recovered::Yes) => (),
|
||||
Ok(Recovered::No) => unreachable!(),
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
|
|
|
@ -22,6 +22,7 @@ use crate::fluent_generated as fluent;
|
|||
use crate::parser;
|
||||
use crate::parser::attr::InnerAttrPolicy;
|
||||
use ast::token::IdentIsRaw;
|
||||
use parser::Recovered;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind};
|
||||
|
@ -430,7 +431,7 @@ impl<'a> Parser<'a> {
|
|||
&mut self,
|
||||
edible: &[TokenKind],
|
||||
inedible: &[TokenKind],
|
||||
) -> PResult<'a, bool /* recovered */> {
|
||||
) -> PResult<'a, Recovered> {
|
||||
debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
|
||||
fn tokens_to_string(tokens: &[TokenType]) -> String {
|
||||
let mut i = tokens.iter();
|
||||
|
@ -533,7 +534,7 @@ impl<'a> Parser<'a> {
|
|||
sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span),
|
||||
});
|
||||
self.bump();
|
||||
return Ok(true);
|
||||
return Ok(Recovered::Yes);
|
||||
} else if self.look_ahead(0, |t| {
|
||||
t == &token::CloseDelim(Delimiter::Brace)
|
||||
|| ((t.can_begin_expr() || t.can_begin_item())
|
||||
|
@ -557,7 +558,7 @@ impl<'a> Parser<'a> {
|
|||
unexpected_token_label: Some(self.token.span),
|
||||
sugg: ExpectedSemiSugg::AddSemi(span),
|
||||
});
|
||||
return Ok(true);
|
||||
return Ok(Recovered::Yes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -712,7 +713,7 @@ impl<'a> Parser<'a> {
|
|||
if self.check_too_many_raw_str_terminators(&mut err) {
|
||||
if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) {
|
||||
err.emit();
|
||||
return Ok(true);
|
||||
return Ok(Recovered::Yes);
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
|
@ -1224,7 +1225,7 @@ impl<'a> Parser<'a> {
|
|||
|p| p.parse_generic_arg(None),
|
||||
);
|
||||
match x {
|
||||
Ok((_, _, false)) => {
|
||||
Ok((_, _, Recovered::No)) => {
|
||||
if self.eat(&token::Gt) {
|
||||
// We made sense of it. Improve the error message.
|
||||
e.span_suggestion_verbose(
|
||||
|
@ -1248,7 +1249,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Ok((_, _, true)) => {}
|
||||
Ok((_, _, Recovered::Yes)) => {}
|
||||
Err(err) => {
|
||||
err.cancel();
|
||||
}
|
||||
|
@ -1841,10 +1842,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Creates a `DiagnosticBuilder` for an unexpected token `t` and tries to recover if it is a
|
||||
/// closing delimiter.
|
||||
pub(super) fn unexpected_try_recover(
|
||||
&mut self,
|
||||
t: &TokenKind,
|
||||
) -> PResult<'a, bool /* recovered */> {
|
||||
pub(super) fn unexpected_try_recover(&mut self, t: &TokenKind) -> PResult<'a, Recovered> {
|
||||
let token_str = pprust::token_kind_to_string(t);
|
||||
let this_token_str = super::token_descr(&self.token);
|
||||
let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {
|
||||
|
|
|
@ -3,7 +3,7 @@ use super::diagnostics::SnapshotParser;
|
|||
use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
|
||||
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
|
||||
use super::{
|
||||
AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
|
||||
AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Recovered, Restrictions,
|
||||
SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
|
||||
};
|
||||
|
||||
|
@ -3093,10 +3093,10 @@ impl<'a> Parser<'a> {
|
|||
if !require_comma {
|
||||
arm_body = Some(expr);
|
||||
this.eat(&token::Comma);
|
||||
Ok(false)
|
||||
Ok(Recovered::No)
|
||||
} else if let Some(body) = this.parse_arm_body_missing_braces(&expr, arrow_span) {
|
||||
arm_body = Some(body);
|
||||
Ok(true)
|
||||
Ok(Recovered::Yes)
|
||||
} else {
|
||||
let expr_span = expr.span;
|
||||
arm_body = Some(expr);
|
||||
|
@ -3177,7 +3177,7 @@ impl<'a> Parser<'a> {
|
|||
this.dcx().emit_err(errors::MissingCommaAfterMatchArm {
|
||||
span: arm_span.shrink_to_hi(),
|
||||
});
|
||||
return Ok(true);
|
||||
return Ok(Recovered::Yes);
|
||||
}
|
||||
Err(err)
|
||||
});
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
|
||||
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
|
||||
use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
|
||||
use super::{
|
||||
AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Recovered, TrailingToken,
|
||||
};
|
||||
use crate::errors::{self, MacroExpandsToAdtField};
|
||||
use crate::fluent_generated as fluent;
|
||||
use ast::token::IdentIsRaw;
|
||||
|
@ -1534,10 +1536,10 @@ impl<'a> Parser<'a> {
|
|||
err.span_label(span, "while parsing this enum");
|
||||
err.help(help);
|
||||
err.emit();
|
||||
(thin_vec![], true)
|
||||
(thin_vec![], Recovered::Yes)
|
||||
}
|
||||
};
|
||||
VariantData::Struct { fields, recovered }
|
||||
VariantData::Struct { fields, recovered: recovered.into() }
|
||||
} else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
|
||||
let body = match this.parse_tuple_struct_body() {
|
||||
Ok(body) => body,
|
||||
|
@ -1622,7 +1624,7 @@ impl<'a> Parser<'a> {
|
|||
class_name.span,
|
||||
generics.where_clause.has_where_token,
|
||||
)?;
|
||||
VariantData::Struct { fields, recovered }
|
||||
VariantData::Struct { fields, recovered: recovered.into() }
|
||||
}
|
||||
// No `where` so: `struct Foo<T>;`
|
||||
} else if self.eat(&token::Semi) {
|
||||
|
@ -1634,7 +1636,7 @@ impl<'a> Parser<'a> {
|
|||
class_name.span,
|
||||
generics.where_clause.has_where_token,
|
||||
)?;
|
||||
VariantData::Struct { fields, recovered }
|
||||
VariantData::Struct { fields, recovered: recovered.into() }
|
||||
// Tuple-style struct definition with optional where-clause.
|
||||
} else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
|
||||
let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID);
|
||||
|
@ -1663,14 +1665,14 @@ impl<'a> Parser<'a> {
|
|||
class_name.span,
|
||||
generics.where_clause.has_where_token,
|
||||
)?;
|
||||
VariantData::Struct { fields, recovered }
|
||||
VariantData::Struct { fields, recovered: recovered.into() }
|
||||
} else if self.token == token::OpenDelim(Delimiter::Brace) {
|
||||
let (fields, recovered) = self.parse_record_struct_body(
|
||||
"union",
|
||||
class_name.span,
|
||||
generics.where_clause.has_where_token,
|
||||
)?;
|
||||
VariantData::Struct { fields, recovered }
|
||||
VariantData::Struct { fields, recovered: recovered.into() }
|
||||
} else {
|
||||
let token_str = super::token_descr(&self.token);
|
||||
let msg = format!("expected `where` or `{{` after union name, found {token_str}");
|
||||
|
@ -1687,14 +1689,14 @@ impl<'a> Parser<'a> {
|
|||
adt_ty: &str,
|
||||
ident_span: Span,
|
||||
parsed_where: bool,
|
||||
) -> PResult<'a, (ThinVec<FieldDef>, /* recovered */ bool)> {
|
||||
) -> PResult<'a, (ThinVec<FieldDef>, Recovered)> {
|
||||
let mut fields = ThinVec::new();
|
||||
let mut recovered = false;
|
||||
let mut recovered = Recovered::No;
|
||||
if self.eat(&token::OpenDelim(Delimiter::Brace)) {
|
||||
while self.token != token::CloseDelim(Delimiter::Brace) {
|
||||
let field = self.parse_field_def(adt_ty).map_err(|e| {
|
||||
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::No);
|
||||
recovered = true;
|
||||
recovered = Recovered::Yes;
|
||||
e
|
||||
});
|
||||
match field {
|
||||
|
@ -2465,8 +2467,8 @@ impl<'a> Parser<'a> {
|
|||
// `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
|
||||
// account for this.
|
||||
match self.expect_one_of(&[], &[]) {
|
||||
Ok(true) => {}
|
||||
Ok(false) => unreachable!(),
|
||||
Ok(Recovered::Yes) => {}
|
||||
Ok(Recovered::No) => unreachable!(),
|
||||
Err(mut err) => {
|
||||
// Qualifier keywords ordering check
|
||||
enum WrongKw {
|
||||
|
|
|
@ -358,6 +358,19 @@ pub enum FollowedByType {
|
|||
No,
|
||||
}
|
||||
|
||||
/// Whether a function performed recovery
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Recovered {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
|
||||
impl From<Recovered> for bool {
|
||||
fn from(r: Recovered) -> bool {
|
||||
matches!(r, Recovered::Yes)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum TokenDescription {
|
||||
ReservedIdentifier,
|
||||
|
@ -456,11 +469,11 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
/// Expects and consumes the token `t`. Signals an error if the next token is not `t`.
|
||||
pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, bool /* recovered */> {
|
||||
pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, Recovered> {
|
||||
if self.expected_tokens.is_empty() {
|
||||
if self.token == *t {
|
||||
self.bump();
|
||||
Ok(false)
|
||||
Ok(Recovered::No)
|
||||
} else {
|
||||
self.unexpected_try_recover(t)
|
||||
}
|
||||
|
@ -476,13 +489,13 @@ impl<'a> Parser<'a> {
|
|||
&mut self,
|
||||
edible: &[TokenKind],
|
||||
inedible: &[TokenKind],
|
||||
) -> PResult<'a, bool /* recovered */> {
|
||||
) -> PResult<'a, Recovered> {
|
||||
if edible.contains(&self.token.kind) {
|
||||
self.bump();
|
||||
Ok(false)
|
||||
Ok(Recovered::No)
|
||||
} else if inedible.contains(&self.token.kind) {
|
||||
// leave it in the input
|
||||
Ok(false)
|
||||
Ok(Recovered::No)
|
||||
} else if self.token.kind != token::Eof
|
||||
&& self.last_unexpected_token_span == Some(self.token.span)
|
||||
{
|
||||
|
@ -784,9 +797,9 @@ impl<'a> Parser<'a> {
|
|||
sep: SeqSep,
|
||||
expect: TokenExpectType,
|
||||
mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
) -> PResult<'a, (ThinVec<T>, bool /* trailing */, bool /* recovered */)> {
|
||||
) -> PResult<'a, (ThinVec<T>, bool /* trailing */, Recovered)> {
|
||||
let mut first = true;
|
||||
let mut recovered = false;
|
||||
let mut recovered = Recovered::No;
|
||||
let mut trailing = false;
|
||||
let mut v = ThinVec::new();
|
||||
|
||||
|
@ -801,12 +814,12 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
// check for separator
|
||||
match self.expect(t) {
|
||||
Ok(false) /* not recovered */ => {
|
||||
Ok(Recovered::No) => {
|
||||
self.current_closure.take();
|
||||
}
|
||||
Ok(true) /* recovered */ => {
|
||||
Ok(Recovered::Yes) => {
|
||||
self.current_closure.take();
|
||||
recovered = true;
|
||||
recovered = Recovered::Yes;
|
||||
break;
|
||||
}
|
||||
Err(mut expect_err) => {
|
||||
|
@ -979,7 +992,7 @@ impl<'a> Parser<'a> {
|
|||
ket: &TokenKind,
|
||||
sep: SeqSep,
|
||||
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
) -> PResult<'a, (ThinVec<T>, bool /* trailing */, bool /* recovered */)> {
|
||||
) -> PResult<'a, (ThinVec<T>, bool /* trailing */, Recovered)> {
|
||||
self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
|
||||
}
|
||||
|
||||
|
@ -993,7 +1006,7 @@ impl<'a> Parser<'a> {
|
|||
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> {
|
||||
let (val, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
|
||||
if !recovered {
|
||||
if matches!(recovered, Recovered::No) {
|
||||
self.eat(ket);
|
||||
}
|
||||
Ok((val, trailing))
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::errors;
|
|||
use crate::maybe_whole;
|
||||
|
||||
use crate::errors::MalformedLoopLabel;
|
||||
use crate::parser::Recovered;
|
||||
use ast::Label;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
|
@ -661,7 +662,6 @@ impl<'a> Parser<'a> {
|
|||
if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) =>
|
||||
{
|
||||
// Just check for errors and recover; do not eat semicolon yet.
|
||||
// `expect_one_of` returns PResult<'a, bool /* recovered */>
|
||||
|
||||
let expect_result =
|
||||
self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]);
|
||||
|
@ -669,7 +669,7 @@ impl<'a> Parser<'a> {
|
|||
let replace_with_err = 'break_recover: {
|
||||
match expect_result {
|
||||
// Recover from parser, skip type error to avoid extra errors.
|
||||
Ok(true) => true,
|
||||
Ok(Recovered::Yes) => true,
|
||||
Err(e) => {
|
||||
if self.recover_colon_as_semi() {
|
||||
// recover_colon_as_semi has already emitted a nicer error.
|
||||
|
@ -735,7 +735,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
true
|
||||
}
|
||||
Ok(false) => false,
|
||||
Ok(Recovered::No) => false,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue