diff --git a/src/doc/reference.md b/src/doc/reference.md index 9ce191ee5897f..8b4e94063f9bd 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2357,7 +2357,7 @@ The currently implemented features of the reference compiler are: terms of encapsulation). * - `default_type_parameter_fallback` - Allows type parameter defaults to influence type inference. -* - `braced_empty_structs` - Allows use of empty structs with braces. +* - `braced_empty_structs` - Allows use of empty structs and enum variants with braces. If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about `#![feature]` directives which enabled diff --git a/src/librustc/front/map/collector.rs b/src/librustc/front/map/collector.rs index 5f3148c7c33c5..fc7531d3f61ba 100644 --- a/src/librustc/front/map/collector.rs +++ b/src/librustc/front/map/collector.rs @@ -134,26 +134,15 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { ItemEnum(ref enum_definition, _) => { for v in &enum_definition.variants { let variant_def_index = - self.insert_def(v.node.id, + self.insert_def(v.node.data.id(), NodeVariant(&**v), DefPathData::EnumVariant(v.node.name)); - match v.node.kind { - TupleVariantKind(ref args) => { - for arg in args { - self.create_def_with_parent(Some(variant_def_index), - arg.id, - DefPathData::PositionalField); - } - } - StructVariantKind(ref def) => { - for field in &def.fields { - self.create_def_with_parent( - Some(variant_def_index), - field.node.id, - DefPathData::Field(field.node.kind)); - } - } + for field in v.node.data.fields() { + self.create_def_with_parent( + Some(variant_def_index), + field.node.id, + DefPathData::Field(field.node.kind)); } } } @@ -161,13 +150,13 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { } ItemStruct(ref struct_def, _) => { // If this is a tuple-like struct, register the constructor. - if let Some(ctor_id) = struct_def.ctor_id { - self.insert_def(ctor_id, + if !struct_def.is_struct() { + self.insert_def(struct_def.id(), NodeStructCtor(&**struct_def), DefPathData::StructCtor); } - for field in &struct_def.fields { + for field in struct_def.fields() { self.create_def(field.node.id, DefPathData::Field(field.node.kind)); } } diff --git a/src/librustc/front/map/mod.rs b/src/librustc/front/map/mod.rs index 396e2bb5703b1..028e1ad5ce974 100644 --- a/src/librustc/front/map/mod.rs +++ b/src/librustc/front/map/mod.rs @@ -124,7 +124,7 @@ pub enum Node<'ast> { NodeBlock(&'ast Block), /// NodeStructCtor represents a tuple struct. - NodeStructCtor(&'ast StructDef), + NodeStructCtor(&'ast VariantData), NodeLifetime(&'ast Lifetime), NodeTyParam(&'ast TyParam) @@ -149,7 +149,7 @@ pub enum MapEntry<'ast> { EntryLocal(NodeId, &'ast Pat), EntryPat(NodeId, &'ast Pat), EntryBlock(NodeId, &'ast Block), - EntryStructCtor(NodeId, &'ast StructDef), + EntryStructCtor(NodeId, &'ast VariantData), EntryLifetime(NodeId, &'ast Lifetime), EntryTyParam(NodeId, &'ast TyParam), @@ -471,18 +471,19 @@ impl<'ast> Map<'ast> { } } - pub fn expect_struct(&self, id: NodeId) -> &'ast StructDef { + pub fn expect_struct(&self, id: NodeId) -> &'ast VariantData { match self.find(id) { Some(NodeItem(i)) => { match i.node { - ItemStruct(ref struct_def, _) => &**struct_def, + ItemStruct(ref struct_def, _) => struct_def, _ => panic!("struct ID bound to non-struct") } } Some(NodeVariant(variant)) => { - match variant.node.kind { - StructVariantKind(ref struct_def) => &**struct_def, - _ => panic!("struct ID bound to enum variant that isn't struct-like"), + if variant.node.data.is_struct() { + &variant.node.data + } else { + panic!("struct ID bound to enum variant that isn't struct-like") } } _ => panic!(format!("expected struct, found {}", self.node_to_string(id))), diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 36236efe50d2c..f5c6cfe2437dc 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -661,14 +661,15 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { hir_visit::walk_fn(self, fk, decl, body, span); } - fn visit_struct_def(&mut self, - s: &hir::StructDef, + fn visit_variant_data(&mut self, + s: &hir::VariantData, name: ast::Name, g: &hir::Generics, - id: ast::NodeId) { - run_lints!(self, check_struct_def, late_passes, s, name, g, id); + item_id: ast::NodeId, + _: Span) { + run_lints!(self, check_struct_def, late_passes, s, name, g, item_id); hir_visit::walk_struct_def(self, s); - run_lints!(self, check_struct_def_post, late_passes, s, name, g, id); + run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id); } fn visit_struct_field(&mut self, s: &hir::StructField) { @@ -678,10 +679,10 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { }) } - fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics) { + fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) { self.with_lint_attrs(&v.node.attrs, |cx| { run_lints!(cx, check_variant, late_passes, v, g); - hir_visit::walk_variant(cx, v, g); + hir_visit::walk_variant(cx, v, g, item_id); run_lints!(cx, check_variant_post, late_passes, v, g); }) } @@ -810,14 +811,15 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> { ast_visit::walk_fn(self, fk, decl, body, span); } - fn visit_struct_def(&mut self, - s: &ast::StructDef, + fn visit_variant_data(&mut self, + s: &ast::VariantData, ident: ast::Ident, g: &ast::Generics, - id: ast::NodeId) { - run_lints!(self, check_struct_def, early_passes, s, ident, g, id); + item_id: ast::NodeId, + _: Span) { + run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id); ast_visit::walk_struct_def(self, s); - run_lints!(self, check_struct_def_post, early_passes, s, ident, g, id); + run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id); } fn visit_struct_field(&mut self, s: &ast::StructField) { @@ -827,10 +829,10 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> { }) } - fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics) { + fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics, item_id: ast::NodeId) { self.with_lint_attrs(&v.node.attrs, |cx| { run_lints!(cx, check_variant, early_passes, v, g); - ast_visit::walk_variant(cx, v, g); + ast_visit::walk_variant(cx, v, g, item_id); run_lints!(cx, check_variant_post, early_passes, v, g); }) } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 5c316b58303fe..14c11af6f3863 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -150,9 +150,9 @@ pub trait LateLintPass: LintPass { fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { } fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { } fn check_struct_def(&mut self, _: &LateContext, - _: &hir::StructDef, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { } + _: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { } fn check_struct_def_post(&mut self, _: &LateContext, - _: &hir::StructDef, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { } + _: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { } fn check_struct_field(&mut self, _: &LateContext, _: &hir::StructField) { } fn check_variant(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { } fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { } @@ -192,9 +192,9 @@ pub trait EarlyLintPass: LintPass { fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { } fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { } fn check_struct_def(&mut self, _: &EarlyContext, - _: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { } + _: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { } fn check_struct_def_post(&mut self, _: &EarlyContext, - _: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { } + _: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { } fn check_struct_field(&mut self, _: &EarlyContext, _: &ast::StructField) { } fn check_variant(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { } fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 9d2b1548f29d8..8e2c2e6a0bfbd 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -315,7 +315,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, let vid = variant.did; let variant_node_id = ecx.local_id(vid); - if let ty::VariantKind::Dict = variant.kind() { + if let ty::VariantKind::Struct = variant.kind() { // tuple-like enum variant fields aren't really items so // don't try to encode them. for field in &variant.fields { @@ -328,7 +328,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_def_id_and_key(ecx, rbml_w, vid); encode_family(rbml_w, match variant.kind() { ty::VariantKind::Unit | ty::VariantKind::Tuple => 'v', - ty::VariantKind::Dict => 'V' + ty::VariantKind::Struct => 'V' }); encode_name(rbml_w, variant.name); encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id)); @@ -381,12 +381,8 @@ fn each_auxiliary_node_id(item: &hir::Item, callback: F) -> bool where match item.node { hir::ItemStruct(ref struct_def, _) => { // If this is a newtype struct, return the constructor. - match struct_def.ctor_id { - Some(ctor_id) if !struct_def.fields.is_empty() && - struct_def.fields[0].node.kind.is_unnamed() => { - continue_ = callback(ctor_id); - } - _ => {} + if struct_def.is_tuple() { + continue_ = callback(struct_def.id()); } } _ => {} @@ -1023,7 +1019,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_attributes(rbml_w, &item.attrs); encode_repr_attrs(rbml_w, ecx, &item.attrs); for v in &enum_definition.variants { - encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.id)); + encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); } encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); encode_path(rbml_w, path); @@ -1072,8 +1068,8 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, // Encode inherent implementations for this structure. encode_inherent_implementations(ecx, rbml_w, def_id); - if let Some(ctor_id) = struct_def.ctor_id { - let ctor_did = ecx.tcx.map.local_def_id(ctor_id); + if !struct_def.is_struct() { + let ctor_did = ecx.tcx.map.local_def_id(struct_def.id()); rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, def_to_u64(ctor_did)); } @@ -1085,9 +1081,8 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } // If this is a tuple-like struct, encode the type of the constructor. - if let Some(ctor_id) = struct_def.ctor_id { - encode_info_for_struct_ctor(ecx, rbml_w, item.name, - ctor_id, index, item.id); + if !struct_def.is_struct() { + encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def.id(), index, item.id); } } hir::ItemDefaultImpl(unsafety, _) => { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 3b4cb56ec741f..e81445f19ede6 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1315,17 +1315,17 @@ fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) { def.variants.iter().zip(orig_def.variants.iter()) { debug!("astencode: copying variant {:?} => {:?}", - orig_variant.did, i_variant.node.id); - copy_item_type(dcx, i_variant.node.id, orig_variant.did); + orig_variant.did, i_variant.node.data.id()); + copy_item_type(dcx, i_variant.node.data.id(), orig_variant.did); } } hir::ItemStruct(ref def, _) => { - if let Some(ctor_id) = def.ctor_id { + if !def.is_struct() { let ctor_did = dcx.tcx.lookup_adt_def(orig_did) .struct_variant().did; debug!("astencode: copying ctor {:?} => {:?}", ctor_did, - ctor_id); - copy_item_type(dcx, ctor_id, ctor_did); + def.id()); + copy_item_type(dcx, def.id(), ctor_did); } } _ => {} diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index a8f20815a9a8b..4d7dd60a27156 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -518,7 +518,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { let v = adt.variant_of_ctor(ctor); - if let VariantKind::Dict = v.kind() { + if let VariantKind::Struct = v.kind() { let field_pats: Vec<_> = v.fields.iter() .zip(pats) .filter(|&(_, ref pat)| pat.node != hir::PatWild(hir::PatWildSingle)) diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index acb66b8efe7eb..fd73fe45180be 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -54,7 +54,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> { let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &variant.span); recursion_visitor.populate_enum_discriminants(enum_def); - recursion_visitor.visit_variant(variant, generics); + recursion_visitor.visit_variant(variant, generics, it.id); } } } @@ -168,7 +168,7 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { let mut discriminant_map = self.discriminant_map.borrow_mut(); match enum_definition.variants.first() { None => { return; } - Some(variant) if discriminant_map.contains_key(&variant.node.id) => { + Some(variant) if discriminant_map.contains_key(&variant.node.data.id()) => { return; } _ => {} @@ -177,7 +177,7 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> { // Go through all the variants. let mut variant_stack: Vec = Vec::new(); for variant in enum_definition.variants.iter().rev() { - variant_stack.push(variant.node.id); + variant_stack.push(variant.node.data.id()); // When we find an expression, every variant currently on the stack // is affected by that expression. if let Some(ref expr) = variant.node.disr_expr { @@ -201,14 +201,14 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { } fn visit_enum_def(&mut self, enum_definition: &'ast hir::EnumDef, - generics: &'ast hir::Generics) { + generics: &'ast hir::Generics, item_id: ast::NodeId) { self.populate_enum_discriminants(enum_definition); - visit::walk_enum_def(self, enum_definition, generics); + visit::walk_enum_def(self, enum_definition, generics, item_id); } fn visit_variant(&mut self, variant: &'ast hir::Variant, - _: &'ast hir::Generics) { - let variant_id = variant.node.id; + _: &'ast hir::Generics, _: ast::NodeId) { + let variant_id = variant.node.data.id(); let maybe_expr; if let Some(get_expr) = self.discriminant_map.borrow().get(&variant_id) { // This is necessary because we need to let the `discriminant_map` @@ -269,9 +269,10 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { self.ast_map.expect_item(enum_node_id).node { self.populate_enum_discriminants(enum_def); + let enum_id = self.ast_map.as_local_node_id(enum_id).unwrap(); let variant_id = self.ast_map.as_local_node_id(variant_id).unwrap(); let variant = self.ast_map.expect_variant(variant_id); - self.visit_variant(variant, generics); + self.visit_variant(variant, generics, enum_id); } else { self.sess.span_bug(e.span, "`check_static_recursion` found \ diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index acda0fe2f0e35..3c68fb62e2445 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -63,7 +63,7 @@ fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt, fn variant_expr<'a>(variants: &'a [P], id: ast::NodeId) -> Option<&'a Expr> { for variant in variants { - if variant.node.id == id { + if variant.node.data.id() == id { return variant.node.disr_expr.as_ref().map(|e| &**e); } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 6e31b733254bd..7b11419d92562 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -215,11 +215,11 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { - fn visit_struct_def(&mut self, def: &hir::StructDef, _: ast::Name, - _: &hir::Generics, _: ast::NodeId) { + fn visit_variant_data(&mut self, def: &hir::VariantData, _: ast::Name, + _: &hir::Generics, _: ast::NodeId, _: codemap::Span) { let has_extern_repr = self.struct_has_extern_repr; let inherited_pub_visibility = self.inherited_pub_visibility; - let live_fields = def.fields.iter().filter(|f| { + let live_fields = def.fields().filter(|f| { has_extern_repr || inherited_pub_visibility || match f.node.kind { hir::NamedField(_, hir::Public) => true, _ => false @@ -339,7 +339,8 @@ impl<'v> Visitor<'v> for LifeSeeder { } match item.node { hir::ItemEnum(ref enum_def, _) if allow_dead_code => { - self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id)); + self.worklist.extend(enum_def.variants.iter() + .map(|variant| variant.node.data.id())); } hir::ItemTrait(_, _, _, ref trait_items) => { for trait_item in trait_items { @@ -426,7 +427,9 @@ fn find_live(tcx: &ty::ctxt, fn get_struct_ctor_id(item: &hir::Item) -> Option { match item.node { - hir::ItemStruct(ref struct_def, _) => struct_def.ctor_id, + hir::ItemStruct(ref struct_def, _) if !struct_def.is_struct() => { + Some(struct_def.id()) + } _ => None } } @@ -464,7 +467,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { } fn should_warn_about_variant(&mut self, variant: &hir::Variant_) -> bool { - !self.symbol_is_live(variant.id, None) + !self.symbol_is_live(variant.data.id(), None) && !has_allow_dead_code_or_lang_attr(&variant.attrs) } @@ -540,7 +543,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { hir::ItemEnum(ref enum_def, _) => { for variant in &enum_def.variants { if self.should_warn_about_variant(&variant.node) { - self.warn_dead_code(variant.node.id, variant.span, + self.warn_dead_code(variant.node.data.id(), variant.span, variant.node.name, "variant"); } } diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 3e8325b86121d..ef2b918a9f5d7 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -44,13 +44,13 @@ pub enum Def { ast::NodeId), // expr node that creates the closure /// Note that if it's a tuple struct's definition, the node id of the DefId - /// may either refer to the item definition's id or the StructDef.ctor_id. + /// may either refer to the item definition's id or the VariantData.ctor_id. /// /// The cases that I have encountered so far are (this is not exhaustive): /// - If it's a ty_path referring to some tuple struct, then DefMap maps /// it to a def whose id is the item definition's id. /// - If it's an ExprPath referring to some tuple struct, then DefMap maps - /// it to a def whose id is the StructDef.ctor_id. + /// it to a def whose id is the VariantData.ctor_id. DefStruct(DefId), DefLabel(ast::NodeId), DefMethod(DefId), diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index c2235591ceef1..af295c3e584b0 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -185,9 +185,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> { |v| visit::walk_item(v, i), required); if let hir::ItemStruct(ref sd, _) = i.node { - sd.ctor_id.map(|id| { - self.annotate(id, true, &i.attrs, i.span, |_| {}, true) - }); + if !sd.is_struct() { + self.annotate(sd.id(), true, &i.attrs, i.span, |_| {}, true) + } } } @@ -207,9 +207,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> { |v| visit::walk_impl_item(v, ii), true); } - fn visit_variant(&mut self, var: &Variant, g: &'v Generics) { - self.annotate(var.node.id, true, &var.node.attrs, var.span, - |v| visit::walk_variant(v, var, g), true) + fn visit_variant(&mut self, var: &Variant, g: &'v Generics, item_id: NodeId) { + self.annotate(var.node.data.id(), true, &var.node.attrs, var.span, + |v| visit::walk_variant(v, var, g, item_id), true) } fn visit_struct_field(&mut self, s: &StructField) { diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 4ffb519900356..975a5adad2bd2 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -1533,7 +1533,7 @@ impl<'tcx, 'container> Hash for AdtDefData<'tcx, 'container> { pub enum AdtKind { Struct, Enum } #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum VariantKind { Dict, Tuple, Unit } +pub enum VariantKind { Struct, Tuple, Unit } impl<'tcx, 'container> AdtDefData<'tcx, 'container> { fn new(tcx: &ctxt<'tcx>, @@ -1716,7 +1716,7 @@ impl<'tcx, 'container> VariantDefData<'tcx, 'container> { Some(&FieldDefData { name, .. }) if name == special_idents::unnamed_field.name => { VariantKind::Tuple } - Some(_) => VariantKind::Dict + Some(_) => VariantKind::Struct } } diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 25b4cfad01ce0..a9cfc7138d8d9 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -301,18 +301,18 @@ mod svh_visitor { } impl<'a, 'v> Visitor<'v> for StrictVersionHashVisitor<'a> { - fn visit_struct_def(&mut self, s: &StructDef, name: Name, - g: &Generics, _: NodeId) { + fn visit_variant_data(&mut self, s: &VariantData, name: Name, + g: &Generics, _: NodeId, _: Span) { SawStructDef(name.as_str()).hash(self.st); visit::walk_generics(self, g); visit::walk_struct_def(self, s) } - fn visit_variant(&mut self, v: &Variant, g: &Generics) { + fn visit_variant(&mut self, v: &Variant, g: &Generics, item_id: NodeId) { SawVariant.hash(self.st); // walk_variant does not call walk_generics, so do it here. visit::walk_generics(self, g); - visit::walk_variant(self, v, g) + visit::walk_variant(self, v, g, item_id) } // All of the remaining methods just record (in the hash diff --git a/src/librustc_front/fold.rs b/src/librustc_front/fold.rs index c6108044beace..dafca7188d5ad 100644 --- a/src/librustc_front/fold.rs +++ b/src/librustc_front/fold.rs @@ -223,7 +223,7 @@ pub trait Folder : Sized { noop_fold_poly_trait_ref(p, self) } - fn fold_struct_def(&mut self, struct_def: P) -> P { + fn fold_variant_data(&mut self, struct_def: P) -> P { noop_fold_struct_def(struct_def, self) } @@ -247,10 +247,6 @@ pub trait Folder : Sized { noop_fold_opt_lifetime(o_lt, self) } - fn fold_variant_arg(&mut self, va: VariantArg) -> VariantArg { - noop_fold_variant_arg(va, self) - } - fn fold_opt_bounds(&mut self, b: Option>) -> Option> { @@ -435,24 +431,14 @@ pub fn noop_fold_foreign_mod(ForeignMod { abi, items }: ForeignMod, } pub fn noop_fold_variant(v: P, fld: &mut T) -> P { - v.map(|Spanned { node: Variant_ { id, name, attrs, kind, disr_expr }, span }| { - Spanned { - node: Variant_ { - id: fld.new_id(id), - name: name, - attrs: fold_attrs(attrs, fld), - kind: match kind { - TupleVariantKind(variant_args) => { - TupleVariantKind(variant_args.move_map(|x| fld.fold_variant_arg(x))) - } - StructVariantKind(struct_def) => { - StructVariantKind(fld.fold_struct_def(struct_def)) - } - }, - disr_expr: disr_expr.map(|e| fld.fold_expr(e)), - }, - span: fld.new_span(span), - } + v.map(|Spanned {node: Variant_ {name, attrs, data, disr_expr}, span}| Spanned { + node: Variant_ { + name: name, + attrs: fold_attrs(attrs, fld), + data: fld.fold_variant_data(data), + disr_expr: disr_expr.map(|e| fld.fold_expr(e)), + }, + span: fld.new_span(span), }) } @@ -707,11 +693,16 @@ pub fn noop_fold_where_predicate(pred: WherePredicate, fld: &mut T) - } } -pub fn noop_fold_struct_def(struct_def: P, fld: &mut T) -> P { - struct_def.map(|StructDef { fields, ctor_id }| { - StructDef { - fields: fields.move_map(|f| fld.fold_struct_field(f)), - ctor_id: ctor_id.map(|cid| fld.new_id(cid)), +pub fn noop_fold_struct_def(struct_def: P, fld: &mut T) -> P { + struct_def.map(|vdata| { + match vdata { + VariantData::Struct(fields, id) => { + VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)), fld.new_id(id)) + } + VariantData::Tuple(fields, id) => { + VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)), fld.new_id(id)) + } + VariantData::Unit(id) => VariantData::Unit(fld.new_id(id)) } }) } @@ -775,15 +766,6 @@ fn noop_fold_bounds(bounds: TyParamBounds, folder: &mut T) -> TyParam bounds.move_map(|bound| folder.fold_ty_param_bound(bound)) } -fn noop_fold_variant_arg(VariantArg { id, ty }: VariantArg, - folder: &mut T) - -> VariantArg { - VariantArg { - id: folder.new_id(id), - ty: folder.fold_ty(ty), - } -} - pub fn noop_fold_block(b: P, folder: &mut T) -> P { b.map(|Block { id, stmts, expr, rules, span }| { Block { @@ -828,7 +810,7 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { folder.fold_generics(generics)) } ItemStruct(struct_def, generics) => { - let struct_def = folder.fold_struct_def(struct_def); + let struct_def = folder.fold_variant_data(struct_def); ItemStruct(struct_def, folder.fold_generics(generics)) } ItemDefaultImpl(unsafety, ref trait_ref) => { diff --git a/src/librustc_front/hir.rs b/src/librustc_front/hir.rs index 9066b93262cd6..e62eadaa4387d 100644 --- a/src/librustc_front/hir.rs +++ b/src/librustc_front/hir.rs @@ -33,7 +33,6 @@ pub use self::Ty_::*; pub use self::TyParamBound::*; pub use self::UnOp::*; pub use self::UnsafeSource::*; -pub use self::VariantKind::*; pub use self::ViewPath_::*; pub use self::Visibility::*; pub use self::PathParameters::*; @@ -50,6 +49,7 @@ use print::pprust; use util; use std::fmt; +use std::{iter, option, slice}; use serialize::{Encodable, Encoder, Decoder}; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] @@ -1015,20 +1015,6 @@ pub struct ForeignMod { pub items: Vec>, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct VariantArg { - pub ty: P, - pub id: NodeId, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum VariantKind { - /// Tuple variant, e.g. `Foo(A, B)` - TupleVariantKind(Vec), - /// Struct variant, e.g. `Foo {x: A, y: B}` - StructVariantKind(P), -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: Vec>, @@ -1038,8 +1024,7 @@ pub struct EnumDef { pub struct Variant_ { pub name: Name, pub attrs: Vec, - pub kind: VariantKind, - pub id: NodeId, + pub data: P, /// Explicit discriminant, eg `Foo = 1` pub disr_expr: Option>, } @@ -1176,13 +1161,50 @@ impl StructFieldKind { } } +/// Fields and Ids of enum variants and structs +/// +/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all +/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants). +/// One shared Id can be successfully used for these two purposes. +/// Id of the whole enum lives in `Item`. +/// +/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually +/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of +/// the variant itself" from enum variants. +/// Id of the whole struct lives in `Item`. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct StructDef { - /// Fields, not including ctor - pub fields: Vec, - /// ID of the constructor. This is only used for tuple- or enum-like - /// structs. - pub ctor_id: Option, +pub enum VariantData { + Struct(Vec, NodeId), + Tuple(Vec, NodeId), + Unit(NodeId), +} + +pub type FieldIter<'a> = iter::FlatMap>, + slice::Iter<'a, StructField>, + fn(&Vec) -> slice::Iter>; + +impl VariantData { + pub fn fields(&self) -> FieldIter { + fn vec_iter(v: &Vec) -> slice::Iter { v.iter() } + match *self { + VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => Some(fields), + _ => None, + }.into_iter().flat_map(vec_iter) + } + pub fn id(&self) -> NodeId { + match *self { + VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id + } + } + pub fn is_struct(&self) -> bool { + if let VariantData::Struct(..) = *self { true } else { false } + } + pub fn is_tuple(&self) -> bool { + if let VariantData::Tuple(..) = *self { true } else { false } + } + pub fn is_unit(&self) -> bool { + if let VariantData::Unit(..) = *self { true } else { false } + } } /* @@ -1226,7 +1248,7 @@ pub enum Item_ { /// An enum definition, e.g. `enum Foo {C, D}` ItemEnum(EnumDef, Generics), /// A struct definition, e.g. `struct Foo {x: A}` - ItemStruct(P, Generics), + ItemStruct(P, Generics), /// Represents a Trait Declaration ItemTrait(Unsafety, Generics, TyParamBounds, Vec>), diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs index 5bd188020a33c..890896eb1c5aa 100644 --- a/src/librustc_front/lowering.rs +++ b/src/librustc_front/lowering.rs @@ -264,19 +264,9 @@ pub fn lower_foreign_mod(_lctx: &LoweringContext, fm: &ForeignMod) -> hir::Forei pub fn lower_variant(_lctx: &LoweringContext, v: &Variant) -> P { P(Spanned { node: hir::Variant_ { - id: v.node.id, name: v.node.name.name, attrs: v.node.attrs.clone(), - kind: match v.node.kind { - TupleVariantKind(ref variant_args) => { - hir::TupleVariantKind(variant_args.iter() - .map(|ref x| lower_variant_arg(_lctx, x)) - .collect()) - } - StructVariantKind(ref struct_def) => { - hir::StructVariantKind(lower_struct_def(_lctx, struct_def)) - } - }, + data: lower_struct_def(_lctx, &v.node.data), disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(_lctx, e)), }, span: v.span, @@ -508,10 +498,17 @@ pub fn lower_where_predicate(_lctx: &LoweringContext, } } -pub fn lower_struct_def(_lctx: &LoweringContext, sd: &StructDef) -> P { - P(hir::StructDef { - fields: sd.fields.iter().map(|f| lower_struct_field(_lctx, f)).collect(), - ctor_id: sd.ctor_id, +pub fn lower_struct_def(_lctx: &LoweringContext, sd: &VariantData) -> P { + P(match *sd { + VariantData::Struct(ref fields, id) => { + hir::VariantData::Struct(fields.iter() + .map(|f| lower_struct_field(_lctx, f)).collect(), id) + } + VariantData::Tuple(ref fields, id) => { + hir::VariantData::Tuple(fields.iter() + .map(|f| lower_struct_field(_lctx, f)).collect(), id) + } + VariantData::Unit(id) => hir::VariantData::Unit(id) }) } @@ -567,13 +564,6 @@ fn lower_bounds(_lctx: &LoweringContext, bounds: &TyParamBounds) -> hir::TyParam bounds.iter().map(|bound| lower_ty_param_bound(_lctx, bound)).collect() } -fn lower_variant_arg(_lctx: &LoweringContext, va: &VariantArg) -> hir::VariantArg { - hir::VariantArg { - id: va.id, - ty: lower_ty(_lctx, &va.ty), - } -} - pub fn lower_block(_lctx: &LoweringContext, b: &Block) -> P { P(hir::Block { id: b.id, diff --git a/src/librustc_front/print/pprust.rs b/src/librustc_front/print/pprust.rs index 80b0a984681a3..5e78aa5fbc1f8 100644 --- a/src/librustc_front/print/pprust.rs +++ b/src/librustc_front/print/pprust.rs @@ -734,7 +734,7 @@ impl<'a> State<'a> { } hir::ItemStruct(ref struct_def, ref generics) => { try!(self.head(&visibility_qualified(item.vis, "struct"))); - try!(self.print_struct(&**struct_def, generics, item.name, item.span)); + try!(self.print_struct(&**struct_def, generics, item.name, item.span, true)); } hir::ItemDefaultImpl(unsafety, ref trait_ref) => { @@ -888,18 +888,19 @@ impl<'a> State<'a> { } pub fn print_struct(&mut self, - struct_def: &hir::StructDef, + struct_def: &hir::VariantData, generics: &hir::Generics, name: ast::Name, - span: codemap::Span) + span: codemap::Span, + print_finalizer: bool) -> io::Result<()> { try!(self.print_name(name)); try!(self.print_generics(generics)); - if ::util::struct_def_is_tuple_like(struct_def) { - if !struct_def.fields.is_empty() { + if !struct_def.is_struct() { + if struct_def.is_tuple() { try!(self.popen()); - try!(self.commasep(Inconsistent, - &struct_def.fields, + try!(self.commasep_iter(Inconsistent, + struct_def.fields(), |s, field| { match field.node.kind { hir::NamedField(..) => panic!("unexpected named field"), @@ -913,7 +914,9 @@ impl<'a> State<'a> { try!(self.pclose()); } try!(self.print_where_clause(&generics.where_clause)); - try!(word(&mut self.s, ";")); + if print_finalizer { + try!(word(&mut self.s, ";")); + } try!(self.end()); self.end() // close the outer-box } else { @@ -922,7 +925,7 @@ impl<'a> State<'a> { try!(self.bopen()); try!(self.hardbreak_if_not_bol()); - for field in &struct_def.fields { + for field in struct_def.fields() { match field.node.kind { hir::UnnamedField(..) => panic!("unexpected unnamed field"), hir::NamedField(name, visibility) => { @@ -943,21 +946,9 @@ impl<'a> State<'a> { } pub fn print_variant(&mut self, v: &hir::Variant) -> io::Result<()> { - match v.node.kind { - hir::TupleVariantKind(ref args) => { - try!(self.print_name(v.node.name)); - if !args.is_empty() { - try!(self.popen()); - try!(self.commasep(Consistent, &args[..], |s, arg| s.print_type(&*arg.ty))); - try!(self.pclose()); - } - } - hir::StructVariantKind(ref struct_def) => { - try!(self.head("")); - let generics = ::util::empty_generics(); - try!(self.print_struct(&**struct_def, &generics, v.node.name, v.span)); - } - } + try!(self.head("")); + let generics = ::util::empty_generics(); + try!(self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)); match v.node.disr_expr { Some(ref d) => { try!(space(&mut self.s)); diff --git a/src/librustc_front/util.rs b/src/librustc_front/util.rs index c6b2a2acc2b8d..5d8973ead47db 100644 --- a/src/librustc_front/util.rs +++ b/src/librustc_front/util.rs @@ -81,12 +81,6 @@ pub fn binop_to_string(op: BinOp_) -> &'static str { } } -/// Returns true if the given struct def is tuple-like; i.e. that its fields -/// are unnamed. -pub fn struct_def_is_tuple_like(struct_def: &hir::StructDef) -> bool { - struct_def.ctor_id.is_some() -} - pub fn stmt_id(s: &Stmt) -> NodeId { match s.node { StmtDecl(_, id) => id, @@ -200,11 +194,6 @@ impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> } } } - ItemEnum(ref enum_definition, _) => { - for variant in &enum_definition.variants { - self.operation.visit_id(variant.node.id) - } - } _ => {} } @@ -292,13 +281,13 @@ impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> visit::walk_struct_field(self, struct_field) } - fn visit_struct_def(&mut self, - struct_def: &StructDef, + fn visit_variant_data(&mut self, + struct_def: &VariantData, _: Name, _: &hir::Generics, - id: NodeId) { - self.operation.visit_id(id); - struct_def.ctor_id.map(|ctor_id| self.operation.visit_id(ctor_id)); + _: NodeId, + _: Span) { + self.operation.visit_id(struct_def.id()); visit::walk_struct_def(self, struct_def); } diff --git a/src/librustc_front/visit.rs b/src/librustc_front/visit.rs index 9e91ab34d089a..00c2c3a3ddd65 100644 --- a/src/librustc_front/visit.rs +++ b/src/librustc_front/visit.rs @@ -112,20 +112,20 @@ pub trait Visitor<'v> : Sized { fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } - fn visit_struct_def(&mut self, s: &'v StructDef, _: Name, _: &'v Generics, _: NodeId) { + fn visit_variant_data(&mut self, s: &'v VariantData, _: Name, + _: &'v Generics, _: NodeId, _: Span) { walk_struct_def(self, s) } fn visit_struct_field(&mut self, s: &'v StructField) { walk_struct_field(self, s) } - fn visit_enum_def(&mut self, enum_definition: &'v EnumDef, generics: &'v Generics) { - walk_enum_def(self, enum_definition, generics) + fn visit_enum_def(&mut self, enum_definition: &'v EnumDef, + generics: &'v Generics, item_id: NodeId) { + walk_enum_def(self, enum_definition, generics, item_id) } - - fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics) { - walk_variant(self, v, g) + fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) { + walk_variant(self, v, g, item_id) } - fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { walk_lifetime(self, lifetime) } @@ -293,7 +293,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { } ItemEnum(ref enum_definition, ref type_parameters) => { visitor.visit_generics(type_parameters); - visitor.visit_enum_def(enum_definition, type_parameters) + visitor.visit_enum_def(enum_definition, type_parameters, item.id) } ItemDefaultImpl(_, ref trait_ref) => { visitor.visit_trait_ref(trait_ref) @@ -310,7 +310,8 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { } ItemStruct(ref struct_definition, ref generics) => { visitor.visit_generics(generics); - visitor.visit_struct_def(struct_definition, item.name, generics, item.id) + visitor.visit_variant_data(struct_definition, item.name, + generics, item.id, item.span); } ItemTrait(_, ref generics, ref bounds, ref methods) => { visitor.visit_generics(generics); @@ -323,30 +324,20 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, enum_definition: &'v EnumDef, - generics: &'v Generics) { + generics: &'v Generics, + item_id: NodeId) { for variant in &enum_definition.variants { - visitor.visit_variant(variant, generics); + visitor.visit_variant(variant, generics, item_id); } } pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant, - generics: &'v Generics) { + generics: &'v Generics, + item_id: NodeId) { visitor.visit_name(variant.span, variant.node.name); - - match variant.node.kind { - TupleVariantKind(ref variant_arguments) => { - for variant_argument in variant_arguments { - visitor.visit_ty(&variant_argument.ty) - } - } - StructVariantKind(ref struct_definition) => { - visitor.visit_struct_def(struct_definition, - variant.node.name, - generics, - variant.node.id) - } - } + visitor.visit_variant_data(&variant.node.data, variant.node.name, + generics, item_id, variant.span); walk_list!(visitor, visit_expr, &variant.node.disr_expr); walk_list!(visitor, visit_attribute, &variant.node.attrs); } @@ -637,8 +628,8 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt } } -pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v StructDef) { - walk_list!(visitor, visit_struct_field, &struct_definition.fields); +pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) { + walk_list!(visitor, visit_struct_field, struct_definition.fields()); } pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) { diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 91d1d398a0e54..693de1740bfee 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -280,9 +280,9 @@ impl LateLintPass for NonSnakeCase { } } - fn check_struct_def(&mut self, cx: &LateContext, s: &hir::StructDef, + fn check_struct_def(&mut self, cx: &LateContext, s: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { - for sf in &s.fields { + for sf in s.fields() { if let hir::StructField_ { kind: hir::NamedField(name, _), .. } = sf.node { self.check_snake_case(cx, "structure field", &name.as_str(), Some(sf.span)); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 1df3c1609b890..f5a58656080db 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -123,7 +123,7 @@ impl LateLintPass for BoxPointers { // If it's a struct, we also have to check the fields' types match it.node { hir::ItemStruct(ref struct_def, _) => { - for struct_field in &struct_def.fields { + for struct_field in struct_def.fields() { self.check_heap_type(cx, struct_field.span, cx.tcx.node_id_to_type(struct_field.node.id)); } @@ -427,15 +427,15 @@ impl LateLintPass for MissingDoc { self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); } - fn check_struct_def(&mut self, _: &LateContext, _: &hir::StructDef, - _: ast::Name, _: &hir::Generics, id: ast::NodeId) { - self.struct_def_stack.push(id); + fn check_struct_def(&mut self, _: &LateContext, _: &hir::VariantData, + _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) { + self.struct_def_stack.push(item_id); } - fn check_struct_def_post(&mut self, _: &LateContext, _: &hir::StructDef, - _: ast::Name, _: &hir::Generics, id: ast::NodeId) { + fn check_struct_def_post(&mut self, _: &LateContext, _: &hir::VariantData, + _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) { let popped = self.struct_def_stack.pop().expect("empty struct_def_stack"); - assert!(popped == id); + assert!(popped == item_id); } fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { @@ -527,7 +527,8 @@ impl LateLintPass for MissingDoc { } fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) { - self.check_missing_docs_attrs(cx, Some(v.node.id), &v.node.attrs, v.span, "a variant"); + self.check_missing_docs_attrs(cx, Some(v.node.data.id()), + &v.node.attrs, v.span, "a variant"); assert!(!self.in_variant); self.in_variant = true; } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index ca5411f9c790a..608558ac2bdb9 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -82,7 +82,7 @@ impl<'v> Visitor<'v> for ParentVisitor { // The parent is considered the enclosing enum because the // enum will dictate the privacy visibility of this variant // instead. - self.parents.insert(variant.node.id, item.id); + self.parents.insert(variant.node.data.id(), item.id); } } @@ -128,18 +128,17 @@ impl<'v> Visitor<'v> for ParentVisitor { visit::walk_impl_item(self, ii); } - fn visit_struct_def(&mut self, s: &hir::StructDef, _: ast::Name, - _: &'v hir::Generics, n: ast::NodeId) { + fn visit_variant_data(&mut self, s: &hir::VariantData, _: ast::Name, + _: &'v hir::Generics, item_id: ast::NodeId, _: Span) { // Struct constructors are parented to their struct definitions because // they essentially are the struct definitions. - match s.ctor_id { - Some(id) => { self.parents.insert(id, n); } - None => {} + if !s.is_struct() { + self.parents.insert(s.id(), item_id); } // While we have the id of the struct definition, go ahead and parent // all the fields. - for field in &s.fields { + for field in s.fields() { self.parents.insert(field.node.id, self.curparent); } visit::walk_struct_def(self, s) @@ -234,8 +233,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { // public all variants are public unless they're explicitly priv hir::ItemEnum(ref def, _) if public_first => { for variant in &def.variants { - self.exported_items.insert(variant.node.id); - self.public_items.insert(variant.node.id); + self.exported_items.insert(variant.node.data.id()); + self.public_items.insert(variant.node.data.id()); } } @@ -320,12 +319,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { // Struct constructors are public if the struct is all public. hir::ItemStruct(ref def, _) if public_first => { - match def.ctor_id { - Some(id) => { self.exported_items.insert(id); } - None => {} + if !def.is_struct() { + self.exported_items.insert(def.id()); } // fields can be public or private, so lets check - for field in &def.fields { + for field in def.fields() { let vis = match field.node.kind { hir::NamedField(_, vis) | hir::UnnamedField(vis) => vis }; @@ -1090,8 +1088,8 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { "visibility has no effect inside functions"); } } - let check_struct = |def: &hir::StructDef| { - for f in &def.fields { + let check_struct = |def: &hir::VariantData| { + for f in def.fields() { match f.node.kind { hir::NamedField(_, p) => check_inherited(tcx, f.span, p), hir::UnnamedField(..) => {} @@ -1432,20 +1430,20 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { visit::walk_ty(self, t) } - fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics) { - if self.exported_items.contains(&v.node.id) { + fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) { + if self.exported_items.contains(&v.node.data.id()) { self.in_variant = true; - visit::walk_variant(self, v, g); + visit::walk_variant(self, v, g, item_id); self.in_variant = false; } } fn visit_struct_field(&mut self, s: &hir::StructField) { - match s.node.kind { - hir::NamedField(_, vis) if vis == hir::Public || self.in_variant => { - visit::walk_struct_field(self, s); - } - _ => {} + let vis = match s.node.kind { + hir::NamedField(_, vis) | hir::UnnamedField(vis) => vis + }; + if vis == hir::Public || self.in_variant { + visit::walk_struct_field(self, s); } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f74144565fc58..c051f8c263723 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -49,8 +49,6 @@ use rustc_front::hir::{ItemForeignMod, ItemImpl, ItemMod, ItemStatic, ItemDefaul use rustc_front::hir::{ItemStruct, ItemTrait, ItemTy, ItemUse}; use rustc_front::hir::{NamedField, PathListIdent, PathListMod, Public}; use rustc_front::hir::StmtDecl; -use rustc_front::hir::StructVariantKind; -use rustc_front::hir::TupleVariantKind; use rustc_front::hir::UnnamedField; use rustc_front::hir::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; use rustc_front::hir::Visibility; @@ -494,9 +492,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { // These items live in both the type and value namespaces. ItemStruct(ref struct_def, _) => { // Adding to both Type and Value namespaces or just Type? - let (forbid, ctor_id) = match struct_def.ctor_id { - Some(ctor_id) => (ForbidDuplicateTypesAndValues, Some(ctor_id)), - None => (ForbidDuplicateTypesAndModules, None) + let (forbid, ctor_id) = if struct_def.is_struct() { + (ForbidDuplicateTypesAndModules, None) + } else { + (ForbidDuplicateTypesAndValues, Some(struct_def.id())) }; let name_bindings = self.add_child(name, parent, forbid, sp); @@ -515,7 +514,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { } // Record the def ID and fields of this struct. - let named_fields = struct_def.fields.iter().filter_map(|f| { + let named_fields = struct_def.fields().filter_map(|f| { match f.node.kind { NamedField(name, _) => Some(name), UnnamedField(_) => None @@ -589,14 +588,13 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { item_id: DefId, parent: &Rc) { let name = variant.node.name; - let is_exported = match variant.node.kind { - TupleVariantKind(_) => false, - StructVariantKind(_) => { - // Not adding fields for variants as they are not accessed with a self receiver - let variant_def_id = self.ast_map.local_def_id(variant.node.id); - self.structs.insert(variant_def_id, Vec::new()); - true - } + let is_exported = if variant.node.data.is_struct() { + // Not adding fields for variants as they are not accessed with a self receiver + let variant_def_id = self.ast_map.local_def_id(variant.node.data.id()); + self.structs.insert(variant_def_id, Vec::new()); + true + } else { + false }; let child = self.add_child(name, parent, @@ -605,10 +603,12 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { // variants are always treated as importable to allow them to be glob // used child.define_value(DefVariant(item_id, - self.ast_map.local_def_id(variant.node.id), is_exported), + self.ast_map.local_def_id(variant.node.data.id()), + is_exported), variant.span, DefModifiers::PUBLIC | DefModifiers::IMPORTABLE); child.define_type(DefVariant(item_id, - self.ast_map.local_def_id(variant.node.id), is_exported), + self.ast_map.local_def_id(variant.node.data.id()), + is_exported), variant.span, DefModifiers::PUBLIC | DefModifiers::IMPORTABLE); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 40477d8698ebe..ac09534f1e0e5 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -491,7 +491,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { } visit::walk_poly_trait_ref(self, tref, m); } - fn visit_variant(&mut self, variant: &hir::Variant, generics: &Generics) { + fn visit_variant(&mut self, variant: &hir::Variant, generics: &Generics, item_id: ast::NodeId) { execute_callback!(hir_map::Node::NodeVariant(variant), self); if let Some(ref dis_expr) = variant.node.disr_expr { // resolve the discriminator expr as a constant @@ -501,19 +501,8 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { } // `visit::walk_variant` without the discriminant expression. - match variant.node.kind { - hir::TupleVariantKind(ref variant_arguments) => { - for variant_argument in variant_arguments { - self.visit_ty(&*variant_argument.ty); - } - } - hir::StructVariantKind(ref struct_definition) => { - self.visit_struct_def(&**struct_definition, - variant.node.name, - generics, - variant.node.id); - } - } + self.visit_variant_data(&variant.node.data, variant.node.name, + generics, item_id, variant.span); } fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem) { execute_callback!(hir_map::Node::NodeForeignItem(foreign_item), self); diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index 09825f1f91939..146fa857fc850 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -458,26 +458,22 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fn process_struct(&mut self, item: &ast::Item, - def: &ast::StructDef, + def: &ast::VariantData, ty_params: &ast::Generics) { let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); - let ctor_id = match def.ctor_id { - Some(node_id) => node_id, - None => ast::DUMMY_NODE_ID, - }; let val = self.span.snippet(item.span); let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct); self.fmt.struct_str(item.span, sub_span, item.id, - ctor_id, + def.id(), &qualname, self.cur_scope, &val); // fields - for field in &def.fields { + for field in def.fields() { self.process_struct_field_def(field, item.id); self.visit_ty(&field.node.ty); } @@ -504,40 +500,19 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { qualname.push_str("::"); qualname.push_str(name); let val = self.span.snippet(variant.span); - match variant.node.kind { - ast::TupleVariantKind(ref args) => { - // first ident in span is the variant's name - self.fmt.tuple_variant_str(variant.span, - self.span.span_for_first_ident(variant.span), - variant.node.id, - name, - &qualname, - &enum_data.qualname, - &val, - enum_data.id); - for arg in args { - self.visit_ty(&*arg.ty); - } - } - ast::StructVariantKind(ref struct_def) => { - let ctor_id = match struct_def.ctor_id { - Some(node_id) => node_id, - None => ast::DUMMY_NODE_ID, - }; - self.fmt.struct_variant_str(variant.span, - self.span.span_for_first_ident(variant.span), - variant.node.id, - ctor_id, - &qualname, - &enum_data.qualname, - &val, - enum_data.id); - - for field in &struct_def.fields { - self.process_struct_field_def(field, variant.node.id); - self.visit_ty(&*field.node.ty); - } - } + + self.fmt.struct_variant_str(variant.span, + self.span.span_for_first_ident(variant.span), + variant.node.data.id(), + variant.node.data.id(), + &qualname, + &enum_data.qualname, + &val, + enum_data.id); + + for field in variant.node.data.fields() { + self.process_struct_field_def(field, variant.node.data.id()); + self.visit_ty(&*field.node.ty); } } self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 05b20ac3fb7d4..9fa1aaf76f819 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2428,13 +2428,12 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { hir_map::NodeVariant(ref v) => { let llfn; - let args = match v.node.kind { - hir::TupleVariantKind(ref args) => args, - hir::StructVariantKind(_) => { - ccx.sess().bug("struct variant kind unexpected in get_item_val") - } + let fields = if v.node.data.is_struct() { + ccx.sess().bug("struct variant kind unexpected in get_item_val") + } else { + v.node.data.fields() }; - assert!(!args.is_empty()); + assert!(fields.count() != 0); let ty = ccx.tcx().node_id_to_type(id); let parent = ccx.tcx().map.get_parent(id); let enm = ccx.tcx().map.expect_item(parent); @@ -2455,12 +2454,11 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { hir_map::NodeStructCtor(struct_def) => { // Only register the constructor if this is a tuple-like struct. - let ctor_id = match struct_def.ctor_id { - None => { - ccx.sess().bug("attempt to register a constructor of \ - a non-tuple-like struct") - } - Some(ctor_id) => ctor_id, + let ctor_id = if struct_def.is_struct() { + ccx.sess().bug("attempt to register a constructor of \ + a non-tuple-like struct") + } else { + struct_def.id() }; let parent = ccx.tcx().map.get_parent(id); let struct_item = ccx.tcx().map.expect_item(parent); diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 86a65f57bdab0..c8525e33e2667 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -417,10 +417,9 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( || "local item should be in ast map".to_string()); match map_node { - hir_map::NodeVariant(v) => match v.node.kind { - hir::TupleVariantKind(ref args) => !args.is_empty(), - _ => false - }, + hir_map::NodeVariant(v) => { + v.node.data.is_tuple() + } hir_map::NodeStructCtor(_) => true, _ => false } diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index f509ed8dc5cbc..7c72b249a6e81 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -818,7 +818,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::VariantKind::Tuple => { expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val } - ty::VariantKind::Dict => { + ty::VariantKind::Struct => { cx.sess().span_bug(e.span, "path-expr refers to a dict variant!") } } diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index bc5152cba1f2c..aeda8f723cfee 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -1365,7 +1365,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { let sole_struct_member_description = MemberDescription { name: match non_null_variant.kind() { ty::VariantKind::Tuple => "__0".to_string(), - ty::VariantKind::Dict => { + ty::VariantKind::Struct => { non_null_variant.fields[0].name.to_string() } ty::VariantKind::Unit => unreachable!() @@ -1540,7 +1540,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, .map(|(i, _)| format!("__{}", i)) .collect() } - ty::VariantKind::Dict => { + ty::VariantKind::Struct => { variant.fields .iter() .map(|f| f.name.to_string()) diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index b8f75df8c11ca..14e1ca7675f79 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -110,18 +110,17 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) let ty_vs = &ccx.tcx().lookup_adt_def(parent_id).variants; assert_eq!(ast_vs.len(), ty_vs.len()); for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) { - if ty_v.did == fn_id { my_id = ast_v.node.id; } - ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.id)); + if ty_v.did == fn_id { my_id = ast_v.node.data.id(); } + ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.data.id())); } } hir::ItemStruct(ref struct_def, _) => { - match struct_def.ctor_id { - None => ccx.sess().bug("instantiate_inline: called on a \ - non-tuple struct"), - Some(ctor_id) => { - ccx.external().borrow_mut().insert(fn_id, Some(ctor_id)); - my_id = ctor_id; - } + if struct_def.is_struct() { + ccx.sess().bug("instantiate_inline: called on a \ + non-tuple struct") + } else { + ccx.external().borrow_mut().insert(fn_id, Some(struct_def.id())); + my_id = struct_def.id(); } } _ => ccx.sess().bug("instantiate_inline: item has a \ diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 33f798be85e87..f84f0feb96030 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -246,9 +246,11 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, hir_map::NodeStructCtor(struct_def) => { let d = mk_lldecl(abi::Rust); attributes::inline(d, attributes::InlineAttr::Hint); + if struct_def.is_struct() { + panic!("ast-mapped struct didn't have a ctor id") + } base::trans_tuple_struct(ccx, - struct_def.ctor_id.expect("ast-mapped tuple struct \ - didn't have a ctor id"), + struct_def.id(), psubsts, d); d diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 8bcff22575563..db5dd19c9236c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -530,7 +530,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx hir::Pat, let tcx = pcx.fcx.ccx.tcx; let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); - let variant = match fcx.def_struct_variant(def) { + let variant = match fcx.def_struct_variant(def, path.span) { Some((_, variant)) => variant, None => { let name = pprust::path_to_string(path); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f6b007018b88a..ba1af220d8e0f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1464,7 +1464,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Return the dict-like variant corresponding to a given `Def`. pub fn def_struct_variant(&self, - def: def::Def) + def: def::Def, + span: Span) -> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)> { let (adt, variant) = match def { @@ -1484,11 +1485,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let var_kind = variant.kind(); - if var_kind == ty::VariantKind::Dict || var_kind == ty::VariantKind::Unit { + if var_kind == ty::VariantKind::Struct { Some((adt, variant)) - } else { - None - } + } else if var_kind == ty::VariantKind::Unit { + if !self.tcx().sess.features.borrow().braced_empty_structs { + self.tcx().sess.span_err(span, "empty structs and enum variants \ + with braces are unstable"); + fileline_help!(self.tcx().sess, span, "add #![feature(braced_empty_structs)] to \ + the crate features to enable"); + } + + Some((adt, variant)) + } else { + None + } } pub fn write_nil(&self, node_id: ast::NodeId) { @@ -3177,7 +3187,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Find the relevant variant let def = lookup_full_def(tcx, path.span, expr.id); - let (adt, variant) = match fcx.def_struct_variant(def) { + let (adt, variant) = match fcx.def_struct_variant(def, path.span) { Some((adt, variant)) => (adt, variant), None => { span_err!(fcx.tcx().sess, path.span, E0071, diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index b5cf069bda684..14947d9955efd 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -624,11 +624,10 @@ struct AdtField<'tcx> { } fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - struct_def: &hir::StructDef) + struct_def: &hir::VariantData) -> AdtVariant<'tcx> { let fields = - struct_def.fields - .iter() + struct_def.fields() .map(|field| { let field_ty = fcx.tcx().node_id_to_type(field.node.id); let field_ty = fcx.instantiate_type_scheme(field.span, @@ -647,41 +646,7 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, enum_def: &hir::EnumDef) -> Vec> { enum_def.variants.iter() - .map(|variant| { - match variant.node.kind { - hir::TupleVariantKind(ref args) if !args.is_empty() => { - let ctor_ty = fcx.tcx().node_id_to_type(variant.node.id); - - // the regions in the argument types come from the - // enum def'n, and hence will all be early bound - let arg_tys = fcx.tcx().no_late_bound_regions(&ctor_ty.fn_args()).unwrap(); - AdtVariant { - fields: args.iter().enumerate().map(|(index, arg)| { - let arg_ty = arg_tys[index]; - let arg_ty = - fcx.instantiate_type_scheme(variant.span, - &fcx.inh - .infcx - .parameter_environment - .free_substs, - &arg_ty); - AdtField { - ty: arg_ty, - span: arg.ty.span - } - }).collect() - } - } - hir::TupleVariantKind(_) => { - AdtVariant { - fields: Vec::new() - } - } - hir::StructVariantKind(ref struct_def) => { - struct_variant(fcx, &**struct_def) - } - } - }) + .map(|variant| struct_variant(fcx, &variant.node.data)) .collect() } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b8d942ad22703..4cfc34dbb2384 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -521,11 +521,10 @@ struct AdtField<'tcx> { } fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - struct_def: &hir::StructDef) + struct_def: &hir::VariantData) -> AdtVariant<'tcx> { let fields = - struct_def.fields - .iter() + struct_def.fields() .map(|field| { let field_ty = fcx.tcx().node_id_to_type(field.node.id); let field_ty = fcx.instantiate_type_scheme(field.span, @@ -544,41 +543,7 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, enum_def: &hir::EnumDef) -> Vec> { enum_def.variants.iter() - .map(|variant| { - match variant.node.kind { - hir::TupleVariantKind(ref args) if !args.is_empty() => { - let ctor_ty = fcx.tcx().node_id_to_type(variant.node.id); - - // the regions in the argument types come from the - // enum def'n, and hence will all be early bound - let arg_tys = fcx.tcx().no_late_bound_regions(&ctor_ty.fn_args()).unwrap(); - AdtVariant { - fields: args.iter().enumerate().map(|(index, arg)| { - let arg_ty = arg_tys[index]; - let arg_ty = - fcx.instantiate_type_scheme(variant.span, - &fcx.inh - .infcx - .parameter_environment - .free_substs, - &arg_ty); - AdtField { - ty: arg_ty, - span: arg.ty.span - } - }).collect() - } - } - hir::TupleVariantKind(_) => { - AdtVariant { - fields: Vec::new() - } - } - hir::StructVariantKind(ref struct_def) => { - struct_variant(fcx, &**struct_def) - } - } - }) + .map(|variant| struct_variant(fcx, &variant.node.data)) .collect() } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 69d170602303b..194710a46fbce 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1010,12 +1010,12 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let it_def_id = ccx.tcx.map.local_def_id(it.id); let variant = tcx.lookup_adt_def_master(it_def_id).struct_variant(); - for (f, ty_f) in struct_def.fields.iter().zip(variant.fields.iter()) { + for (f, ty_f) in struct_def.fields().zip(variant.fields.iter()) { convert_field(ccx, &scheme.generics, &predicates, f, ty_f) } - if let Some(ctor_id) = struct_def.ctor_id { - convert_variant_ctor(tcx, ctor_id, variant, scheme, predicates); + if !struct_def.is_struct() { + convert_variant_ctor(tcx, struct_def.id(), variant, scheme, predicates); } }, hir::ItemTy(_, ref generics) => { @@ -1039,7 +1039,7 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, scheme: ty::TypeScheme<'tcx>, predicates: ty::GenericPredicates<'tcx>) { let ctor_ty = match variant.kind() { - VariantKind::Unit | VariantKind::Dict => scheme.ty, + VariantKind::Unit | VariantKind::Struct => scheme.ty, VariantKind::Tuple => { let inputs: Vec<_> = variant.fields @@ -1065,32 +1065,17 @@ fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, scheme: ty::TypeScheme<'tcx>, predicates: ty::GenericPredicates<'tcx>, variants: &[P]) { - let tcx = ccx.tcx; - let icx = ccx.icx(&predicates); - // fill the field types for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) { - match variant.node.kind { - hir::TupleVariantKind(ref args) => { - let rs = ExplicitRscope; - let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect(); - for (field, &ty) in ty_variant.fields.iter().zip(input_tys.iter()) { - field.fulfill_ty(ty); - } - } - - hir::StructVariantKind(ref struct_def) => { - for (f, ty_f) in struct_def.fields.iter().zip(ty_variant.fields.iter()) { - convert_field(ccx, &scheme.generics, &predicates, f, ty_f) - } - } - }; + for (f, ty_f) in variant.node.data.fields().zip(ty_variant.fields.iter()) { + convert_field(ccx, &scheme.generics, &predicates, f, ty_f) + } // Convert the ctor, if any. This also registers the variant as // an item. convert_variant_ctor( - tcx, - variant.node.id, + ccx.tcx, + variant.node.data.id(), ty_variant, scheme.clone(), predicates.clone() @@ -1102,9 +1087,9 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>, did: DefId, name: ast::Name, disr_val: ty::Disr, - def: &hir::StructDef) -> ty::VariantDefData<'tcx, 'tcx> { + def: &hir::VariantData) -> ty::VariantDefData<'tcx, 'tcx> { let mut seen_fields: FnvHashMap = FnvHashMap(); - let fields = def.fields.iter().map(|f| { + let fields = def.fields().map(|f| { let fid = tcx.map.local_def_id(f.node.id); match f.node.kind { hir::NamedField(name, vis) => { @@ -1135,13 +1120,16 @@ fn convert_struct_variant<'tcx>(tcx: &ty::ctxt<'tcx>, fn convert_struct_def<'tcx>(tcx: &ty::ctxt<'tcx>, it: &hir::Item, - def: &hir::StructDef) + def: &hir::VariantData) -> ty::AdtDefMaster<'tcx> { let did = tcx.map.local_def_id(it.id); - let ctor_id = def.ctor_id.map_or(did, - |ctor_id| tcx.map.local_def_id(ctor_id)); + let ctor_id = if !def.is_struct() { + tcx.map.local_def_id(def.id()) + } else { + did + }; tcx.intern_adt_def( did, ty::AdtKind::Struct, @@ -1221,27 +1209,9 @@ fn convert_enum_def<'tcx>(tcx: &ty::ctxt<'tcx>, disr: ty::Disr) -> ty::VariantDefData<'tcx, 'tcx> { - let did = tcx.map.local_def_id(v.node.id); + let did = tcx.map.local_def_id(v.node.data.id()); let name = v.node.name; - match v.node.kind { - hir::TupleVariantKind(ref va) => { - ty::VariantDefData { - did: did, - name: name, - disr_val: disr, - fields: va.iter().map(|&hir::VariantArg { id, .. }| { - ty::FieldDefData::new( - tcx.map.local_def_id(id), - special_idents::unnamed_field.name, - hir::Visibility::Public - ) - }).collect() - } - } - hir::StructVariantKind(ref def) => { - convert_struct_variant(tcx, did, name, disr, &def) - } - } + convert_struct_variant(tcx, did, name, disr, &v.node.data) } let did = tcx.map.local_def_id(it.id); let repr_hints = tcx.lookup_repr_hints(did); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 160c7e7d754d9..e4420d0dd92fa 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1805,11 +1805,11 @@ pub struct VariantStruct { pub fields_stripped: bool, } -impl Clean for ::rustc_front::hir::StructDef { +impl Clean for ::rustc_front::hir::VariantData { fn clean(&self, cx: &DocContext) -> VariantStruct { VariantStruct { struct_type: doctree::struct_type_from_def(self), - fields: self.fields.clean(cx), + fields: self.fields().map(|x| x.clean(cx)).collect(), fields_stripped: false, } } @@ -1853,9 +1853,9 @@ impl Clean for doctree::Variant { source: self.whence.clean(cx), visibility: None, stability: self.stab.clean(cx), - def_id: cx.map.local_def_id(self.id), + def_id: cx.map.local_def_id(self.def.id()), inner: VariantItem(Variant { - kind: self.kind.clean(cx), + kind: struct_def_to_variant_kind(&self.def, cx), }), } } @@ -1871,7 +1871,7 @@ impl<'tcx> Clean for ty::VariantDefData<'tcx, 'static> { self.fields.iter().map(|f| f.unsubst_ty().clean(cx)).collect() ) } - ty::VariantKind::Dict => { + ty::VariantKind::Struct => { StructVariant(VariantStruct { struct_type: doctree::Plain, fields_stripped: false, @@ -1917,18 +1917,13 @@ pub enum VariantKind { StructVariant(VariantStruct), } -impl Clean for hir::VariantKind { - fn clean(&self, cx: &DocContext) -> VariantKind { - match self { - &hir::TupleVariantKind(ref args) => { - if args.is_empty() { - CLikeVariant - } else { - TupleVariant(args.iter().map(|x| x.ty.clean(cx)).collect()) - } - }, - &hir::StructVariantKind(ref sd) => StructVariant(sd.clean(cx)), - } +fn struct_def_to_variant_kind(struct_def: &hir::VariantData, cx: &DocContext) -> VariantKind { + if struct_def.is_struct() { + StructVariant(struct_def.clean(cx)) + } else if struct_def.is_unit() { + CLikeVariant + } else { + TupleVariant(struct_def.fields().map(|x| x.node.ty.clean(cx)).collect()) } } diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index c234ec01b8869..47cc007f605eb 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -119,8 +119,7 @@ pub struct Enum { pub struct Variant { pub name: Name, pub attrs: Vec, - pub kind: hir::VariantKind, - pub id: ast::NodeId, + pub def: P, pub stab: Option, pub whence: Span, } @@ -234,10 +233,10 @@ pub struct Import { pub whence: Span, } -pub fn struct_type_from_def(sd: &hir::StructDef) -> StructType { - if sd.ctor_id.is_some() { +pub fn struct_type_from_def(sd: &hir::VariantData) -> StructType { + if !sd.is_struct() { // We are in a tuple-struct - match sd.fields.len() { + match sd.fields().count() { 0 => Unit, 1 => Newtype, _ => Tuple diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 264656835a384..1487c1668aac7 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -84,8 +84,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.module.is_crate = true; } - pub fn visit_struct_def(&mut self, item: &hir::Item, - name: ast::Name, sd: &hir::StructDef, + pub fn visit_variant_data(&mut self, item: &hir::Item, + name: ast::Name, sd: &hir::VariantData, generics: &hir::Generics) -> Struct { debug!("Visiting struct"); let struct_type = struct_type_from_def(&*sd); @@ -97,7 +97,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { stab: self.stability(item.id), attrs: item.attrs.clone(), generics: generics.clone(), - fields: sd.fields.clone(), + fields: sd.fields().cloned().collect(), whence: item.span } } @@ -111,9 +111,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { variants: def.variants.iter().map(|v| Variant { name: v.node.name, attrs: v.node.attrs.clone(), - stab: self.stability(v.node.id), - id: v.node.id, - kind: v.node.kind.clone(), + stab: self.stability(v.node.data.id()), + def: v.node.data.clone(), whence: v.span, }).collect(), vis: it.vis, @@ -299,7 +298,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::ItemEnum(ref ed, ref gen) => om.enums.push(self.visit_enum_def(item, name, ed, gen)), hir::ItemStruct(ref sd, ref gen) => - om.structs.push(self.visit_struct_def(item, name, &**sd, gen)), + om.structs.push(self.visit_variant_data(item, name, &**sd, gen)), hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) => om.fns.push(self.visit_fn(item, name, &**fd, unsafety, constness, abi, gen)), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 34b99ab8cce1c..720c2ffc6d483 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -44,7 +44,6 @@ pub use self::TyParamBound::*; pub use self::UintTy::*; pub use self::UnOp::*; pub use self::UnsafeSource::*; -pub use self::VariantKind::*; pub use self::ViewPath_::*; pub use self::Visibility::*; pub use self::PathParameters::*; @@ -66,6 +65,7 @@ use std::fmt; use std::rc::Rc; use std::borrow::Cow; use std::hash::{Hash, Hasher}; +use std::{iter, option, slice}; use serialize::{Encodable, Decodable, Encoder, Decoder}; /// A name is a part of an identifier, representing a string or gensym. It's @@ -1571,20 +1571,6 @@ pub struct ForeignMod { pub items: Vec>, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct VariantArg { - pub ty: P, - pub id: NodeId, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum VariantKind { - /// Tuple variant, e.g. `Foo(A, B)` - TupleVariantKind(Vec), - /// Struct variant, e.g. `Foo {x: A, y: B}` - StructVariantKind(P), -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: Vec>, @@ -1594,8 +1580,7 @@ pub struct EnumDef { pub struct Variant_ { pub name: Ident, pub attrs: Vec, - pub kind: VariantKind, - pub id: NodeId, + pub data: P, /// Explicit discriminant, eg `Foo = 1` pub disr_expr: Option>, } @@ -1756,13 +1741,50 @@ impl StructFieldKind { } } +/// Fields and Ids of enum variants and structs +/// +/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all +/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants). +/// One shared Id can be successfully used for these two purposes. +/// Id of the whole enum lives in `Item`. +/// +/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually +/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of +/// the variant itself" from enum variants. +/// Id of the whole struct lives in `Item`. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct StructDef { - /// Fields, not including ctor - pub fields: Vec, - /// ID of the constructor. This is only used for tuple- or enum-like - /// structs. - pub ctor_id: Option, +pub enum VariantData { + Struct(Vec, NodeId), + Tuple(Vec, NodeId), + Unit(NodeId), +} + +pub type FieldIter<'a> = iter::FlatMap>, + slice::Iter<'a, StructField>, + fn(&Vec) -> slice::Iter>; + +impl VariantData { + pub fn fields(&self) -> FieldIter { + fn vec_iter(v: &Vec) -> slice::Iter { v.iter() } + match *self { + VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => Some(fields), + _ => None, + }.into_iter().flat_map(vec_iter) + } + pub fn id(&self) -> NodeId { + match *self { + VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id + } + } + pub fn is_struct(&self) -> bool { + if let VariantData::Struct(..) = *self { true } else { false } + } + pub fn is_tuple(&self) -> bool { + if let VariantData::Tuple(..) = *self { true } else { false } + } + pub fn is_unit(&self) -> bool { + if let VariantData::Unit(..) = *self { true } else { false } + } } /* @@ -1806,7 +1828,7 @@ pub enum Item_ { /// An enum definition, e.g. `enum Foo {C, D}` ItemEnum(EnumDef, Generics), /// A struct definition, e.g. `struct Foo {x: A}` - ItemStruct(P, Generics), + ItemStruct(P, Generics), /// Represents a Trait Declaration ItemTrait(Unsafety, Generics, diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 905a83b050ed7..8c3360512d512 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -360,11 +360,6 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { } } } - ItemEnum(ref enum_definition, _) => { - for variant in &enum_definition.variants { - self.operation.visit_id(variant.node.id) - } - } _ => {} } @@ -457,13 +452,13 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { visit::walk_struct_field(self, struct_field) } - fn visit_struct_def(&mut self, - struct_def: &StructDef, + fn visit_variant_data(&mut self, + struct_def: &VariantData, _: ast::Ident, _: &ast::Generics, - id: NodeId) { - self.operation.visit_id(id); - struct_def.ctor_id.map(|ctor_id| self.operation.visit_id(ctor_id)); + _: NodeId, + _: Span) { + self.operation.visit_id(struct_def.id()); visit::walk_struct_def(self, struct_def); } @@ -529,12 +524,6 @@ pub fn compute_id_range_for_fn_body(fk: FnKind, id_visitor.operation.result } -/// Returns true if the given struct def is tuple-like; i.e. that its fields -/// are unnamed. -pub fn struct_def_is_tuple_like(struct_def: &ast::StructDef) -> bool { - struct_def.ctor_id.is_some() -} - /// Returns true if the given pattern consists solely of an identifier /// and false otherwise. pub fn pat_is_ident(pat: P) -> bool { diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 2d266be3242a5..0ca110c5b1ed2 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -140,19 +140,13 @@ fn fold_item_underscore(cx: &mut Context, item: ast::Item_) -> ast::Item_ if !(cx.in_cfg)(&v.node.attrs) { None } else { - Some(v.map(|Spanned {node: ast::Variant_ {id, name, attrs, kind, + Some(v.map(|Spanned {node: ast::Variant_ {name, attrs, data, disr_expr}, span}| { Spanned { node: ast::Variant_ { - id: id, name: name, attrs: attrs, - kind: match kind { - ast::TupleVariantKind(..) => kind, - ast::StructVariantKind(def) => { - ast::StructVariantKind(fold_struct(cx, def)) - } - }, + data: fold_struct(cx, data), disr_expr: disr_expr, }, span: span @@ -170,15 +164,22 @@ fn fold_item_underscore(cx: &mut Context, item: ast::Item_) -> ast::Item_ fold::noop_fold_item_underscore(item, cx) } -fn fold_struct(cx: &mut Context, def: P) -> P where +fn fold_struct(cx: &mut Context, def: P) -> P where F: FnMut(&[ast::Attribute]) -> bool { - def.map(|ast::StructDef { fields, ctor_id }| { - ast::StructDef { - fields: fields.into_iter().filter(|m| { - (cx.in_cfg)(&m.node.attrs) - }).collect(), - ctor_id: ctor_id, + def.map(|vdata| { + match vdata { + ast::VariantData::Struct(fields, id) => { + ast::VariantData::Struct(fields.into_iter().filter(|m| { + (cx.in_cfg)(&m.node.attrs) + }).collect(), id) + } + ast::VariantData::Tuple(fields, id) => { + ast::VariantData::Tuple(fields.into_iter().filter(|m| { + (cx.in_cfg)(&m.node.attrs) + }).collect(), id) + } + ast::VariantData::Unit(id) => ast::VariantData::Unit(id) } }) } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index efea85f916252..9b06fbd0a0b85 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -247,9 +247,9 @@ pub trait AstBuilder { fn item_struct_poly(&self, span: Span, name: Ident, - struct_def: ast::StructDef, + struct_def: ast::VariantData, generics: Generics) -> P; - fn item_struct(&self, span: Span, name: Ident, struct_def: ast::StructDef) -> P; + fn item_struct(&self, span: Span, name: Ident, struct_def: ast::VariantData) -> P; fn item_mod(&self, span: Span, inner_span: Span, name: Ident, attrs: Vec, @@ -993,16 +993,26 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn variant(&self, span: Span, name: Ident, tys: Vec> ) -> ast::Variant { - let args = tys.into_iter().map(|ty| { - ast::VariantArg { ty: ty, id: ast::DUMMY_NODE_ID } + let fields: Vec<_> = tys.into_iter().map(|ty| { + Spanned { span: ty.span, node: ast::StructField_ { + ty: ty, + kind: ast::UnnamedField(ast::Inherited), + attrs: Vec::new(), + id: ast::DUMMY_NODE_ID, + }} }).collect(); + let vdata = if fields.is_empty() { + ast::VariantData::Unit(ast::DUMMY_NODE_ID) + } else { + ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID) + }; + respan(span, ast::Variant_ { name: name, attrs: Vec::new(), - kind: ast::TupleVariantKind(args), - id: ast::DUMMY_NODE_ID, + data: P(vdata), disr_expr: None, }) } @@ -1020,7 +1030,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn item_struct(&self, span: Span, name: Ident, - struct_def: ast::StructDef) -> P { + struct_def: ast::VariantData) -> P { self.item_struct_poly( span, name, @@ -1030,7 +1040,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn item_struct_poly(&self, span: Span, name: Ident, - struct_def: ast::StructDef, generics: Generics) -> P { + struct_def: ast::VariantData, generics: Generics) -> P { self.item(span, name, Vec::new(), ast::ItemStruct(P(struct_def), generics)) } diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 9fc2745cf929a..2a5c4993112a9 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -174,9 +174,9 @@ //! A static method on the types above would result in, //! //! ```{.text} -//! StaticStruct(, Named(vec![(, )])) +//! StaticStruct(, Named(vec![(, )])) //! -//! StaticStruct(, Unnamed(vec![])) +//! StaticStruct(, Unnamed(vec![])) //! //! StaticEnum(, //! vec![(, , Unnamed(vec![])), @@ -194,7 +194,7 @@ use std::vec; use abi::Abi; use abi; use ast; -use ast::{EnumDef, Expr, Ident, Generics, StructDef}; +use ast::{EnumDef, Expr, Ident, Generics, VariantData}; use ast_util; use attr; use attr::AttrMetaMethods; @@ -317,7 +317,7 @@ pub enum SubstructureFields<'a> { EnumNonMatchingCollapsed(Vec, &'a [P], &'a [Ident]), /// A static method where `Self` is a struct. - StaticStruct(&'a ast::StructDef, StaticFields), + StaticStruct(&'a ast::VariantData, StaticFields), /// A static method where `Self` is an enum. StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>), } @@ -649,10 +649,10 @@ impl<'a> TraitDef<'a> { fn expand_struct_def(&self, cx: &mut ExtCtxt, - struct_def: &'a StructDef, + struct_def: &'a VariantData, type_ident: Ident, generics: &Generics) -> P { - let field_tys: Vec> = struct_def.fields.iter() + let field_tys: Vec> = struct_def.fields() .map(|field| field.node.ty.clone()) .collect(); @@ -700,16 +700,8 @@ impl<'a> TraitDef<'a> { let mut field_tys = Vec::new(); for variant in &enum_def.variants { - match variant.node.kind { - ast::VariantKind::TupleVariantKind(ref args) => { - field_tys.extend(args.iter() - .map(|arg| arg.ty.clone())); - } - ast::VariantKind::StructVariantKind(ref args) => { - field_tys.extend(args.fields.iter() - .map(|field| field.node.ty.clone())); - } - } + field_tys.extend(variant.node.data.fields() + .map(|field| field.node.ty.clone())); } let methods = self.methods.iter().map(|method_def| { @@ -935,7 +927,7 @@ impl<'a> MethodDef<'a> { fn expand_struct_method_body<'b>(&self, cx: &mut ExtCtxt, trait_: &TraitDef<'b>, - struct_def: &'b StructDef, + struct_def: &'b VariantData, type_ident: Ident, self_args: &[P], nonself_args: &[P]) @@ -1004,7 +996,7 @@ impl<'a> MethodDef<'a> { fn expand_static_struct_method_body(&self, cx: &mut ExtCtxt, trait_: &TraitDef, - struct_def: &StructDef, + struct_def: &VariantData, type_ident: Ident, self_args: &[P], nonself_args: &[P]) @@ -1413,14 +1405,7 @@ impl<'a> MethodDef<'a> { -> P { let summary = enum_def.variants.iter().map(|v| { let ident = v.node.name; - let summary = match v.node.kind { - ast::TupleVariantKind(ref args) => { - Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect()) - } - ast::StructVariantKind(ref struct_def) => { - trait_.summarise_struct(cx, &**struct_def) - } - }; + let summary = trait_.summarise_struct(cx, &v.node.data); (ident, v.span, summary) }).collect(); self.call_substructure_method(cx, trait_, type_ident, @@ -1456,10 +1441,10 @@ impl<'a> TraitDef<'a> { fn summarise_struct(&self, cx: &mut ExtCtxt, - struct_def: &StructDef) -> StaticFields { + struct_def: &VariantData) -> StaticFields { let mut named_idents = Vec::new(); let mut just_spans = Vec::new(); - for field in struct_def.fields.iter(){ + for field in struct_def.fields(){ let sp = self.set_expn_info(cx, field.span); match field.node.kind { ast::NamedField(ident, _) => named_idents.push((ident, sp)), @@ -1492,13 +1477,13 @@ impl<'a> TraitDef<'a> { fn create_struct_pattern(&self, cx: &mut ExtCtxt, struct_path: ast::Path, - struct_def: &'a StructDef, + struct_def: &'a VariantData, prefix: &str, mutbl: ast::Mutability) -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { - if struct_def.fields.is_empty() { + if struct_def.fields().count() == 0 { return (cx.pat_enum(self.span, struct_path, vec![]), vec![]); } @@ -1506,7 +1491,7 @@ impl<'a> TraitDef<'a> { let mut ident_expr = Vec::new(); let mut struct_type = Unknown; - for (i, struct_field) in struct_def.fields.iter().enumerate() { + for (i, struct_field) in struct_def.fields().enumerate() { let sp = self.set_expn_info(cx, struct_field.span); let opt_id = match struct_field.node.kind { ast::NamedField(ident, _) if (struct_type == Unknown || @@ -1560,34 +1545,7 @@ impl<'a> TraitDef<'a> { -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { let variant_ident = variant.node.name; let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]); - match variant.node.kind { - ast::TupleVariantKind(ref variant_args) => { - if variant_args.is_empty() { - return (cx.pat_enum(variant.span, variant_path, vec![]), vec![]); - } - - let mut paths = Vec::new(); - let mut ident_expr: Vec<(_, _, _, &'a [ast::Attribute])> = Vec::new(); - for (i, va) in variant_args.iter().enumerate() { - let sp = self.set_expn_info(cx, va.ty.span); - let ident = cx.ident_of(&format!("{}_{}", prefix, i)); - let path1 = codemap::Spanned{span: sp, node: ident}; - paths.push(path1); - let expr_path = cx.expr_path(cx.path_ident(sp, ident)); - let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path))); - ident_expr.push((sp, None, val, &[])); - } - - let subpats = self.create_subpatterns(cx, paths, mutbl); - - (cx.pat_enum(variant.span, variant_path, subpats), - ident_expr) - } - ast::StructVariantKind(ref struct_def) => { - self.create_struct_pattern(cx, variant_path, &**struct_def, - prefix, mutbl) - } - } + self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl) } } diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs index 5d3cc50557cde..07b587783583e 100644 --- a/src/libsyntax/ext/deriving/primitive.rs +++ b/src/libsyntax/ext/deriving/primitive.rs @@ -94,45 +94,35 @@ fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure let mut arms = Vec::new(); for variant in &enum_def.variants { - match variant.node.kind { - ast::TupleVariantKind(ref args) => { - if !args.is_empty() { - cx.span_err(trait_span, - "`FromPrimitive` cannot be derived for \ - enum variants with arguments"); - return cx.expr_fail(trait_span, - InternedString::new("")); - } - let span = variant.span; + let def = &variant.node.data; + if !def.is_unit() { + cx.span_err(trait_span, "`FromPrimitive` cannot be derived \ + for enums with non-unit variants"); + return cx.expr_fail(trait_span, + InternedString::new("")); + } - // expr for `$n == $variant as $name` - let path = cx.path(span, vec![substr.type_ident, variant.node.name]); - let variant = cx.expr_path(path); - let ty = cx.ty_ident(span, cx.ident_of(name)); - let cast = cx.expr_cast(span, variant.clone(), ty); - let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast); + let span = variant.span; - // expr for `Some($variant)` - let body = cx.expr_some(span, variant); + // expr for `$n == $variant as $name` + let path = cx.path(span, vec![substr.type_ident, variant.node.name]); + let variant = cx.expr_path(path); + let ty = cx.ty_ident(span, cx.ident_of(name)); + let cast = cx.expr_cast(span, variant.clone(), ty); + let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast); - // arm for `_ if $guard => $body` - let arm = ast::Arm { - attrs: vec!(), - pats: vec!(cx.pat_wild(span)), - guard: Some(guard), - body: body, - }; + // expr for `Some($variant)` + let body = cx.expr_some(span, variant); - arms.push(arm); - } - ast::StructVariantKind(_) => { - cx.span_err(trait_span, - "`FromPrimitive` cannot be derived for enums \ - with struct variants"); - return cx.expr_fail(trait_span, - InternedString::new("")); - } - } + // arm for `_ if $guard => $body` + let arm = ast::Arm { + attrs: vec!(), + pats: vec!(cx.pat_wild(span)), + guard: Some(guard), + body: body, + }; + + arms.push(arm); } // arm for `_ => None` diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1d545268e57d7..be6ad9311114a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -196,7 +196,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status // allow `#[unwind]` ("unwind_attributes", "1.4.0", None, Active), - // allow empty structs/enum variants with braces + // allow empty structs and enum variants with braces ("braced_empty_structs", "1.5.0", None, Active), // allow overloading augmented assignment operations like `a += b` @@ -486,6 +486,7 @@ pub struct Features { pub cfg_target_feature: bool, pub cfg_target_vendor: bool, pub augmented_assignments: bool, + pub braced_empty_structs: bool, } impl Features { @@ -516,6 +517,7 @@ impl Features { cfg_target_feature: false, cfg_target_vendor: false, augmented_assignments: false, + braced_empty_structs: false, } } } @@ -809,7 +811,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } } - ast::ItemStruct(ref def, _) => { + ast::ItemStruct(..) => { if attr::contains_name(&i.attrs[..], "simd") { self.gate_feature("simd", i.span, "SIMD types are experimental and possibly buggy"); @@ -828,10 +830,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } } } - if def.fields.is_empty() && def.ctor_id.is_none() { - self.gate_feature("braced_empty_structs", i.span, - "empty structs with braces are unstable"); - } } ast::ItemDefaultImpl(..) => { @@ -859,6 +857,21 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { visit::walk_item(self, i); } + fn visit_variant_data(&mut self, s: &'v ast::VariantData, _: ast::Ident, + _: &'v ast::Generics, _: ast::NodeId, span: Span) { + if s.fields().count() == 0 { + if s.is_struct() { + self.gate_feature("braced_empty_structs", span, + "empty structs and enum variants with braces are unstable"); + } else if s.is_tuple() { + self.context.span_handler.span_err(span, "empty tuple structs and enum variants \ + are not allowed, use unit structs and \ + enum variants instead"); + } + } + visit::walk_struct_def(self, s) + } + fn visit_foreign_item(&mut self, i: &ast::ForeignItem) { let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") { @@ -881,12 +894,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { "box expression syntax is experimental; \ you can call `Box::new` instead."); } - ast::ExprStruct(_, ref fields, ref expr) => { - if fields.is_empty() && expr.is_none() { - self.gate_feature("braced_empty_structs", e.span, - "empty structs with braces are unstable"); - } - } _ => {} } visit::walk_expr(self, e); @@ -911,12 +918,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { pattern.span, "box pattern syntax is experimental"); } - ast::PatStruct(_, ref fields, dotdot) => { - if fields.is_empty() && !dotdot { - self.gate_feature("braced_empty_structs", pattern.span, - "empty structs with braces are unstable"); - } - } _ => {} } visit::walk_pat(self, pattern) @@ -1086,6 +1087,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, cfg_target_feature: cx.has_feature("cfg_target_feature"), cfg_target_vendor: cx.has_feature("cfg_target_vendor"), augmented_assignments: cx.has_feature("augmented_assignments"), + braced_empty_structs: cx.has_feature("braced_empty_structs"), } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 3c1aa992a3c16..219a4649339dd 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -231,7 +231,7 @@ pub trait Folder : Sized { noop_fold_poly_trait_ref(p, self) } - fn fold_struct_def(&mut self, struct_def: P) -> P { + fn fold_variant_data(&mut self, struct_def: P) -> P { noop_fold_struct_def(struct_def, self) } @@ -271,10 +271,6 @@ pub trait Folder : Sized { noop_fold_opt_lifetime(o_lt, self) } - fn fold_variant_arg(&mut self, va: VariantArg) -> VariantArg { - noop_fold_variant_arg(va, self) - } - fn fold_opt_bounds(&mut self, b: Option>) -> Option> { noop_fold_opt_bounds(b, self) @@ -450,20 +446,11 @@ pub fn noop_fold_foreign_mod(ForeignMod {abi, items}: ForeignMod, } pub fn noop_fold_variant(v: P, fld: &mut T) -> P { - v.map(|Spanned {node: Variant_ {id, name, attrs, kind, disr_expr}, span}| Spanned { + v.map(|Spanned {node: Variant_ {name, attrs, data, disr_expr}, span}| Spanned { node: Variant_ { - id: fld.new_id(id), name: name, attrs: fold_attrs(attrs, fld), - kind: match kind { - TupleVariantKind(variant_args) => { - TupleVariantKind(variant_args.move_map(|x| - fld.fold_variant_arg(x))) - } - StructVariantKind(struct_def) => { - StructVariantKind(fld.fold_struct_def(struct_def)) - } - }, + data: fld.fold_variant_data(data), disr_expr: disr_expr.map(|e| fld.fold_expr(e)), }, span: fld.new_span(span), @@ -827,10 +814,19 @@ pub fn noop_fold_where_predicate( } } -pub fn noop_fold_struct_def(struct_def: P, fld: &mut T) -> P { - struct_def.map(|StructDef { fields, ctor_id }| StructDef { - fields: fields.move_map(|f| fld.fold_struct_field(f)), - ctor_id: ctor_id.map(|cid| fld.new_id(cid)), +pub fn noop_fold_struct_def(struct_def: P, fld: &mut T) -> P { + struct_def.map(|vdata| { + match vdata { + ast::VariantData::Struct(fields, id) => { + ast::VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)), + fld.new_id(id)) + } + ast::VariantData::Tuple(fields, id) => { + ast::VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)), + fld.new_id(id)) + } + ast::VariantData::Unit(id) => ast::VariantData::Unit(fld.new_id(id)) + } }) } @@ -892,14 +888,6 @@ fn noop_fold_bounds(bounds: TyParamBounds, folder: &mut T) bounds.move_map(|bound| folder.fold_ty_param_bound(bound)) } -fn noop_fold_variant_arg(VariantArg {id, ty}: VariantArg, folder: &mut T) - -> VariantArg { - VariantArg { - id: folder.new_id(id), - ty: folder.fold_ty(ty) - } -} - pub fn noop_fold_block(b: P, folder: &mut T) -> P { b.map(|Block {id, stmts, expr, rules, span}| Block { id: folder.new_id(id), @@ -945,7 +933,7 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { folder.fold_generics(generics)) } ItemStruct(struct_def, generics) => { - let struct_def = folder.fold_struct_def(struct_def); + let struct_def = folder.fold_variant_data(struct_def); ItemStruct(struct_def, folder.fold_generics(generics)) } ItemDefaultImpl(unsafety, ref trait_ref) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 443cea696b682..934e4472bdc84 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -45,12 +45,12 @@ use ast::{PatRegion, PatStruct, PatTup, PatVec, PatWild, PatWildMulti}; use ast::PatWildSingle; use ast::{PolyTraitRef, QSelf}; use ast::{Return, BiShl, BiShr, Stmt, StmtDecl}; -use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; -use ast::{StructVariantKind, BiSub, StrStyle}; +use ast::{StmtExpr, StmtSemi, StmtMac, VariantData, StructField}; +use ast::{BiSub, StrStyle}; use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue}; use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef}; use ast::{TtDelimited, TtSequence, TtToken}; -use ast::{TupleVariantKind, Ty, Ty_, TypeBinding}; +use ast::{Ty, Ty_, TypeBinding}; use ast::{TyMac}; use ast::{TyFixedLengthVec, TyBareFn, TyTypeof, TyInfer}; use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr}; @@ -4640,26 +4640,25 @@ impl<'a> Parser<'a> { // Otherwise if we look ahead and see a paren we parse a tuple-style // struct. - let (fields, ctor_id) = if self.token.is_keyword(keywords::Where) { + let vdata = if self.token.is_keyword(keywords::Where) { generics.where_clause = try!(self.parse_where_clause()); if try!(self.eat(&token::Semi)) { // If we see a: `struct Foo where T: Copy;` style decl. - (Vec::new(), Some(ast::DUMMY_NODE_ID)) + VariantData::Unit(ast::DUMMY_NODE_ID) } else { // If we see: `struct Foo where T: Copy { ... }` - (try!(self.parse_record_struct_body()), None) + VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID) } // No `where` so: `struct Foo;` } else if try!(self.eat(&token::Semi) ){ - (Vec::new(), Some(ast::DUMMY_NODE_ID)) + VariantData::Unit(ast::DUMMY_NODE_ID) // Record-style struct definition } else if self.token == token::OpenDelim(token::Brace) { - let fields = try!(self.parse_record_struct_body()); - (fields, None) + VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID) // Tuple-style struct definition with optional where-clause. } else if self.token == token::OpenDelim(token::Paren) { - let fields = try!(self.parse_tuple_struct_body(class_name, &mut generics)); - (fields, Some(ast::DUMMY_NODE_ID)) + VariantData::Tuple(try!(self.parse_tuple_struct_body(&mut generics)), + ast::DUMMY_NODE_ID) } else { let token_str = self.this_token_to_string(); return Err(self.fatal(&format!("expected `where`, `{{`, `(`, or `;` after struct \ @@ -4667,11 +4666,8 @@ impl<'a> Parser<'a> { }; Ok((class_name, - ItemStruct(P(ast::StructDef { - fields: fields, - ctor_id: ctor_id, - }), generics), - None)) + ItemStruct(P(vdata), generics), + None)) } pub fn parse_record_struct_body(&mut self) -> PResult> { @@ -4693,7 +4689,6 @@ impl<'a> Parser<'a> { } pub fn parse_tuple_struct_body(&mut self, - class_name: ast::Ident, generics: &mut ast::Generics) -> PResult> { // This is the case where we find `struct Foo(T) where T: Copy;` @@ -4714,12 +4709,6 @@ impl<'a> Parser<'a> { Ok(spanned(lo, p.span.hi, struct_field_)) })); - if fields.is_empty() { - return Err(self.fatal(&format!("unit-like struct definition should be \ - written as `struct {};`", - class_name))); - } - generics.where_clause = try!(self.parse_where_clause()); try!(self.expect(&token::Semi)); Ok(fields) @@ -5109,17 +5098,14 @@ impl<'a> Parser<'a> { /// Parse a structure-like enum variant definition /// this should probably be renamed or refactored... - fn parse_struct_def(&mut self) -> PResult> { + fn parse_struct_def(&mut self) -> PResult> { let mut fields: Vec = Vec::new(); while self.token != token::CloseDelim(token::Brace) { fields.push(try!(self.parse_struct_decl_field(false))); } try!(self.bump()); - Ok(P(StructDef { - fields: fields, - ctor_id: None, - })) + Ok(P(VariantData::Struct(fields, ast::DUMMY_NODE_ID))) } /// Parse the part of an "enum" decl following the '{' @@ -5131,22 +5117,13 @@ impl<'a> Parser<'a> { let variant_attrs = self.parse_outer_attributes(); let vlo = self.span.lo; - let kind; - let mut args = Vec::new(); + let struct_def; let mut disr_expr = None; let ident = try!(self.parse_ident()); if try!(self.eat(&token::OpenDelim(token::Brace)) ){ // Parse a struct variant. all_nullary = false; - let start_span = self.span; - let struct_def = try!(self.parse_struct_def()); - if struct_def.fields.is_empty() { - self.span_err(start_span, - &format!("unit-like struct variant should be written \ - without braces, as `{},`", - ident)); - } - kind = StructVariantKind(struct_def); + struct_def = try!(self.parse_struct_def()); } else if self.check(&token::OpenDelim(token::Paren)) { all_nullary = false; let arg_tys = try!(self.parse_enum_variant_seq( @@ -5155,26 +5132,28 @@ impl<'a> Parser<'a> { seq_sep_trailing_allowed(token::Comma), |p| p.parse_ty_sum() )); + let mut fields = Vec::new(); for ty in arg_tys { - args.push(ast::VariantArg { + fields.push(Spanned { span: ty.span, node: ast::StructField_ { ty: ty, + kind: ast::UnnamedField(ast::Inherited), + attrs: Vec::new(), id: ast::DUMMY_NODE_ID, - }); + }}); } - kind = TupleVariantKind(args); + struct_def = P(ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID)); } else if try!(self.eat(&token::Eq) ){ disr_expr = Some(try!(self.parse_expr_nopanic())); any_disr = disr_expr.as_ref().map(|expr| expr.span); - kind = TupleVariantKind(args); + struct_def = P(ast::VariantData::Unit(ast::DUMMY_NODE_ID)); } else { - kind = TupleVariantKind(Vec::new()); + struct_def = P(ast::VariantData::Unit(ast::DUMMY_NODE_ID)); } let vr = ast::Variant_ { name: ident, attrs: variant_attrs, - kind: kind, - id: ast::DUMMY_NODE_ID, + data: struct_def, disr_expr: disr_expr, }; variants.push(P(spanned(vlo, self.last_span.hi, vr))); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f5f3907a4e6c8..e5a9ce216a92a 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -520,6 +520,18 @@ pub trait PrintState<'a> { self.end() } + fn commasep_iter<'it, T: 'it, F, I>(&mut self, b: Breaks, elts: I, mut op: F) -> io::Result<()> + where F: FnMut(&mut Self, &T) -> io::Result<()>, + I: Iterator, + { + try!(self.rbox(0, b)); + let mut first = true; + for elt in elts { + if first { first = false; } else { try!(self.word_space(",")); } + try!(op(self, elt)); + } + self.end() + } fn next_lit(&mut self, pos: BytePos) -> Option { let mut cur_lit = self.cur_cmnt_and_lit().cur_lit; @@ -1223,7 +1235,7 @@ impl<'a> State<'a> { } ast::ItemStruct(ref struct_def, ref generics) => { try!(self.head(&visibility_qualified(item.vis,"struct"))); - try!(self.print_struct(&**struct_def, generics, item.ident, item.span)); + try!(self.print_struct(&struct_def, generics, item.ident, item.span, true)); } ast::ItemDefaultImpl(unsafety, ref trait_ref) => { @@ -1385,17 +1397,18 @@ impl<'a> State<'a> { } pub fn print_struct(&mut self, - struct_def: &ast::StructDef, + struct_def: &ast::VariantData, generics: &ast::Generics, ident: ast::Ident, - span: codemap::Span) -> io::Result<()> { + span: codemap::Span, + print_finalizer: bool) -> io::Result<()> { try!(self.print_ident(ident)); try!(self.print_generics(generics)); - if ast_util::struct_def_is_tuple_like(struct_def) { - if !struct_def.fields.is_empty() { + if !struct_def.is_struct() { + if struct_def.is_tuple() { try!(self.popen()); - try!(self.commasep( - Inconsistent, &struct_def.fields, + try!(self.commasep_iter( + Inconsistent, struct_def.fields(), |s, field| { match field.node.kind { ast::NamedField(..) => panic!("unexpected named field"), @@ -1410,7 +1423,9 @@ impl<'a> State<'a> { try!(self.pclose()); } try!(self.print_where_clause(&generics.where_clause)); - try!(word(&mut self.s, ";")); + if print_finalizer { + try!(word(&mut self.s, ";")); + } try!(self.end()); self.end() // close the outer-box } else { @@ -1419,7 +1434,7 @@ impl<'a> State<'a> { try!(self.bopen()); try!(self.hardbreak_if_not_bol()); - for field in &struct_def.fields { + for field in struct_def.fields() { match field.node.kind { ast::UnnamedField(..) => panic!("unexpected unnamed field"), ast::NamedField(ident, visibility) => { @@ -1505,23 +1520,9 @@ impl<'a> State<'a> { } pub fn print_variant(&mut self, v: &ast::Variant) -> io::Result<()> { - match v.node.kind { - ast::TupleVariantKind(ref args) => { - try!(self.print_ident(v.node.name)); - if !args.is_empty() { - try!(self.popen()); - try!(self.commasep(Consistent, - &args[..], - |s, arg| s.print_type(&*arg.ty))); - try!(self.pclose()); - } - } - ast::StructVariantKind(ref struct_def) => { - try!(self.head("")); - let generics = ast_util::empty_generics(); - try!(self.print_struct(&**struct_def, &generics, v.node.name, v.span)); - } - } + try!(self.head("")); + let generics = ast_util::empty_generics(); + try!(self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)); match v.node.disr_expr { Some(ref d) => { try!(space(&mut self.s)); @@ -3103,6 +3104,7 @@ mod tests { use ast_util; use codemap; use parse::token; + use ptr::P; #[test] fn test_fun_to_string() { @@ -3129,8 +3131,7 @@ mod tests { name: ident, attrs: Vec::new(), // making this up as I go.... ? - kind: ast::TupleVariantKind(Vec::new()), - id: 0, + data: P(ast::VariantData::Unit(ast::DUMMY_NODE_ID)), disr_expr: None, }); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 091580b9bd837..b7d202804c5a4 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -80,17 +80,18 @@ pub trait Visitor<'v> : Sized { fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } - fn visit_struct_def(&mut self, s: &'v StructDef, _: Ident, _: &'v Generics, _: NodeId) { + fn visit_variant_data(&mut self, s: &'v VariantData, _: Ident, + _: &'v Generics, _: NodeId, _: Span) { walk_struct_def(self, s) } fn visit_struct_field(&mut self, s: &'v StructField) { walk_struct_field(self, s) } fn visit_enum_def(&mut self, enum_definition: &'v EnumDef, - generics: &'v Generics) { - walk_enum_def(self, enum_definition, generics) + generics: &'v Generics, item_id: NodeId) { + walk_enum_def(self, enum_definition, generics, item_id) + } + fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) { + walk_variant(self, v, g, item_id) } - - fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics) { walk_variant(self, v, g) } - fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { walk_lifetime(self, lifetime) } @@ -271,7 +272,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { } ItemEnum(ref enum_definition, ref type_parameters) => { visitor.visit_generics(type_parameters); - visitor.visit_enum_def(enum_definition, type_parameters) + visitor.visit_enum_def(enum_definition, type_parameters, item.id) } ItemDefaultImpl(_, ref trait_ref) => { visitor.visit_trait_ref(trait_ref) @@ -288,10 +289,8 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { } ItemStruct(ref struct_definition, ref generics) => { visitor.visit_generics(generics); - visitor.visit_struct_def(struct_definition, - item.ident, - generics, - item.id) + visitor.visit_variant_data(struct_definition, item.ident, + generics, item.id, item.span); } ItemTrait(_, ref generics, ref bounds, ref methods) => { visitor.visit_generics(generics); @@ -305,30 +304,20 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, enum_definition: &'v EnumDef, - generics: &'v Generics) { + generics: &'v Generics, + item_id: NodeId) { for variant in &enum_definition.variants { - visitor.visit_variant(variant, generics); + visitor.visit_variant(variant, generics, item_id); } } pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant, - generics: &'v Generics) { + generics: &'v Generics, + item_id: NodeId) { visitor.visit_ident(variant.span, variant.node.name); - - match variant.node.kind { - TupleVariantKind(ref variant_arguments) => { - for variant_argument in variant_arguments { - visitor.visit_ty(&variant_argument.ty) - } - } - StructVariantKind(ref struct_definition) => { - visitor.visit_struct_def(struct_definition, - variant.node.name, - generics, - variant.node.id) - } - } + visitor.visit_variant_data(&variant.node.data, variant.node.name, + generics, item_id, variant.span); walk_list!(visitor, visit_expr, &variant.node.disr_expr); walk_list!(visitor, visit_attribute, &variant.node.attrs); } @@ -614,8 +603,8 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt } pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, - struct_definition: &'v StructDef) { - walk_list!(visitor, visit_struct_field, &struct_definition.fields); + struct_definition: &'v VariantData) { + walk_list!(visitor, visit_struct_field, struct_definition.fields()); } pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, diff --git a/src/test/compile-fail/deriving-primitive.rs b/src/test/compile-fail/deriving-primitive.rs index 6e9b120aa69b5..e8e37d8804986 100644 --- a/src/test/compile-fail/deriving-primitive.rs +++ b/src/test/compile-fail/deriving-primitive.rs @@ -23,12 +23,12 @@ struct B(isize); #[derive(FromPrimitive)] enum C { Foo(isize), Bar(usize) } -//~^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments -//~^^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments +//~^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants +//~^^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants #[derive(FromPrimitive)] enum D { Baz { x: isize } } -//~^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants -//~^^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants +//~^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants +//~^^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants pub fn main() {} diff --git a/src/test/compile-fail/empty-struct-braces-expr.rs b/src/test/compile-fail/empty-struct-braces-expr.rs new file mode 100644 index 0000000000000..67167086b9c4a --- /dev/null +++ b/src/test/compile-fail/empty-struct-braces-expr.rs @@ -0,0 +1,26 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Can't use empty braced struct as constant or constructor function + +#![feature(braced_empty_structs)] + +struct Empty1 {} + +enum E { + Empty2 {} +} + +fn main() { + let e1 = Empty1; //~ ERROR `Empty1` is the name of a struct or struct variant + let e1 = Empty1(); //~ ERROR `Empty1` is the name of a struct or struct variant + let e2 = E::Empty2; //~ ERROR `E::Empty2` is the name of a struct or struct variant + let e2 = E::Empty2(); //~ ERROR `E::Empty2` is the name of a struct or struct variant +} diff --git a/src/test/compile-fail/empty-struct-with-braces-3.rs b/src/test/compile-fail/empty-struct-braces-gate-1.rs similarity index 68% rename from src/test/compile-fail/empty-struct-with-braces-3.rs rename to src/test/compile-fail/empty-struct-braces-gate-1.rs index e6f20ba345ad3..a131b46e1c19b 100644 --- a/src/test/compile-fail/empty-struct-with-braces-3.rs +++ b/src/test/compile-fail/empty-struct-braces-gate-1.rs @@ -9,13 +9,15 @@ // except according to those terms. // Feature gate test for empty struct with braces +// Can't define an empty braced struct -struct Empty {} //~ ERROR empty structs with braces are unstable +struct Empty1 {} //~ ERROR empty structs and enum variants with braces are unstable +struct Empty2; -fn main() { - let e = Empty {}; //~ ERROR empty structs with braces are unstable +enum E { + Empty4 {}, //~ ERROR empty structs and enum variants with braces are unstable + Empty5, +} - match e { - Empty {} => {} //~ ERROR empty structs with braces are unstable - } +fn main() { } diff --git a/src/test/compile-fail/empty-struct-braces-gate-2.rs b/src/test/compile-fail/empty-struct-braces-gate-2.rs new file mode 100644 index 0000000000000..c1b73bdc96a8f --- /dev/null +++ b/src/test/compile-fail/empty-struct-braces-gate-2.rs @@ -0,0 +1,49 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Feature gate test for empty struct with braces +// Can't use braced expressions and patterns with structs defined without braces + +struct Empty2; + +enum E { + Empty5, +} + +fn main() { + let e2: Empty2 = Empty2 {}; //~ ERROR empty structs and enum variants with braces are unstable + let e2: Empty2 = Empty2; + // Issue #28692 + // let e5: E = E::Empty5 {}; // ERROR empty structs and enum variants with braces are unstable + let e5: E = E::Empty5; + + match e2 { + Empty2 {} => {} //~ ERROR empty structs and enum variants with braces are unstable + } + match e2 { + Empty2 => {} + } + match e2 { + Empty2 { .. } => {} //~ ERROR empty structs and enum variants with braces are unstable + } + // Issue #28692 + // match e5 { + // E::Empty5 {} => {} // ERROR empty structs and enum variants with braces are unstable + // } + match e5 { + E::Empty5 => {} + } + // Issue #28692 + // match e5 { + // E::Empty5 { .. } => {} // ERROR empty structs and enum variants with braces are unstable + // } + + let e22 = Empty2 { ..e2 }; //~ ERROR empty structs and enum variants with braces are unstable +} diff --git a/src/test/compile-fail/empty-struct-with-braces-2.rs b/src/test/compile-fail/empty-struct-braces-pat-1.rs similarity index 60% rename from src/test/compile-fail/empty-struct-with-braces-2.rs rename to src/test/compile-fail/empty-struct-braces-pat-1.rs index 0e72e7dc44185..e095f69ed7da6 100644 --- a/src/test/compile-fail/empty-struct-with-braces-2.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-1.rs @@ -8,18 +8,26 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Empty struct defined with braces shouldn't add names into value namespace +// Can't use empty braced struct as constant pattern -#![feature(braced_empty_structs)] #![deny(warnings)] +#![feature(braced_empty_structs)] -struct Empty {} +struct Empty1 {} + +enum E { + Empty2 {} +} fn main() { - let e = Empty {}; + let e1 = Empty1 {}; + let e2 = E::Empty2 {}; - match e { - Empty => () //~ ERROR unused variable: `Empty` - //~^ ERROR variable `Empty` should have a snake case name such as `empty` + // Issue #28692 + // match e1 { + // Empty1 => () // ERROR incorrect error + // } + match e2 { + E::Empty2 => () //~ ERROR `E::Empty2` does not name a non-struct variant or a tuple struct } } diff --git a/src/test/compile-fail/empty-struct-braces-pat-2.rs b/src/test/compile-fail/empty-struct-braces-pat-2.rs new file mode 100644 index 0000000000000..0e7152ec89a81 --- /dev/null +++ b/src/test/compile-fail/empty-struct-braces-pat-2.rs @@ -0,0 +1,39 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Can't use empty braced struct as enum pattern + +#![feature(braced_empty_structs)] + +struct Empty1 {} + +enum E { + Empty2 {} +} + +fn main() { + let e1 = Empty1 {}; + let e2 = E::Empty2 {}; + + // Rejected by parser as yet + // match e1 { + // Empty1() => () // ERROR unresolved enum variant, struct or const `Empty1` + // } + match e1 { + Empty1(..) => () //~ ERROR unresolved enum variant, struct or const `Empty1` + } + // Issue #28692 + // match e2 { + // E::Empty2() => () // ERROR unresolved enum variant, struct or const `Empty2` + // } + // match e2 { + // E::Empty2(..) => () // ERROR unresolved enum variant, struct or const `Empty2` + // } +} diff --git a/src/test/compile-fail/empty-struct-with-braces-1.rs b/src/test/compile-fail/empty-struct-unit-expr.rs similarity index 70% rename from src/test/compile-fail/empty-struct-with-braces-1.rs rename to src/test/compile-fail/empty-struct-unit-expr.rs index ad412259faa29..199065665b9f6 100644 --- a/src/test/compile-fail/empty-struct-with-braces-1.rs +++ b/src/test/compile-fail/empty-struct-unit-expr.rs @@ -8,12 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Empty struct defined with braces shouldn't add names into value namespace +// Can't use unit struct as constructor function #![feature(braced_empty_structs)] -struct Empty {} +struct Empty1; + +enum E { + Empty2 +} fn main() { - let e = Empty; //~ ERROR `Empty` is the name of a struct or struct variant + let e1 = Empty1(); //~ ERROR expected function, found `Empty1` + let e2 = E::Empty2(); //~ ERROR expected function, found `E` } diff --git a/src/test/compile-fail/empty-struct-unit-pat.rs b/src/test/compile-fail/empty-struct-unit-pat.rs new file mode 100644 index 0000000000000..966a2780f9f8c --- /dev/null +++ b/src/test/compile-fail/empty-struct-unit-pat.rs @@ -0,0 +1,40 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Can't use unit struct as enum pattern + +#![feature(braced_empty_structs)] + +FIXME //~ ERROR expected item, found `FIXME` + +struct Empty1; + +enum E { + Empty2 +} + +fn main() { + let e1 = Empty1; + let e2 = E::Empty2; + + // Issue #28692 + // match e1 { + // Empty1() => () // ERROR variable `Empty1` should have a snake case name + // } + // match e1 { + // Empty1(..) => () // ERROR variable `Empty1` should have a snake case name + // } + // match e2 { + // E::Empty2() => () // ERROR variable `Empty2` should have a snake case name + // } + // match e2 { + // E::Empty2(..) => () // ERROR variable `Empty2` should have a snake case name + // } +} diff --git a/src/test/parse-fail/struct-variant-no-fields.rs b/src/test/compile-fail/issue-16819.rs similarity index 67% rename from src/test/parse-fail/struct-variant-no-fields.rs rename to src/test/compile-fail/issue-16819.rs index 68cf661e21805..065b29d29aca5 100644 --- a/src/test/parse-fail/struct-variant-no-fields.rs +++ b/src/test/compile-fail/issue-16819.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,8 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +struct TS ( //~ ERROR empty tuple structs and enum variants are not allowed + #[cfg(untrue)] + int, +); -enum Foo { - Bar {} //~ ERROR unit-like struct variant should be written without braces, as `Bar,` +fn main() { + let s = S; } diff --git a/src/test/compile-fail/issue-27831.rs b/src/test/compile-fail/issue-27831.rs index 533387c576008..3cdb370f0e94c 100644 --- a/src/test/compile-fail/issue-27831.rs +++ b/src/test/compile-fail/issue-27831.rs @@ -22,8 +22,8 @@ fn main() { let Foo { .. } = x; //~ ERROR `Foo` does not name a struct let x = Bar; - Bar { ..x }; - let Bar { .. } = x; + Bar { ..x }; //~ ERROR empty structs and enum variants with braces are unstable + let Bar { .. } = x; //~ ERROR empty structs and enum variants with braces are unstable match Enum::Bar { Enum::Bar { .. } //~ ERROR `Enum::Bar` does not name a struct diff --git a/src/test/parse-fail/struct-no-fields-enumlike.rs b/src/test/compile-fail/struct-no-fields-enumlike.rs similarity index 80% rename from src/test/parse-fail/struct-no-fields-enumlike.rs rename to src/test/compile-fail/struct-no-fields-enumlike.rs index 19a395806d6cf..6bdbae1e4b9d9 100644 --- a/src/test/parse-fail/struct-no-fields-enumlike.rs +++ b/src/test/compile-fail/struct-no-fields-enumlike.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only - -struct Foo(); //~ ERROR unit-like struct definition should be written as `struct Foo;` +struct Foo(); //~ ERROR empty tuple structs and enum variants are not allowed fn main() {} diff --git a/src/test/run-pass/empty-struct-with-braces.rs b/src/test/run-pass/empty-struct-braces.rs similarity index 55% rename from src/test/run-pass/empty-struct-with-braces.rs rename to src/test/run-pass/empty-struct-braces.rs index dc806acb980dd..f2fbf2dd337e7 100644 --- a/src/test/run-pass/empty-struct-with-braces.rs +++ b/src/test/run-pass/empty-struct-braces.rs @@ -18,39 +18,71 @@ struct Empty2; struct Empty3 {} const Empty3: Empty3 = Empty3 {}; +enum E { + Empty4 {}, + Empty5, +} + fn main() { let e1: Empty1 = Empty1 {}; let e2: Empty2 = Empty2 {}; let e2: Empty2 = Empty2; let e3: Empty3 = Empty3 {}; let e3: Empty3 = Empty3; + let e4: E = E::Empty4 {}; + // let e5: E = E::Empty5 {}; // Issue #28692 + let e5: E = E::Empty5; match e1 { - Empty1 {} => () - } - match e2 { - Empty2 {} => () + Empty1 {} => {} } match e2 { - Empty2 => () + Empty2 {} => {} } match e3 { - Empty3 {} => () + Empty3 {} => {} } - match e3 { - Empty3 => () + match e4 { + E::Empty4 {} => {} + _ => {} } + // Issue #28692 + // match e5 { + // E::Empty5 {} => {} + // _ => {} + // } + match e1 { - Empty1 { .. } => () + Empty1 { .. } => {} } match e2 { - Empty2 { .. } => () + Empty2 { .. } => {} } match e3 { - Empty3 { .. } => () + Empty3 { .. } => {} + } + match e4 { + E::Empty4 { .. } => {} + _ => {} + } + // Issue #28692 + // match e5 { + // E::Empty5 { .. } => {} + // _ => {} + // } + + match e2 { + Empty2 => {} + } + match e3 { + Empty3 => {} + } + match e5 { + E::Empty5 => {} + _ => {} } - let e11 = Empty1 { ..e1 }; - let e22 = Empty2 { ..e2 }; - let e33 = Empty3 { ..e3 }; + let e11: Empty1 = Empty1 { ..e1 }; + let e22: Empty2 = Empty2 { ..e2 }; + let e33: Empty3 = Empty3 { ..e3 }; }