Rollup merge of #59266 - estebank:struct-parse-recovery, r=petrochenkov

Do not complain about non-existing fields after parse recovery

When failing to parse struct-like enum variants, the ADT gets recorded
as having no fields. Record that we have actually recovered during
parsing of this variant to avoid complaing about non-existing fields
when actually using it.

Fix #57361.
This commit is contained in:
Mazdak Farrokhzad
2019-03-22 19:31:24 +01:00
committed by GitHub
15 changed files with 111 additions and 58 deletions

View File

@@ -6837,14 +6837,16 @@ impl<'a> Parser<'a> {
VariantData::Unit(ast::DUMMY_NODE_ID)
} else {
// If we see: `struct Foo<T> where T: Copy { ... }`
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
let (fields, recovered) = self.parse_record_struct_body()?;
VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
}
// No `where` so: `struct Foo<T>;`
} else if self.eat(&token::Semi) {
VariantData::Unit(ast::DUMMY_NODE_ID)
// Record-style struct definition
} else if self.token == token::OpenDelim(token::Brace) {
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
let (fields, recovered) = self.parse_record_struct_body()?;
VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
// Tuple-style struct definition with optional where-clause.
} else if self.token == token::OpenDelim(token::Paren) {
let body = VariantData::Tuple(self.parse_tuple_struct_body()?, ast::DUMMY_NODE_ID);
@@ -6872,9 +6874,11 @@ impl<'a> Parser<'a> {
let vdata = if self.token.is_keyword(keywords::Where) {
generics.where_clause = self.parse_where_clause()?;
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
let (fields, recovered) = self.parse_record_struct_body()?;
VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
} else if self.token == token::OpenDelim(token::Brace) {
VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID)
let (fields, recovered) = self.parse_record_struct_body()?;
VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered)
} else {
let token_str = self.this_token_descr();
let mut err = self.fatal(&format!(
@@ -6906,12 +6910,16 @@ impl<'a> Parser<'a> {
}
}
fn parse_record_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
fn parse_record_struct_body(
&mut self,
) -> PResult<'a, (Vec<StructField>, /* recovered */ bool)> {
let mut fields = Vec::new();
let mut recovered = false;
if self.eat(&token::OpenDelim(token::Brace)) {
while self.token != token::CloseDelim(token::Brace) {
let field = self.parse_struct_decl_field().map_err(|e| {
self.recover_stmt();
recovered = true;
e
});
match field {
@@ -6930,7 +6938,7 @@ impl<'a> Parser<'a> {
return Err(err);
}
Ok(fields)
Ok((fields, recovered))
}
fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
@@ -7693,12 +7701,14 @@ impl<'a> Parser<'a> {
if self.check(&token::OpenDelim(token::Brace)) {
// Parse a struct variant.
all_nullary = false;
struct_def = VariantData::Struct(self.parse_record_struct_body()?,
ast::DUMMY_NODE_ID);
let (fields, recovered) = self.parse_record_struct_body()?;
struct_def = VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered);
} else if self.check(&token::OpenDelim(token::Paren)) {
all_nullary = false;
struct_def = VariantData::Tuple(self.parse_tuple_struct_body()?,
ast::DUMMY_NODE_ID);
struct_def = VariantData::Tuple(
self.parse_tuple_struct_body()?,
ast::DUMMY_NODE_ID,
);
} else if self.eat(&token::Eq) {
disr_expr = Some(AnonConst {
id: ast::DUMMY_NODE_ID,