Skip to content

Commit

Permalink
Add newtype for parser recovery
Browse files Browse the repository at this point in the history
  • Loading branch information
clubby789 committed Feb 20, 2024
1 parent f5d0d08 commit 4850ae8
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 44 deletions.
6 changes: 3 additions & 3 deletions compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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;
Expand Down
18 changes: 8 additions & 10 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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())
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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(
Expand All @@ -1248,7 +1249,7 @@ impl<'a> Parser<'a> {
}
}
}
Ok((_, _, true)) => {}
Ok((_, _, Recovered::Yes)) => {}
Err(err) => {
err.cancel();
}
Expand Down Expand Up @@ -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) {
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
});
Expand Down
26 changes: 14 additions & 12 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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}");
Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
37 changes: 25 additions & 12 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
}
Expand All @@ -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)
{
Expand Down Expand Up @@ -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();

Expand All @@ -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) => {
Expand Down Expand Up @@ -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)
}

Expand All @@ -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))
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_parse/src/parser/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -661,15 +662,14 @@ 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)]);

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.
Expand Down Expand Up @@ -735,7 +735,7 @@ impl<'a> Parser<'a> {

true
}
Ok(false) => false,
Ok(Recovered::No) => false,
}
};

Expand Down

0 comments on commit 4850ae8

Please sign in to comment.