Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not complain about non-existing fields after parse recovery #59266

Merged
merged 2 commits into from
Mar 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2672,7 +2672,7 @@ impl<'a> LoweringContext<'a> {

fn lower_variant_data(&mut self, vdata: &VariantData) -> hir::VariantData {
match *vdata {
VariantData::Struct(ref fields, id) => {
VariantData::Struct(ref fields, id, recovered) => {
let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id);

hir::VariantData::Struct(
Expand All @@ -2682,6 +2682,7 @@ impl<'a> LoweringContext<'a> {
.map(|f| self.lower_struct_field(f))
.collect(),
hir_id,
recovered,
)
},
VariantData::Tuple(ref fields, id) => {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2173,7 +2173,7 @@ impl StructField {
/// Id of the whole struct lives in `Item`.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
pub enum VariantData {
Struct(HirVec<StructField>, HirId),
Struct(HirVec<StructField>, HirId, /* recovered */ bool),
Tuple(HirVec<StructField>, HirId),
Unit(HirId),
}
Expand All @@ -2187,7 +2187,7 @@ impl VariantData {
}
pub fn hir_id(&self) -> HirId {
match *self {
VariantData::Struct(_, hir_id)
VariantData::Struct(_, hir_id, _)
| VariantData::Tuple(_, hir_id)
| VariantData::Unit(hir_id) => hir_id,
}
Expand Down
28 changes: 16 additions & 12 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1811,6 +1811,7 @@ pub struct VariantDef {
pub fields: Vec<FieldDef>,
pub ctor_kind: CtorKind,
flags: VariantFlags,
pub recovered: bool,
}

impl<'a, 'gcx, 'tcx> VariantDef {
Expand All @@ -1829,16 +1830,17 @@ impl<'a, 'gcx, 'tcx> VariantDef {
///
/// If someone speeds up attribute loading to not be a performance concern, they can
/// remove this hack and use the constructor `DefId` everywhere.
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
did: DefId,
ident: Ident,
discr: VariantDiscr,
fields: Vec<FieldDef>,
adt_kind: AdtKind,
ctor_kind: CtorKind,
attribute_def_id: DefId)
-> Self
{
pub fn new(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
did: DefId,
ident: Ident,
discr: VariantDiscr,
fields: Vec<FieldDef>,
adt_kind: AdtKind,
ctor_kind: CtorKind,
attribute_def_id: DefId,
recovered: bool,
) -> Self {
debug!("VariantDef::new({:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?})", did, ident, discr,
fields, adt_kind, ctor_kind, attribute_def_id);
let mut flags = VariantFlags::NO_VARIANT_FLAGS;
Expand All @@ -1852,7 +1854,8 @@ impl<'a, 'gcx, 'tcx> VariantDef {
discr,
fields,
ctor_kind,
flags
flags,
recovered,
}
}

Expand All @@ -1868,7 +1871,8 @@ impl_stable_hash_for!(struct VariantDef {
discr,
fields,
ctor_kind,
flags
flags,
recovered
});

#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)]
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,8 @@ impl<'a, 'tcx> CrateMetadata {
}).collect(),
adt_kind,
data.ctor_kind,
attribute_def_id
attribute_def_id,
false,
)
}

Expand Down
6 changes: 3 additions & 3 deletions src/librustc_save_analysis/dump_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,8 +481,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
};

let (value, fields) = match item.node {
ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) |
ast::ItemKind::Union(ast::VariantData::Struct(ref fields, _), _) => {
ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, ..), _) |
ast::ItemKind::Union(ast::VariantData::Struct(ref fields, ..), _) => {
let include_priv_fields = !self.save_ctxt.config.pub_only;
let fields_str = fields
.iter()
Expand Down Expand Up @@ -560,7 +560,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
let name_span = variant.node.ident.span;

match variant.node.data {
ast::VariantData::Struct(ref fields, _) => {
ast::VariantData::Struct(ref fields, ..) => {
let fields_str = fields
.iter()
.enumerate()
Expand Down
18 changes: 11 additions & 7 deletions src/librustc_save_analysis/sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ impl Sig for ast::Variant_ {
fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
let mut text = self.ident.to_string();
match self.data {
ast::VariantData::Struct(ref fields, id) => {
ast::VariantData::Struct(ref fields, id, r) => {
let name_def = SigElement {
id: id_from_node_id(id, scx),
start: offset,
Expand All @@ -712,12 +712,16 @@ impl Sig for ast::Variant_ {
text.push_str(" { ");
let mut defs = vec![name_def];
let mut refs = vec![];
for f in fields {
let field_sig = f.make(offset + text.len(), Some(id), scx)?;
text.push_str(&field_sig.text);
text.push_str(", ");
defs.extend(field_sig.defs.into_iter());
refs.extend(field_sig.refs.into_iter());
if r {
text.push_str("/* parse error */ ");
} else {
for f in fields {
let field_sig = f.make(offset + text.len(), Some(id), scx)?;
text.push_str(&field_sig.text);
text.push_str(", ");
defs.extend(field_sig.defs.into_iter());
refs.extend(field_sig.refs.into_iter());
}
}
text.push('}');
Ok(Signature { text, defs, refs })
Expand Down
20 changes: 11 additions & 9 deletions src/librustc_typeck/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -918,14 +918,16 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
pat_ty
}

fn check_struct_pat_fields(&self,
adt_ty: Ty<'tcx>,
pat_id: hir::HirId,
span: Span,
variant: &'tcx ty::VariantDef,
fields: &'gcx [Spanned<hir::FieldPat>],
etc: bool,
def_bm: ty::BindingMode) -> bool {
fn check_struct_pat_fields(
&self,
adt_ty: Ty<'tcx>,
pat_id: hir::HirId,
span: Span,
variant: &'tcx ty::VariantDef,
fields: &'gcx [Spanned<hir::FieldPat>],
etc: bool,
def_bm: ty::BindingMode,
) -> bool {
let tcx = self.tcx;

let (substs, adt) = match adt_ty.sty {
Expand Down Expand Up @@ -985,7 +987,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
.map(|field| field.ident.modern())
.filter(|ident| !used_fields.contains_key(&ident))
.collect::<Vec<_>>();
if inexistent_fields.len() > 0 {
if inexistent_fields.len() > 0 && !variant.recovered {
let (field_names, t, plural) = if inexistent_fields.len() == 1 {
(format!("a field named `{}`", inexistent_fields[0].1), "this", "")
} else {
Expand Down
17 changes: 11 additions & 6 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3689,12 +3689,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
field, expr_t)
}

fn report_unknown_field(&self,
ty: Ty<'tcx>,
variant: &'tcx ty::VariantDef,
field: &hir::Field,
skip_fields: &[hir::Field],
kind_name: &str) {
fn report_unknown_field(
&self,
ty: Ty<'tcx>,
variant: &'tcx ty::VariantDef,
field: &hir::Field,
skip_fields: &[hir::Field],
kind_name: &str,
) {
if variant.recovered {
return;
}
let mut err = self.type_error_struct_with_diag(
field.ident.span,
|actual| match ty.sty {
Expand Down
7 changes: 6 additions & 1 deletion src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,14 +598,19 @@ fn convert_variant<'a, 'tcx>(
}
})
.collect();
let recovered = match def {
hir::VariantData::Struct(_, _, r) => *r,
_ => false,
};
ty::VariantDef::new(tcx,
did,
ident,
discr,
fields,
adt_kind,
CtorKind::from_hir(def),
attribute_def_id
attribute_def_id,
recovered,
)
}

Expand Down
8 changes: 4 additions & 4 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ pub enum PatKind {

/// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`).
/// The `bool` is `true` in the presence of a `..`.
Struct(Path, Vec<Spanned<FieldPat>>, bool),
Struct(Path, Vec<Spanned<FieldPat>>, /* recovered */ bool),

/// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
Expand Down Expand Up @@ -2133,7 +2133,7 @@ pub enum VariantData {
/// Struct variant.
///
/// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
Struct(Vec<StructField>, NodeId),
Struct(Vec<StructField>, NodeId, bool),
estebank marked this conversation as resolved.
Show resolved Hide resolved
/// Tuple variant.
///
/// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
Expand All @@ -2147,13 +2147,13 @@ pub enum VariantData {
impl VariantData {
pub fn fields(&self) -> &[StructField] {
match *self {
VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => fields,
VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, _) => fields,
_ => &[],
}
}
pub fn id(&self) -> NodeId {
match *self {
VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id,
VariantData::Struct(_, id, _) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id,
}
}
pub fn is_struct(&self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ impl<'a> StripUnconfigured<'a> {

fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) {
match vdata {
ast::VariantData::Struct(fields, _id) |
ast::VariantData::Struct(fields, _id, _) |
ast::VariantData::Tuple(fields, _id) =>
fields.flat_map_in_place(|field| self.configure(field)),
ast::VariantData::Unit(_id) => {}
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ pub fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis:

pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut T) {
match vdata {
VariantData::Struct(fields, id) |
VariantData::Struct(fields, id, _) |
VariantData::Tuple(fields, id) => {
visit_vec(fields, |field| vis.visit_struct_field(field));
vis.visit_id(id);
Expand Down
30 changes: 20 additions & 10 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6829,14 +6829,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);
Expand Down Expand Up @@ -6864,9 +6866,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!(
Expand Down Expand Up @@ -6898,12 +6902,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 {
Expand All @@ -6922,7 +6930,7 @@ impl<'a> Parser<'a> {
return Err(err);
}

Ok(fields)
Ok((fields, recovered))
}

fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
Expand Down Expand Up @@ -7684,12 +7692,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,
Expand Down
13 changes: 13 additions & 0 deletions src/test/ui/parser/recovered-struct-variant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
enum Foo {
A { a, b: usize }
//~^ ERROR expected `:`, found `,`
}

fn main() {
// no complaints about non-existing fields
let f = Foo::A { a:3, b: 4};
match f {
// no complaints about non-existing fields
Foo::A {a, b} => {}
}
}
8 changes: 8 additions & 0 deletions src/test/ui/parser/recovered-struct-variant.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: expected `:`, found `,`
--> $DIR/recovered-struct-variant.rs:2:10
|
LL | A { a, b: usize }
| ^ expected `:`

error: aborting due to previous error
estebank marked this conversation as resolved.
Show resolved Hide resolved