Skip to content

Commit 9eaa532

Browse files
committed
Add newtype for parser recovery
1 parent b5310de commit 9eaa532

File tree

6 files changed

+58
-45
lines changed

6 files changed

+58
-45
lines changed

compiler/rustc_builtin_macros/src/format.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_ast::{
1010
use rustc_data_structures::fx::FxHashSet;
1111
use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan, PResult, SingleLabelManySpans};
1212
use rustc_expand::base::{self, *};
13+
use rustc_parse::parser::Recovered;
1314
use rustc_parse_format as parse;
1415
use rustc_span::symbol::{Ident, Symbol};
1516
use rustc_span::{BytePos, InnerSpan, Span};
@@ -111,9 +112,8 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
111112
_ => return Err(err),
112113
}
113114
}
114-
Ok(recovered) => {
115-
assert!(recovered);
116-
}
115+
Ok(Recovered::Yes) => (),
116+
Ok(Recovered::No) => unreachable!(),
117117
}
118118
}
119119
first = false;

compiler/rustc_parse/src/parser/diagnostics.rs

+8-10
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crate::fluent_generated as fluent;
2222
use crate::parser;
2323
use crate::parser::attr::InnerAttrPolicy;
2424
use ast::token::IdentIsRaw;
25+
use parser::Recovered;
2526
use rustc_ast as ast;
2627
use rustc_ast::ptr::P;
2728
use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind};
@@ -430,7 +431,7 @@ impl<'a> Parser<'a> {
430431
&mut self,
431432
edible: &[TokenKind],
432433
inedible: &[TokenKind],
433-
) -> PResult<'a, bool /* recovered */> {
434+
) -> PResult<'a, Recovered> {
434435
debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
435436
fn tokens_to_string(tokens: &[TokenType]) -> String {
436437
let mut i = tokens.iter();
@@ -533,7 +534,7 @@ impl<'a> Parser<'a> {
533534
sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span),
534535
});
535536
self.bump();
536-
return Ok(true);
537+
return Ok(Recovered::Yes);
537538
} else if self.look_ahead(0, |t| {
538539
t == &token::CloseDelim(Delimiter::Brace)
539540
|| ((t.can_begin_expr() || t.can_begin_item())
@@ -557,7 +558,7 @@ impl<'a> Parser<'a> {
557558
unexpected_token_label: Some(self.token.span),
558559
sugg: ExpectedSemiSugg::AddSemi(span),
559560
});
560-
return Ok(true);
561+
return Ok(Recovered::Yes);
561562
}
562563
}
563564

@@ -712,7 +713,7 @@ impl<'a> Parser<'a> {
712713
if self.check_too_many_raw_str_terminators(&mut err) {
713714
if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) {
714715
err.emit();
715-
return Ok(true);
716+
return Ok(Recovered::Yes);
716717
} else {
717718
return Err(err);
718719
}
@@ -1224,7 +1225,7 @@ impl<'a> Parser<'a> {
12241225
|p| p.parse_generic_arg(None),
12251226
);
12261227
match x {
1227-
Ok((_, _, false)) => {
1228+
Ok((_, _, Recovered::No)) => {
12281229
if self.eat(&token::Gt) {
12291230
// We made sense of it. Improve the error message.
12301231
e.span_suggestion_verbose(
@@ -1248,7 +1249,7 @@ impl<'a> Parser<'a> {
12481249
}
12491250
}
12501251
}
1251-
Ok((_, _, true)) => {}
1252+
Ok((_, _, Recovered::Yes)) => {}
12521253
Err(err) => {
12531254
err.cancel();
12541255
}
@@ -1841,10 +1842,7 @@ impl<'a> Parser<'a> {
18411842

18421843
/// Creates a `DiagnosticBuilder` for an unexpected token `t` and tries to recover if it is a
18431844
/// closing delimiter.
1844-
pub(super) fn unexpected_try_recover(
1845-
&mut self,
1846-
t: &TokenKind,
1847-
) -> PResult<'a, bool /* recovered */> {
1845+
pub(super) fn unexpected_try_recover(&mut self, t: &TokenKind) -> PResult<'a, Recovered> {
18481846
let token_str = pprust::token_kind_to_string(t);
18491847
let this_token_str = super::token_descr(&self.token);
18501848
let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {

compiler/rustc_parse/src/parser/expr.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use super::diagnostics::SnapshotParser;
33
use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
44
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
55
use super::{
6-
AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
6+
AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Recovered, Restrictions,
77
SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken,
88
};
99

@@ -3093,10 +3093,10 @@ impl<'a> Parser<'a> {
30933093
if !require_comma {
30943094
arm_body = Some(expr);
30953095
this.eat(&token::Comma);
3096-
Ok(false)
3096+
Ok(Recovered::No)
30973097
} else if let Some(body) = this.parse_arm_body_missing_braces(&expr, arrow_span) {
30983098
arm_body = Some(body);
3099-
Ok(true)
3099+
Ok(Recovered::Yes)
31003100
} else {
31013101
let expr_span = expr.span;
31023102
arm_body = Some(expr);
@@ -3177,7 +3177,7 @@ impl<'a> Parser<'a> {
31773177
this.dcx().emit_err(errors::MissingCommaAfterMatchArm {
31783178
span: arm_span.shrink_to_hi(),
31793179
});
3180-
return Ok(true);
3180+
return Ok(Recovered::Yes);
31813181
}
31823182
Err(err)
31833183
});

compiler/rustc_parse/src/parser/item.rs

+15-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
22
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
3-
use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
3+
use super::{
4+
AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Recovered, TrailingToken,
5+
};
46
use crate::errors::{self, MacroExpandsToAdtField};
57
use crate::fluent_generated as fluent;
68
use ast::token::IdentIsRaw;
@@ -1518,10 +1520,10 @@ impl<'a> Parser<'a> {
15181520
err.span_label(span, "while parsing this enum");
15191521
err.help(help);
15201522
err.emit();
1521-
(thin_vec![], true)
1523+
(thin_vec![], Recovered::Yes)
15221524
}
15231525
};
1524-
VariantData::Struct { fields, recovered }
1526+
VariantData::Struct { fields, recovered: recovered.into() }
15251527
} else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
15261528
let body = match this.parse_tuple_struct_body() {
15271529
Ok(body) => body,
@@ -1606,7 +1608,7 @@ impl<'a> Parser<'a> {
16061608
class_name.span,
16071609
generics.where_clause.has_where_token,
16081610
)?;
1609-
VariantData::Struct { fields, recovered }
1611+
VariantData::Struct { fields, recovered: recovered.into() }
16101612
}
16111613
// No `where` so: `struct Foo<T>;`
16121614
} else if self.eat(&token::Semi) {
@@ -1618,8 +1620,8 @@ impl<'a> Parser<'a> {
16181620
class_name.span,
16191621
generics.where_clause.has_where_token,
16201622
)?;
1621-
VariantData::Struct { fields, recovered }
1622-
// Tuple-style struct definition with optional where-clause.
1623+
VariantData::Struct { fields, recovered: recovered.into() }
1624+
// Tuple-style struct definition with optional where-clause.
16231625
} else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
16241626
let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID);
16251627
generics.where_clause = self.parse_where_clause()?;
@@ -1647,14 +1649,14 @@ impl<'a> Parser<'a> {
16471649
class_name.span,
16481650
generics.where_clause.has_where_token,
16491651
)?;
1650-
VariantData::Struct { fields, recovered }
1652+
VariantData::Struct { fields, recovered: recovered.into() }
16511653
} else if self.token == token::OpenDelim(Delimiter::Brace) {
16521654
let (fields, recovered) = self.parse_record_struct_body(
16531655
"union",
16541656
class_name.span,
16551657
generics.where_clause.has_where_token,
16561658
)?;
1657-
VariantData::Struct { fields, recovered }
1659+
VariantData::Struct { fields, recovered: recovered.into() }
16581660
} else {
16591661
let token_str = super::token_descr(&self.token);
16601662
let msg = format!("expected `where` or `{{` after union name, found {token_str}");
@@ -1671,14 +1673,14 @@ impl<'a> Parser<'a> {
16711673
adt_ty: &str,
16721674
ident_span: Span,
16731675
parsed_where: bool,
1674-
) -> PResult<'a, (ThinVec<FieldDef>, /* recovered */ bool)> {
1676+
) -> PResult<'a, (ThinVec<FieldDef>, Recovered)> {
16751677
let mut fields = ThinVec::new();
1676-
let mut recovered = false;
1678+
let mut recovered = Recovered::No;
16771679
if self.eat(&token::OpenDelim(Delimiter::Brace)) {
16781680
while self.token != token::CloseDelim(Delimiter::Brace) {
16791681
let field = self.parse_field_def(adt_ty).map_err(|e| {
16801682
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::No);
1681-
recovered = true;
1683+
recovered = Recovered::Yes;
16821684
e
16831685
});
16841686
match field {
@@ -2446,8 +2448,8 @@ impl<'a> Parser<'a> {
24462448
// `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
24472449
// account for this.
24482450
match self.expect_one_of(&[], &[]) {
2449-
Ok(true) => {}
2450-
Ok(false) => unreachable!(),
2451+
Ok(Recovered::Yes) => {}
2452+
Ok(Recovered::No) => unreachable!(),
24512453
Err(mut err) => {
24522454
// Qualifier keywords ordering check
24532455
enum WrongKw {

compiler/rustc_parse/src/parser/mod.rs

+25-12
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,19 @@ pub enum FollowedByType {
358358
No,
359359
}
360360

361+
/// Whether a function performed recovery
362+
#[derive(Copy, Clone, Debug)]
363+
pub enum Recovered {
364+
No,
365+
Yes,
366+
}
367+
368+
impl From<Recovered> for bool {
369+
fn from(r: Recovered) -> bool {
370+
matches!(r, Recovered::Yes)
371+
}
372+
}
373+
361374
#[derive(Clone, Copy, PartialEq, Eq)]
362375
pub enum TokenDescription {
363376
ReservedIdentifier,
@@ -456,11 +469,11 @@ impl<'a> Parser<'a> {
456469
}
457470

458471
/// Expects and consumes the token `t`. Signals an error if the next token is not `t`.
459-
pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, bool /* recovered */> {
472+
pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, Recovered> {
460473
if self.expected_tokens.is_empty() {
461474
if self.token == *t {
462475
self.bump();
463-
Ok(false)
476+
Ok(Recovered::No)
464477
} else {
465478
self.unexpected_try_recover(t)
466479
}
@@ -476,13 +489,13 @@ impl<'a> Parser<'a> {
476489
&mut self,
477490
edible: &[TokenKind],
478491
inedible: &[TokenKind],
479-
) -> PResult<'a, bool /* recovered */> {
492+
) -> PResult<'a, Recovered> {
480493
if edible.contains(&self.token.kind) {
481494
self.bump();
482-
Ok(false)
495+
Ok(Recovered::No)
483496
} else if inedible.contains(&self.token.kind) {
484497
// leave it in the input
485-
Ok(false)
498+
Ok(Recovered::No)
486499
} else if self.token.kind != token::Eof
487500
&& self.last_unexpected_token_span == Some(self.token.span)
488501
{
@@ -784,9 +797,9 @@ impl<'a> Parser<'a> {
784797
sep: SeqSep,
785798
expect: TokenExpectType,
786799
mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
787-
) -> PResult<'a, (ThinVec<T>, bool /* trailing */, bool /* recovered */)> {
800+
) -> PResult<'a, (ThinVec<T>, bool /* trailing */, Recovered)> {
788801
let mut first = true;
789-
let mut recovered = false;
802+
let mut recovered = Recovered::No;
790803
let mut trailing = false;
791804
let mut v = ThinVec::new();
792805

@@ -801,12 +814,12 @@ impl<'a> Parser<'a> {
801814
} else {
802815
// check for separator
803816
match self.expect(t) {
804-
Ok(false) /* not recovered */ => {
817+
Ok(Recovered::No) => {
805818
self.current_closure.take();
806819
}
807-
Ok(true) /* recovered */ => {
820+
Ok(Recovered::Yes) => {
808821
self.current_closure.take();
809-
recovered = true;
822+
recovered = Recovered::Yes;
810823
break;
811824
}
812825
Err(mut expect_err) => {
@@ -979,7 +992,7 @@ impl<'a> Parser<'a> {
979992
ket: &TokenKind,
980993
sep: SeqSep,
981994
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
982-
) -> PResult<'a, (ThinVec<T>, bool /* trailing */, bool /* recovered */)> {
995+
) -> PResult<'a, (ThinVec<T>, bool /* trailing */, Recovered)> {
983996
self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
984997
}
985998

@@ -993,7 +1006,7 @@ impl<'a> Parser<'a> {
9931006
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
9941007
) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> {
9951008
let (val, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
996-
if !recovered {
1009+
if matches!(recovered, Recovered::No) {
9971010
self.eat(ket);
9981011
}
9991012
Ok((val, trailing))

compiler/rustc_parse/src/parser/stmt.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::errors;
1111
use crate::maybe_whole;
1212

1313
use crate::errors::MalformedLoopLabel;
14+
use crate::parser::Recovered;
1415
use ast::Label;
1516
use rustc_ast as ast;
1617
use rustc_ast::ptr::P;
@@ -661,15 +662,14 @@ impl<'a> Parser<'a> {
661662
if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) =>
662663
{
663664
// Just check for errors and recover; do not eat semicolon yet.
664-
// `expect_one_of` returns PResult<'a, bool /* recovered */>
665665

666666
let expect_result =
667667
self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]);
668668

669669
let replace_with_err = 'break_recover: {
670670
match expect_result {
671671
// Recover from parser, skip type error to avoid extra errors.
672-
Ok(true) => true,
672+
Ok(Recovered::Yes) => true,
673673
Err(e) => {
674674
if self.recover_colon_as_semi() {
675675
// recover_colon_as_semi has already emitted a nicer error.
@@ -735,7 +735,7 @@ impl<'a> Parser<'a> {
735735

736736
true
737737
}
738-
Ok(false) => false,
738+
Ok(Recovered::No) => false,
739739
}
740740
};
741741

0 commit comments

Comments
 (0)