about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2015-10-02 03:53:28 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2015-10-13 15:19:17 +0300
commit495566ee61174066014b928fffd182834c1eb214 (patch)
tree6af573a725d3b5916cccc8d3122163166fc40f64
parent2314ab29c26c9364c7f8e26b55ce091998489f58 (diff)
downloadrust-495566ee61174066014b928fffd182834c1eb214.tar.gz
rust-495566ee61174066014b928fffd182834c1eb214.zip
Decouple structure kinds from NodeIds
-rw-r--r--src/librustc/front/map/collector.rs4
-rw-r--r--src/librustc/front/map/mod.rs4
-rw-r--r--src/librustc/metadata/encoder.rs13
-rw-r--r--src/librustc/middle/dead.rs4
-rw-r--r--src/librustc/middle/stability.rs6
-rw-r--r--src/librustc_front/fold.rs5
-rw-r--r--src/librustc_front/hir.rs19
-rw-r--r--src/librustc_front/lowering.rs7
-rw-r--r--src/librustc_front/print/pprust.rs4
-rw-r--r--src/librustc_front/util.rs8
-rw-r--r--src/librustc_privacy/lib.rs10
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs12
-rw-r--r--src/librustc_trans/save/dump_csv.rs9
-rw-r--r--src/librustc_trans/trans/base.rs8
-rw-r--r--src/librustc_trans/trans/callee.rs2
-rw-r--r--src/librustc_trans/trans/inline.rs12
-rw-r--r--src/librustc_trans/trans/monomorphize.rs6
-rw-r--r--src/librustc_typeck/collect.rs4
-rw-r--r--src/librustdoc/clean/mod.rs19
-rw-r--r--src/librustdoc/doctree.rs2
-rw-r--r--src/libsyntax/ast.rs19
-rw-r--r--src/libsyntax/ast_util.rs8
-rw-r--r--src/libsyntax/config.rs5
-rw-r--r--src/libsyntax/ext/build.rs8
-rw-r--r--src/libsyntax/ext/deriving/primitive.rs2
-rw-r--r--src/libsyntax/feature_gate.rs2
-rw-r--r--src/libsyntax/fold.rs5
-rw-r--r--src/libsyntax/parse/parser.rs29
-rw-r--r--src/libsyntax/print/pprust.rs8
29 files changed, 113 insertions, 131 deletions
diff --git a/src/librustc/front/map/collector.rs b/src/librustc/front/map/collector.rs
index 3edeaaccbde..51ba799c5d1 100644
--- a/src/librustc/front/map/collector.rs
+++ b/src/librustc/front/map/collector.rs
@@ -150,8 +150,8 @@ 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.kind != VariantKind::Dict {
+                    self.insert_def(struct_def.id,
                                     NodeStructCtor(&**struct_def),
                                     DefPathData::StructCtor);
                 }
diff --git a/src/librustc/front/map/mod.rs b/src/librustc/front/map/mod.rs
index 96e103aa4f4..b183f12a092 100644
--- a/src/librustc/front/map/mod.rs
+++ b/src/librustc/front/map/mod.rs
@@ -480,8 +480,8 @@ impl<'ast> Map<'ast> {
                 }
             }
             Some(NodeVariant(variant)) => {
-                match variant.node.def.ctor_id {
-                    None => &variant.node.def,
+                match variant.node.def.kind {
+                    VariantKind::Dict => &variant.node.def,
                     _ => panic!("struct ID bound to enum variant that isn't struct-like"),
                 }
             }
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 9d2b1548f29..7c08d7618d7 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -381,12 +381,8 @@ fn each_auxiliary_node_id<F>(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.kind == hir::VariantKind::Tuple {
+                continue_ = callback(struct_def.id);
             }
         }
         _ => {}
@@ -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.kind != hir::VariantKind::Dict {
+            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/dead.rs b/src/librustc/middle/dead.rs
index 6e31b733254..f977992e735 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -426,7 +426,9 @@ fn find_live(tcx: &ty::ctxt,
 
 fn get_struct_ctor_id(item: &hir::Item) -> Option<ast::NodeId> {
     match item.node {
-        hir::ItemStruct(ref struct_def, _) => struct_def.ctor_id,
+        hir::ItemStruct(ref struct_def, _) if struct_def.kind != hir::VariantKind::Dict => {
+            Some(struct_def.id)
+        }
         _ => None
     }
 }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index c2235591cee..8476adf6838 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.kind != hir::VariantKind::Dict {
+                self.annotate(sd.id, true, &i.attrs, i.span, |_| {}, true)
+            }
         }
     }
 
diff --git a/src/librustc_front/fold.rs b/src/librustc_front/fold.rs
index 876ec804e27..32518081794 100644
--- a/src/librustc_front/fold.rs
+++ b/src/librustc_front/fold.rs
@@ -699,10 +699,11 @@ pub fn noop_fold_where_predicate<T: Folder>(pred: WherePredicate, fld: &mut T) -
 }
 
 pub fn noop_fold_struct_def<T: Folder>(struct_def: P<StructDef>, fld: &mut T) -> P<StructDef> {
-    struct_def.map(|StructDef { fields, ctor_id }| {
+    struct_def.map(|StructDef { fields, id, kind }| {
         StructDef {
             fields: fields.move_map(|f| fld.fold_struct_field(f)),
-            ctor_id: ctor_id.map(|cid| fld.new_id(cid)),
+            id: fld.new_id(id),
+            kind: kind,
         }
     })
 }
diff --git a/src/librustc_front/hir.rs b/src/librustc_front/hir.rs
index 8f5f95b1104..b9322416541 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::*;
@@ -1022,14 +1021,6 @@ pub struct VariantArg {
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum VariantKind {
-    /// Tuple variant, e.g. `Foo(A, B)`
-    TupleVariantKind(Vec<VariantArg>),
-    /// Struct variant, e.g. `Foo {x: A, y: B}`
-    StructVariantKind(P<StructDef>),
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct EnumDef {
     pub variants: Vec<P<Variant>>,
 }
@@ -1176,13 +1167,21 @@ impl StructFieldKind {
     }
 }
 
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum VariantKind {
+    Dict,
+    Tuple,
+    Unit,
+}
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct StructDef {
     /// Fields, not including ctor
     pub fields: Vec<StructField>,
     /// ID of the constructor. This is only used for tuple- or enum-like
     /// structs.
-    pub ctor_id: Option<NodeId>,
+    pub id: NodeId,
+    pub kind: VariantKind,
 }
 
 /*
diff --git a/src/librustc_front/lowering.rs b/src/librustc_front/lowering.rs
index 0350c9ff114..1539613070f 100644
--- a/src/librustc_front/lowering.rs
+++ b/src/librustc_front/lowering.rs
@@ -502,7 +502,12 @@ pub fn lower_where_predicate(_lctx: &LoweringContext,
 pub fn lower_struct_def(_lctx: &LoweringContext, sd: &StructDef) -> P<hir::StructDef> {
     P(hir::StructDef {
         fields: sd.fields.iter().map(|f| lower_struct_field(_lctx, f)).collect(),
-        ctor_id: sd.ctor_id,
+        id: sd.id,
+        kind: match sd.kind {
+            VariantKind::Dict => hir::VariantKind::Dict,
+            VariantKind::Tuple => hir::VariantKind::Tuple,
+            VariantKind::Unit => hir::VariantKind::Unit,
+        }
     })
 }
 
diff --git a/src/librustc_front/print/pprust.rs b/src/librustc_front/print/pprust.rs
index ee6be06428e..8d4422011f0 100644
--- a/src/librustc_front/print/pprust.rs
+++ b/src/librustc_front/print/pprust.rs
@@ -896,8 +896,8 @@ impl<'a> State<'a> {
                         -> 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.kind != hir::VariantKind::Dict {
+            if struct_def.kind == hir::VariantKind::Tuple {
                 try!(self.popen());
                 try!(self.commasep(Inconsistent,
                                    &struct_def.fields,
diff --git a/src/librustc_front/util.rs b/src/librustc_front/util.rs
index c6b2a2acc2b..05a548a8c66 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,
@@ -298,7 +292,7 @@ impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O>
                         _: &hir::Generics,
                         id: NodeId) {
         self.operation.visit_id(id);
-        struct_def.ctor_id.map(|ctor_id| self.operation.visit_id(ctor_id));
+        self.operation.visit_id(struct_def.id);
         visit::walk_struct_def(self, struct_def);
     }
 
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index ca5411f9c79..4e4609fb083 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -132,9 +132,8 @@ impl<'v> Visitor<'v> for ParentVisitor {
                         _: &'v hir::Generics, n: ast::NodeId) {
         // 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.kind != hir::VariantKind::Dict {
+            self.parents.insert(s.id, n);
         }
 
         // While we have the id of the struct definition, go ahead and parent
@@ -320,9 +319,8 @@ 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.kind != hir::VariantKind::Dict {
+                    self.exported_items.insert(def.id);
                 }
                 // fields can be public or private, so lets check
                 for field in &def.fields {
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index a3f40efa483..6b4b3334166 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -492,9 +492,9 @@ 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) = match struct_def.kind {
+                    hir::VariantKind::Dict => (ForbidDuplicateTypesAndModules, None),
+                    _                     => (ForbidDuplicateTypesAndValues, Some(struct_def.id)),
                 };
 
                 let name_bindings = self.add_child(name, parent, forbid, sp);
@@ -587,14 +587,14 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
                                        item_id: DefId,
                                        parent: &Rc<Module>) {
         let name = variant.node.name;
-        let is_exported = match variant.node.def.ctor_id {
-            Some(_) => false,
-            None => {
+        let is_exported = match variant.node.def.kind {
+            hir::VariantKind::Dict => {
                 // 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
             }
+            _ => false,
         };
 
         let child = self.add_child(name, parent,
diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs
index 983f04643c3..fb1c494ffd4 100644
--- a/src/librustc_trans/save/dump_csv.rs
+++ b/src/librustc_trans/save/dump_csv.rs
@@ -462,16 +462,12 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
                       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);
@@ -505,11 +501,10 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
             qualname.push_str(name);
             let val = self.span.snippet(variant.span);
 
-            let ctor_id = variant.node.def.ctor_id.unwrap_or(ast::DUMMY_NODE_ID);
             self.fmt.struct_variant_str(variant.span,
                                         self.span.span_for_first_ident(variant.span),
                                         variant.node.id,
-                                        ctor_id,
+                                        variant.node.def.id,
                                         &qualname,
                                         &enum_data.qualname,
                                         &val,
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index 6baa3c5e0db..06cb8de0542 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -2428,7 +2428,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
 
         hir_map::NodeVariant(ref v) => {
             let llfn;
-            let fields = if v.node.def.ctor_id.is_none() {
+            let fields = if v.node.def.kind == hir::VariantKind::Dict {
                 ccx.sess().bug("struct variant kind unexpected in get_item_val")
             } else {
                 &v.node.def.fields
@@ -2454,12 +2454,12 @@ 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 => {
+            let ctor_id = match struct_def.kind {
+                hir::VariantKind::Dict => {
                     ccx.sess().bug("attempt to register a constructor of \
                                     a non-tuple-like struct")
                 }
-                Some(ctor_id) => ctor_id,
+                _ => 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 debd4d232b8..fdcc2623ef1 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -418,7 +418,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
 
         match map_node {
             hir_map::NodeVariant(v) => {
-                v.node.def.ctor_id.is_some() && !v.node.def.fields.is_empty()
+                v.node.def.kind == hir::VariantKind::Tuple
             }
             hir_map::NodeStructCtor(_) => true,
             _ => false
diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs
index b8f75df8c11..9cb4b271742 100644
--- a/src/librustc_trans/trans/inline.rs
+++ b/src/librustc_trans/trans/inline.rs
@@ -115,12 +115,12 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId)
                     }
                 }
                 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;
+                    match struct_def.kind {
+                        hir::VariantKind::Dict => ccx.sess().bug("instantiate_inline: called on a \
+                                                                 non-tuple struct"),
+                        _ => {
+                            ccx.external().borrow_mut().insert(fn_id, Some(struct_def.id));
+                            my_id = struct_def.id;
                         }
                     }
                 }
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index 33f798be85e..49009378bb9 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.kind == hir::VariantKind::Dict {
+                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/collect.rs b/src/librustc_typeck/collect.rs
index 4217b0d481f..879432d89c8 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1014,8 +1014,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
                 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.kind != hir::VariantKind::Dict {
+                convert_variant_ctor(tcx, struct_def.id, variant, scheme, predicates);
             }
         },
         hir::ItemTy(_, ref generics) => {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0d2d1118883..a5ed0ea6c09 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1917,25 +1917,10 @@ pub enum VariantKind {
     StructVariant(VariantStruct),
 }
 
-impl Clean<VariantKind> 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::StructDef, cx: &DocContext) -> VariantKind {
-    if struct_def.ctor_id.is_none() {
+    if struct_def.kind == hir::VariantKind::Dict {
         StructVariant(struct_def.clean(cx))
-    } else if struct_def.fields.is_empty() {
+    } else if struct_def.kind == hir::VariantKind::Unit {
         CLikeVariant
     } else {
         TupleVariant(struct_def.fields.iter().map(|x| x.node.ty.clean(cx)).collect())
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 4296c79be50..c65c31e6c3c 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -235,7 +235,7 @@ pub struct Import {
 }
 
 pub fn struct_type_from_def(sd: &hir::StructDef) -> StructType {
-    if sd.ctor_id.is_some() {
+    if sd.kind != hir::VariantKind::Dict {
         // We are in a tuple-struct
         match sd.fields.len() {
             0 => Unit,
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 57d9837e1aa..66c0d858e3c 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::*;
@@ -1578,14 +1577,6 @@ pub struct VariantArg {
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum VariantKind {
-    /// Tuple variant, e.g. `Foo(A, B)`
-    TupleVariantKind(Vec<VariantArg>),
-    /// Struct variant, e.g. `Foo {x: A, y: B}`
-    StructVariantKind(P<StructDef>),
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct EnumDef {
     pub variants: Vec<P<Variant>>,
 }
@@ -1756,13 +1747,21 @@ impl StructFieldKind {
     }
 }
 
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum VariantKind {
+    Dict,
+    Tuple,
+    Unit,
+}
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct StructDef {
     /// Fields, not including ctor
     pub fields: Vec<StructField>,
     /// ID of the constructor. This is only used for tuple- or enum-like
     /// structs.
-    pub ctor_id: Option<NodeId>,
+    pub id: NodeId,
+    pub kind: VariantKind,
 }
 
 /*
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 905a83b050e..87f05f7f41e 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -463,7 +463,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
                         _: &ast::Generics,
                         id: NodeId) {
         self.operation.visit_id(id);
-        struct_def.ctor_id.map(|ctor_id| self.operation.visit_id(ctor_id));
+        self.operation.visit_id(struct_def.id);
         visit::walk_struct_def(self, struct_def);
     }
 
@@ -529,12 +529,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<ast::Pat>) -> bool {
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 0accf34202e..d47072d477e 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -168,12 +168,13 @@ fn fold_item_underscore<F>(cx: &mut Context<F>, item: ast::Item_) -> ast::Item_
 fn fold_struct<F>(cx: &mut Context<F>, def: P<ast::StructDef>) -> P<ast::StructDef> where
     F: FnMut(&[ast::Attribute]) -> bool
 {
-    def.map(|ast::StructDef { fields, ctor_id }| {
+    def.map(|ast::StructDef { fields, id, kind }| {
         ast::StructDef {
             fields: fields.into_iter().filter(|m| {
                 (cx.in_cfg)(&m.node.attrs)
             }).collect(),
-            ctor_id: ctor_id,
+            id: id,
+            kind: kind,
         }
     })
 }
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index d448eb63204..132ab6e67fe 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -993,7 +993,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     }
 
     fn variant(&self, span: Span, name: Ident, tys: Vec<P<ast::Ty>> ) -> ast::Variant {
-        let fields = tys.into_iter().map(|ty| {
+        let fields: Vec<_> = tys.into_iter().map(|ty| {
             Spanned { span: ty.span, node: ast::StructField_ {
                 ty: ty,
                 kind: ast::UnnamedField(ast::Inherited),
@@ -1002,11 +1002,15 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
             }}
         }).collect();
 
+        let kind = if fields.is_empty() { ast::VariantKind::Unit } else { ast::VariantKind::Tuple };
+
         respan(span,
                ast::Variant_ {
                    name: name,
                    attrs: Vec::new(),
-                   def: P(ast::StructDef { fields: fields, ctor_id: Some(ast::DUMMY_NODE_ID) }),
+                   def: P(ast::StructDef { fields: fields,
+                                           id: ast::DUMMY_NODE_ID,
+                                           kind: kind }),
                    id: ast::DUMMY_NODE_ID,
                    disr_expr: None,
                })
diff --git a/src/libsyntax/ext/deriving/primitive.rs b/src/libsyntax/ext/deriving/primitive.rs
index 2fdaa9b7550..7b64e5522a4 100644
--- a/src/libsyntax/ext/deriving/primitive.rs
+++ b/src/libsyntax/ext/deriving/primitive.rs
@@ -95,7 +95,7 @@ fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure
 
             for variant in &enum_def.variants {
                 let def = &variant.node.def;
-                if def.ctor_id.is_none() || !def.fields.is_empty() {
+                if def.kind != ast::VariantKind::Unit {
                     cx.span_err(trait_span, "`FromPrimitive` cannot be derived \
                                              for enums with non-unit variants");
                     return cx.expr_fail(trait_span,
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 1d545268e57..0b3af659a7b 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -828,7 +828,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
                         }
                     }
                 }
-                if def.fields.is_empty() && def.ctor_id.is_none() {
+                if def.fields.is_empty() && def.kind == ast::VariantKind::Dict {
                     self.gate_feature("braced_empty_structs", i.span,
                                       "empty structs with braces are unstable");
                 }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 88781c3664a..8156ef20faf 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -820,9 +820,10 @@ pub fn noop_fold_where_predicate<T: Folder>(
 }
 
 pub fn noop_fold_struct_def<T: Folder>(struct_def: P<StructDef>, fld: &mut T) -> P<StructDef> {
-    struct_def.map(|StructDef { fields, ctor_id }| StructDef {
+    struct_def.map(|StructDef { fields, id, kind }| StructDef {
         fields: fields.move_map(|f| fld.fold_struct_field(f)),
-        ctor_id: ctor_id.map(|cid| fld.new_id(cid)),
+        id: fld.new_id(id),
+        kind: kind,
     })
 }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 0748c898a82..1b446fb9902 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -45,7 +45,7 @@ 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::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField, VariantKind};
 use ast::{BiSub, StrStyle};
 use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue};
 use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef};
@@ -4640,26 +4640,26 @@ 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 (fields, kind) = 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<T> where T: Copy;` style decl.
-                (Vec::new(), Some(ast::DUMMY_NODE_ID))
+                (Vec::new(), VariantKind::Unit)
             } else {
                 // If we see: `struct Foo<T> where T: Copy { ... }`
-                (try!(self.parse_record_struct_body()), None)
+                (try!(self.parse_record_struct_body()), VariantKind::Dict)
             }
         // No `where` so: `struct Foo<T>;`
         } else if try!(self.eat(&token::Semi) ){
-            (Vec::new(), Some(ast::DUMMY_NODE_ID))
+            (Vec::new(), VariantKind::Unit)
         // Record-style struct definition
         } else if self.token == token::OpenDelim(token::Brace) {
             let fields = try!(self.parse_record_struct_body());
-            (fields, None)
+            (fields, VariantKind::Dict)
         // 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))
+            (fields, VariantKind::Tuple)
         } else {
             let token_str = self.this_token_to_string();
             return Err(self.fatal(&format!("expected `where`, `{{`, `(`, or `;` after struct \
@@ -4669,7 +4669,8 @@ impl<'a> Parser<'a> {
         Ok((class_name,
          ItemStruct(P(ast::StructDef {
              fields: fields,
-             ctor_id: ctor_id,
+             id: ast::DUMMY_NODE_ID,
+             kind: kind,
          }), generics),
          None))
     }
@@ -5118,7 +5119,8 @@ impl<'a> Parser<'a> {
 
         Ok(P(StructDef {
             fields: fields,
-            ctor_id: None,
+            id: ast::DUMMY_NODE_ID,
+            kind: VariantKind::Dict,
         }))
     }
 
@@ -5156,15 +5158,18 @@ impl<'a> Parser<'a> {
                     }});
                 }
                 struct_def = P(StructDef { fields: fields,
-                                           ctor_id: Some(ast::DUMMY_NODE_ID) });
+                                           id: ast::DUMMY_NODE_ID,
+                                           kind: ast::VariantKind::Tuple });
             } 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);
                 struct_def = P(StructDef { fields: Vec::new(),
-                                           ctor_id: Some(ast::DUMMY_NODE_ID) });
+                                           id: ast::DUMMY_NODE_ID,
+                                           kind: ast::VariantKind::Unit });
             } else {
                 struct_def = P(StructDef { fields: Vec::new(),
-                                           ctor_id: Some(ast::DUMMY_NODE_ID) });
+                                           id: ast::DUMMY_NODE_ID,
+                                           kind: ast::VariantKind::Unit });
             }
 
             let vr = ast::Variant_ {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 678b8e04897..2d6829c5e75 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1392,8 +1392,8 @@ impl<'a> State<'a> {
                         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.kind != ast::VariantKind::Dict {
+            if struct_def.kind == ast::VariantKind::Tuple {
                 try!(self.popen());
                 try!(self.commasep(
                     Inconsistent, &struct_def.fields,
@@ -3119,7 +3119,9 @@ mod tests {
             name: ident,
             attrs: Vec::new(),
             // making this up as I go.... ?
-            def: P(ast::StructDef { fields: Vec::new(), ctor_id: Some(ast::DUMMY_NODE_ID) }),
+            def: P(ast::StructDef { fields: Vec::new(),
+                                    id: ast::DUMMY_NODE_ID,
+                                    kind: ast::VariantKind::Unit }),
             id: 0,
             disr_expr: None,
         });