From 5c3d1e5d76fdc6d9f40ab13a6a342e1f7ceb4f17 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 21 Mar 2019 23:38:50 +0100 Subject: [PATCH] Separate variant id and variant constructor id. This commit makes two changes - separating the `NodeId` that identifies an enum variant from the `NodeId` that identifies the variant's constructor; and no longer creating a `NodeId` for `Struct`-style enum variants and structs. Separation of the variant id and variant constructor id will allow the rest of RFC 2008 to be implemented by lowering the visibility of the variant's constructor without lowering the visbility of the variant itself. No longer creating a `NodeId` for `Struct`-style enum variants and structs mostly simplifies logic as previously this `NodeId` wasn't used. There were various cases where the `NodeId` wouldn't be used unless there was an unit or tuple struct or enum variant but not all uses of this `NodeId` had that condition, by removing this `NodeId`, this must be explicitly dealt with. This change mostly applied cleanly, but there were one or two cases in name resolution and one case in type check where the existing logic required a id for `Struct`-style enum variants and structs. --- src/librustc/hir/def.rs | 30 ++- src/librustc/hir/intravisit.rs | 5 +- src/librustc/hir/lowering.rs | 20 +- src/librustc/hir/map/collector.rs | 16 +- src/librustc/hir/map/def_collector.rs | 18 +- src/librustc/hir/map/definitions.rs | 8 +- src/librustc/hir/map/mod.rs | 35 +-- src/librustc/hir/mod.rs | 60 +++-- src/librustc/hir/pat_util.rs | 6 +- src/librustc/lint/context.rs | 6 +- src/librustc/lint/mod.rs | 2 +- src/librustc/middle/dead.rs | 39 ++- src/librustc/middle/expr_use_visitor.rs | 14 +- src/librustc/middle/mem_categorization.rs | 23 +- src/librustc/middle/reachable.rs | 2 +- src/librustc/middle/stability.rs | 17 +- src/librustc/mir/mod.rs | 3 +- src/librustc/traits/error_reporting.rs | 24 +- src/librustc/ty/instance.rs | 3 +- src/librustc/ty/mod.rs | 248 +++++++++++++----- src/librustc/ty/print/pretty.rs | 19 +- src/librustc_borrowck/borrowck/mod.rs | 3 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_metadata/cstore_impl.rs | 8 + src/librustc_metadata/decoder.rs | 68 ++--- src/librustc_metadata/encoder.rs | 102 +++++-- src/librustc_metadata/schema.rs | 9 +- src/librustc_mir/build/mod.rs | 5 +- src/librustc_mir/hair/cx/expr.rs | 26 +- src/librustc_mir/hair/pattern/_match.rs | 18 +- src/librustc_mir/hair/pattern/mod.rs | 14 +- src/librustc_mir/shim.rs | 2 +- src/librustc_mir/util/pretty.rs | 8 +- src/librustc_passes/rvalue_promotion.rs | 7 +- src/librustc_privacy/lib.rs | 17 +- src/librustc_resolve/build_reduced_graph.rs | 65 ++++- src/librustc_resolve/error_reporting.rs | 4 +- src/librustc_resolve/lib.rs | 21 +- src/librustc_resolve/resolve_imports.rs | 5 +- src/librustc_save_analysis/dump_visitor.rs | 13 +- src/librustc_save_analysis/lib.rs | 24 +- src/librustc_save_analysis/sig.rs | 7 +- src/librustc_typeck/astconv.rs | 18 +- src/librustc_typeck/check/_match.rs | 21 +- src/librustc_typeck/check/demand.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 11 +- src/librustc_typeck/check/mod.rs | 20 +- src/librustc_typeck/collect.rs | 137 +++++----- src/librustc_typeck/variance/constraints.rs | 4 +- src/librustc_typeck/variance/mod.rs | 2 +- src/librustc_typeck/variance/terms.rs | 4 +- src/librustdoc/clean/inline.rs | 4 +- src/librustdoc/clean/mod.rs | 13 +- src/librustdoc/doctree.rs | 1 + .../passes/collect_intra_doc_links.rs | 4 +- src/librustdoc/visit_ast.rs | 9 +- src/libsyntax/ast.rs | 33 ++- src/libsyntax/config.rs | 5 +- src/libsyntax/ext/build.rs | 1 + src/libsyntax/mut_visit.rs | 7 +- src/libsyntax/parse/parser.rs | 11 +- src/libsyntax/print/pprust.rs | 1 + src/test/mir-opt/unusual-item-types.rs | 4 +- 63 files changed, 818 insertions(+), 520 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index b45fc3ffd82..87a6065bb75 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -37,9 +37,13 @@ pub enum NonMacroAttrKind { pub enum Def { // Type namespace Mod(DefId), - Struct(DefId), // `DefId` refers to `NodeId` of the struct itself + /// `DefId` refers to `NodeId` of the struct. `Def::VariantCtor` represents the constructor of + /// a struct. + Struct(DefId), Union(DefId), Enum(DefId), + /// `DefId` refers to the `NodeId` of the variant. `Def::VariantCtor` represents the + /// constructor of an enum variant. Variant(DefId), Trait(DefId), /// `existential type Foo: Bar;` @@ -61,8 +65,8 @@ pub enum Def { Const(DefId), ConstParam(DefId), Static(DefId, bool /* is_mutbl */), - StructCtor(DefId, CtorKind), // `DefId` refers to `NodeId` of the struct's constructor - VariantCtor(DefId, CtorKind), // `DefId` refers to the enum variant + /// `DefId` refers to `NodeId` of the struct or enum variant's constructor. + Ctor(hir::CtorOf, DefId, CtorKind), SelfCtor(DefId /* impl */), // `DefId` refers to the impl Method(DefId), AssociatedConst(DefId), @@ -265,10 +269,9 @@ impl Def { pub fn opt_def_id(&self) -> Option { match *self { Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) | - Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | + Def::Variant(id) | Def::Ctor(_, id, ..) | Def::Enum(id) | Def::TyAlias(id) | Def::TraitAlias(id) | Def::AssociatedTy(id) | Def::TyParam(id) | Def::ConstParam(id) | Def::Struct(id) | - Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | Def::Macro(id, ..) | Def::Existential(id) | Def::AssociatedExistential(id) | Def::ForeignTy(id) => { @@ -303,20 +306,21 @@ impl Def { Def::Fn(..) => "function", Def::Mod(..) => "module", Def::Static(..) => "static", - Def::Variant(..) => "variant", - Def::VariantCtor(.., CtorKind::Fn) => "tuple variant", - Def::VariantCtor(.., CtorKind::Const) => "unit variant", - Def::VariantCtor(.., CtorKind::Fictive) => "struct variant", Def::Enum(..) => "enum", + Def::Variant(..) => "variant", + Def::Ctor(hir::CtorOf::Variant, _, CtorKind::Fn) => "tuple variant", + Def::Ctor(hir::CtorOf::Variant, _, CtorKind::Const) => "unit variant", + Def::Ctor(hir::CtorOf::Variant, _, CtorKind::Fictive) => "struct variant", + Def::Struct(..) => "struct", + Def::Ctor(hir::CtorOf::Struct, _, CtorKind::Fn) => "tuple struct", + Def::Ctor(hir::CtorOf::Struct, _, CtorKind::Const) => "unit struct", + Def::Ctor(hir::CtorOf::Struct, _, CtorKind::Fictive) => + bug!("impossible struct constructor"), Def::Existential(..) => "existential type", Def::TyAlias(..) => "type alias", Def::TraitAlias(..) => "trait alias", Def::AssociatedTy(..) => "associated type", Def::AssociatedExistential(..) => "associated existential type", - Def::Struct(..) => "struct", - Def::StructCtor(.., CtorKind::Fn) => "tuple struct", - Def::StructCtor(.., CtorKind::Const) => "unit struct", - Def::StructCtor(.., CtorKind::Fictive) => bug!("impossible struct constructor"), Def::SelfCtor(..) => "self constructor", Def::Union(..) => "union", Def::Trait(..) => "trait", diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 977830315e2..bce528189ad 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -559,6 +559,7 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics, parent_item_id: HirId) { visitor.visit_ident(variant.node.ident); + visitor.visit_id(variant.node.id); visitor.visit_variant_data(&variant.node.data, variant.node.ident.name, generics, @@ -923,7 +924,9 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &' pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) { - visitor.visit_id(struct_definition.hir_id()); + if let Some(ctor_hir_id) = struct_definition.ctor_hir_id() { + visitor.visit_id(ctor_hir_id); + } walk_list!(visitor, visit_struct_field, struct_definition.fields()); } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2251e67233c..8db90035c8e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1615,9 +1615,11 @@ impl<'a> LoweringContext<'a> { } fn lower_variant(&mut self, v: &Variant) -> hir::Variant { + let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(v.node.id); Spanned { node: hir::VariantKind { ident: v.node.ident, + id: hir_id, attrs: self.lower_attrs(&v.node.attrs), data: self.lower_variant_data(&v.node.data), disr_expr: v.node.disr_expr.as_ref().map(|e| self.lower_anon_const(e)), @@ -2669,19 +2671,10 @@ impl<'a> LoweringContext<'a> { fn lower_variant_data(&mut self, vdata: &VariantData) -> hir::VariantData { match *vdata { - VariantData::Struct(ref fields, id, recovered) => { - let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id); - - hir::VariantData::Struct( - fields - .iter() - .enumerate() - .map(|f| self.lower_struct_field(f)) - .collect(), - hir_id, - recovered, - ) - }, + VariantData::Struct(ref fields, recovered) => hir::VariantData::Struct( + fields.iter().enumerate().map(|f| self.lower_struct_field(f)).collect(), + recovered, + ), VariantData::Tuple(ref fields, id) => { let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id); @@ -2696,7 +2689,6 @@ impl<'a> LoweringContext<'a> { }, VariantData::Unit(id) => { let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(id); - hir::VariantData::Unit(hir_id) }, } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index e88f9e60702..e7cd8f11353 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -360,9 +360,11 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { this.insert(i.span, i.hir_id, Node::Item(i)); this.with_parent(i.hir_id, |this| { if let ItemKind::Struct(ref struct_def, _) = i.node { - // If this is a tuple-like struct, register the constructor. - if !struct_def.is_struct() { - this.insert(i.span, struct_def.hir_id(), Node::StructCtor(struct_def)); + // If this is a tuple or unit-like struct, register the constructor. + if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { + this.insert(i.span, + ctor_hir_id, + Node::Ctor(hir::CtorOf::Struct, struct_def)); } } intravisit::walk_item(this, i); @@ -515,8 +517,12 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_variant(&mut self, v: &'hir Variant, g: &'hir Generics, item_id: HirId) { - self.insert(v.span, v.node.data.hir_id(), Node::Variant(v)); - self.with_parent(v.node.data.hir_id(), |this| { + self.insert(v.span, v.node.id, Node::Variant(v)); + self.with_parent(v.node.id, |this| { + // Register the constructor of this variant. + if let Some(ctor_hir_id) = v.node.data.ctor_hir_id() { + this.insert(v.span, ctor_hir_id, Node::Ctor(hir::CtorOf::Variant, &v.node.data)); + } intravisit::walk_variant(this, v, g, item_id); }); } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 12760f8b982..2c92d907201 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -158,9 +158,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { self.with_parent(def, |this| { match i.node { ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => { - // If this is a tuple-like struct, register the constructor. - if !struct_def.is_struct() { - this.create_def(struct_def.id(), + // If this is a unit or tuple-like struct, register the constructor. + if let Some(ctor_hir_id) = struct_def.ctor_id() { + this.create_def(ctor_hir_id, DefPathData::StructCtor, REGULAR_SPACE, i.span); @@ -193,11 +193,19 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { } fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) { - let def = self.create_def(v.node.data.id(), + let def = self.create_def(v.node.id, DefPathData::EnumVariant(v.node.ident.as_interned_str()), REGULAR_SPACE, v.span); - self.with_parent(def, |this| visit::walk_variant(this, v, g, item_id)); + self.with_parent(def, |this| { + if let Some(ctor_hir_id) = v.node.data.ctor_id() { + this.create_def(ctor_hir_id, + DefPathData::VariantCtor, + REGULAR_SPACE, + v.span); + } + visit::walk_variant(this, v, g, item_id) + }); } fn visit_variant_data(&mut self, data: &'a VariantData, _: Ident, diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index dca4ce4aef8..dc23b55c1fc 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -366,8 +366,10 @@ pub enum DefPathData { EnumVariant(InternedString), /// A struct field Field(InternedString), - /// Implicit ctor for a tuple-like struct + /// Implicit ctor for a unit or tuple-like struct StructCtor, + /// Implicit ctor for a unit or tuple-like enum variant + VariantCtor, /// A constant expression (see {ast,hir}::AnonConst). AnonConst, /// An `impl Trait` type node @@ -653,6 +655,7 @@ impl DefPathData { Misc | ClosureExpr | StructCtor | + VariantCtor | AnonConst | ImplTrait => None } @@ -683,7 +686,8 @@ impl DefPathData { Impl => "{{impl}}", Misc => "{{misc}}", ClosureExpr => "{{closure}}", - StructCtor => "{{constructor}}", + StructCtor => "{{struct constructor}}", + VariantCtor => "{{variant constructor}}", AnonConst => "{{constant}}", ImplTrait => "{{opaque}}", }; diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 3e8da882eed..ce0246dec71 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -366,12 +366,15 @@ impl<'hir> Map<'hir> { } } Node::Variant(variant) => { - let def_id = self.local_def_id_from_hir_id(variant.node.data.hir_id()); + let def_id = self.local_def_id_from_hir_id(variant.node.id); Some(Def::Variant(def_id)) } - Node::StructCtor(variant) => { - let def_id = self.local_def_id_from_hir_id(variant.hir_id()); - Some(Def::StructCtor(def_id, def::CtorKind::from_hir(variant))) + Node::Ctor(ctor_of, variant_data) => { + variant_data.ctor_hir_id() + .map(|hir_id| self.local_def_id_from_hir_id(hir_id)) + .map(|def_id| Def::Ctor( + ctor_of, def_id, def::CtorKind::from_hir(variant_data), + )) } Node::AnonConst(_) | Node::Field(_) | @@ -516,8 +519,7 @@ impl<'hir> Map<'hir> { Node::AnonConst(_) => { BodyOwnerKind::Const } - Node::Variant(&Spanned { node: VariantKind { data: VariantData::Tuple(..), .. }, .. }) | - Node::StructCtor(..) | + Node::Ctor(..) | Node::Item(&Item { node: ItemKind::Fn(..), .. }) | Node::TraitItem(&TraitItem { node: TraitItemKind::Method(..), .. }) | Node::ImplItem(&ImplItem { node: ImplItemKind::Method(..), .. }) => { @@ -948,8 +950,8 @@ impl<'hir> Map<'hir> { _ => bug!("struct ID bound to non-struct {}", self.hir_to_string(id)) } } - Some(Node::StructCtor(data)) => data, Some(Node::Variant(variant)) => &variant.node.data, + Some(Node::Ctor(_, data)) => data, _ => bug!("expected struct or variant, found {}", self.hir_to_string(id)) } } @@ -993,7 +995,7 @@ impl<'hir> Map<'hir> { Node::Lifetime(lt) => lt.name.ident().name, Node::GenericParam(param) => param.name.ident().name, Node::Binding(&Pat { node: PatKind::Binding(_, _, l, _), .. }) => l.name, - Node::StructCtor(_) => self.name(self.get_parent(id)), + Node::Ctor(..) => self.name(self.get_parent(id)), _ => bug!("no name for {}", self.node_to_string(id)) } } @@ -1019,9 +1021,9 @@ impl<'hir> Map<'hir> { Some(Node::Expr(ref e)) => Some(&*e.attrs), Some(Node::Stmt(ref s)) => Some(s.node.attrs()), Some(Node::GenericParam(param)) => Some(¶m.attrs[..]), - // unit/tuple structs take the attributes straight from - // the struct definition. - Some(Node::StructCtor(_)) => return self.attrs(self.get_parent(id)), + // Unit/tuple structs/variants take the attributes straight from + // the struct/variant definition. + Some(Node::Ctor(..)) => return self.attrs(self.get_parent(id)), _ => None }; attrs.unwrap_or(&[]) @@ -1068,7 +1070,10 @@ impl<'hir> Map<'hir> { Some(Node::Binding(pat)) => pat.span, Some(Node::Pat(pat)) => pat.span, Some(Node::Block(block)) => block.span, - Some(Node::StructCtor(_)) => self.expect_item(self.get_parent(id)).span, + Some(Node::Ctor(CtorOf::Struct, _)) => + self.expect_item(self.get_parent(id)).span, + Some(Node::Ctor(CtorOf::Variant, _)) => + self.expect_variant(self.node_to_hir_id(self.get_parent_node(id))).span, Some(Node::Lifetime(lifetime)) => lifetime.span, Some(Node::GenericParam(param)) => param.span, Some(Node::Visibility(&Spanned { @@ -1324,7 +1329,7 @@ impl<'a> print::State<'a> { // these cases do not carry enough information in the // hir_map to reconstruct their full structure for pretty // printing. - Node::StructCtor(_) => bug!("cannot print isolated StructCtor"), + Node::Ctor(..) => bug!("cannot print isolated Ctor"), Node::Local(a) => self.print_local_decl(&a), Node::MacroDef(_) => bug!("cannot print MacroDef"), Node::Crate => bug!("cannot print Crate"), @@ -1443,8 +1448,8 @@ fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String { Some(Node::Local(_)) => { format!("local {}{}", map.node_to_pretty_string(id), id_str) } - Some(Node::StructCtor(_)) => { - format!("struct_ctor {}{}", path_str(), id_str) + Some(Node::Ctor(..)) => { + format!("ctor {}{}", path_str(), id_str) } Some(Node::Lifetime(_)) => { format!("lifetime {}{}", map.node_to_pretty_string(id), id_str) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 823de08874e..6ce7c347c99 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2049,9 +2049,14 @@ pub struct EnumDef { #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] pub struct VariantKind { + /// Name of the variant. #[stable_hasher(project(name))] pub ident: Ident, + /// Attributes of the variant. pub attrs: HirVec, + /// Id of the variant (not the constructor, see `VariantData::ctor_hir_id()`). + pub id: HirId, + /// Fields and constructor id of the variant. pub data: VariantData, /// Explicit discriminant (e.g., `Foo = 1`). pub disr_expr: Option, @@ -2063,7 +2068,7 @@ pub type Variant = Spanned; pub enum UseKind { /// One import, e.g., `use foo::bar` or `use foo::bar as baz`. /// Also produced for each element of a list `use`, e.g. - // `use foo::{a, b}` lowers to `use foo::a; use foo::b;`. + /// `use foo::{a, b}` lowers to `use foo::a; use foo::b;`. Single, /// Glob import, e.g., `use foo::*`. @@ -2170,38 +2175,41 @@ impl StructField { } } -/// 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 present). Structures don't have an analogue of "Id of -/// the variant itself" from enum variants. -/// Id of the whole struct lives in `Item`. +/// Fields and constructor ids of enum variants and structs #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] pub enum VariantData { - Struct(HirVec, HirId, /* recovered */ bool), + /// Struct variant. + /// + /// e.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`. + Struct(HirVec, /* recovered */ bool), + /// Tuple variant. + /// + /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`. Tuple(HirVec, HirId), + /// Unit variant. + /// + /// E.g., `Bar = ..` as in `enum Foo { Bar = .. }`. Unit(HirId), } impl VariantData { + /// Return the fields of this variant. pub fn fields(&self) -> &[StructField] { match *self { VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, ..) => fields, _ => &[], } } - pub fn hir_id(&self) -> HirId { + + /// Return the `HirId` of this variant's constructor, if it has one. + pub fn ctor_hir_id(&self) -> Option { match *self { - VariantData::Struct(_, hir_id, _) - | VariantData::Tuple(_, hir_id) - | VariantData::Unit(hir_id) => hir_id, + VariantData::Struct(_, _) => None, + VariantData::Tuple(_, hir_id) | VariantData::Unit(hir_id) => Some(hir_id), } } + + /// Does this `VariantData` represent a `Struct`-struct/variant? pub fn is_struct(&self) -> bool { if let VariantData::Struct(..) = *self { true @@ -2209,6 +2217,8 @@ impl VariantData { false } } + + /// Does this `VariantData` represent a tuple struct/variant? pub fn is_tuple(&self) -> bool { if let VariantData::Tuple(..) = *self { true @@ -2216,6 +2226,8 @@ impl VariantData { false } } + + /// Does this `VariantData` represent a unit struct/variant? pub fn is_unit(&self) -> bool { if let VariantData::Unit(..) = *self { true @@ -2574,6 +2586,15 @@ impl CodegenFnAttrs { } } +/// Encodes if a `Node::Ctor` is the constructor of an enum variant or a struct. +#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, HashStable)] +pub enum CtorOf { + /// This `Node::Ctor` is a synthesized constructor of a tuple or unit struct. + Struct, + /// This `Node::Ctor` is a synthesized constructor of a tuple or unit variant. + Variant, +} + #[derive(Copy, Clone, Debug)] pub enum Node<'hir> { Item(&'hir Item), @@ -2594,8 +2615,9 @@ pub enum Node<'hir> { Local(&'hir Local), MacroDef(&'hir MacroDef), - /// StructCtor represents a tuple struct. - StructCtor(&'hir VariantData), + /// `Ctor` refers to the constructor of an enum variant or struct. Only tuple or unit variants + /// with synthesized constructors. + Ctor(CtorOf, &'hir VariantData), Lifetime(&'hir Lifetime), GenericParam(&'hir GenericParam), diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index 18a3d6708db..b859a0f389e 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -55,7 +55,7 @@ impl hir::Pat { PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) | PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => { match path.def { - Def::Variant(..) | Def::VariantCtor(..) => true, + Def::Variant(..) => true, _ => false } } @@ -125,8 +125,8 @@ impl hir::Pat { PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) | PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => { match path.def { - Def::Variant(id) | - Def::VariantCtor(id, ..) => variants.push(id), + Def::Variant(id) => variants.push(id), + Def::Ctor(hir::CtorOf::Variant, id, _) => variants.push(id), _ => () } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 9761ee31353..94f1d9c2710 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -917,7 +917,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { v: &'tcx hir::Variant, g: &'tcx hir::Generics, item_id: hir::HirId) { - self.with_lint_attrs(v.node.data.hir_id(), &v.node.attrs, |cx| { + self.with_lint_attrs(v.node.id, &v.node.attrs, |cx| { run_lints!(cx, check_variant, v, g); hir_visit::walk_variant(cx, v, g, item_id); run_lints!(cx, check_variant_post, v, g); @@ -1073,7 +1073,9 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> item_id: ast::NodeId, _: Span) { run_early_pass!(self, check_struct_def, s, ident, g, item_id); - self.check_id(s.id()); + if let Some(ctor_hir_id) = s.ctor_id() { + self.check_id(ctor_hir_id); + } ast_visit::walk_struct_def(self, s); run_early_pass!(self, check_struct_def_post, s, ident, g, item_id); } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 03ed62f2a0d..e96fe3d3b77 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -803,7 +803,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> { v: &'tcx hir::Variant, g: &'tcx hir::Generics, item_id: hir::HirId) { - self.with_lint_attrs(v.node.data.hir_id(), &v.node.attrs, |builder| { + self.with_lint_attrs(v.node.id, &v.node.attrs, |builder| { intravisit::walk_variant(builder, v, g, item_id); }) } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index ccec4bd1432..786d339e876 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -54,8 +54,7 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn check_def_id(&mut self, def_id: DefId) { if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) { - if should_explore(self.tcx, hir_id) || - self.struct_constructors.contains_key(&hir_id) { + if should_explore(self.tcx, hir_id) || self.struct_constructors.contains_key(&hir_id) { self.worklist.push(hir_id); } self.live_symbols.insert(hir_id); @@ -77,10 +76,17 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { _ if self.in_pat => (), Def::PrimTy(..) | Def::SelfTy(..) | Def::SelfCtor(..) | Def::Local(..) | Def::Upvar(..) => {} - Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => { - if let Some(enum_id) = self.tcx.parent(variant_id) { - self.check_def_id(enum_id); + Def::Ctor(hir::CtorOf::Variant, ctor_def_id, ..) => { + let variant_id = self.tcx.parent(ctor_def_id).unwrap(); + let enum_id = self.tcx.parent(variant_id).unwrap(); + self.check_def_id(enum_id); + if !self.ignore_variant_stack.contains(&ctor_def_id) { + self.check_def_id(variant_id); } + } + Def::Variant(variant_id) => { + let enum_id = self.tcx.parent(variant_id).unwrap(); + self.check_def_id(enum_id); if !self.ignore_variant_stack.contains(&variant_id) { self.check_def_id(variant_id); } @@ -360,9 +366,16 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { self.worklist.push(item.hir_id); } match item.node { - hir::ItemKind::Enum(ref enum_def, _) if allow_dead_code => { - self.worklist.extend(enum_def.variants.iter() - .map(|variant| variant.node.data.hir_id())); + hir::ItemKind::Enum(ref enum_def, _) => { + if allow_dead_code { + self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id)); + } + + for variant in &enum_def.variants { + if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() { + self.struct_constructors.insert(ctor_hir_id, variant.node.id); + } + } } hir::ItemKind::Trait(.., ref trait_item_refs) => { for trait_item_ref in trait_item_refs { @@ -392,7 +405,9 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } hir::ItemKind::Struct(ref variant_data, _) => { - self.struct_constructors.insert(variant_data.hir_id(), item.hir_id); + if let Some(ctor_hir_id) = variant_data.ctor_hir_id() { + self.struct_constructors.insert(ctor_hir_id, item.hir_id); + } } _ => () } @@ -484,9 +499,9 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { } fn should_warn_about_variant(&mut self, variant: &hir::VariantKind) -> bool { - !self.symbol_is_live(variant.data.hir_id()) + !self.symbol_is_live(variant.id) && !has_allow_dead_code_or_lang_attr(self.tcx, - variant.data.hir_id(), + variant.id, &variant.attrs) } @@ -583,7 +598,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { g: &'tcx hir::Generics, id: hir::HirId) { if self.should_warn_about_variant(&variant.node) { - self.warn_dead_code(variant.node.data.hir_id(), variant.span, variant.node.ident.name, + self.warn_dead_code(variant.node.id, variant.span, variant.node.ident.name, "variant", "constructed"); } else { intravisit::walk_variant(self, variant, g, id); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 8ada67efaaf..a60a145dd21 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -14,7 +14,7 @@ use crate::hir::def_id::DefId; use crate::infer::InferCtxt; use crate::middle::mem_categorization as mc; use crate::middle::region; -use crate::ty::{self, TyCtxt, adjustment}; +use crate::ty::{self, DefIdTree, TyCtxt, adjustment}; use crate::hir::{self, PatKind}; use rustc_data_structures::sync::Lrc; @@ -902,14 +902,20 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { }; let def = mc.tables.qpath_def(qpath, pat.hir_id); match def { - Def::Variant(variant_did) | - Def::VariantCtor(variant_did, ..) => { + Def::Ctor(hir::CtorOf::Variant, variant_ctor_did, ..) => { + let variant_did = mc.tcx.parent(variant_ctor_did).unwrap(); + let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did); + + debug!("variantctor downcast_cmt={:?} pat={:?}", downcast_cmt, pat); + delegate.matched_pat(pat, &downcast_cmt, match_mode); + } + Def::Variant(variant_did) => { let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did); debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat); delegate.matched_pat(pat, &downcast_cmt, match_mode); } - Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) | + Def::Struct(..) | Def::Ctor(..) | Def::Union(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => { debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat); delegate.matched_pat(pat, &cmt_pat, match_mode); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index b36d2a57cb3..aa582d48bb6 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -215,7 +215,7 @@ impl<'tcx> cmt_<'tcx> { }; let variant_def = match self.cat { Categorization::Downcast(_, variant_did) => { - adt_def.variant_with_id(variant_did) + adt_def.variant_with_variant_id(variant_did) } _ => { assert_eq!(adt_def.variants.len(), 1); @@ -704,7 +704,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { hir_id, expr_ty, def); match def { - Def::StructCtor(..) | Def::VariantCtor(..) | Def::Const(..) | Def::ConstParam(..) | + Def::Ctor(..) | Def::Const(..) | Def::ConstParam(..) | Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) => { Ok(self.cat_rvalue_node(hir_id, span, expr_ty)) } @@ -1274,12 +1274,14 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { debug!("access to unresolvable pattern {:?}", pat); return Err(()) } - Def::VariantCtor(def_id, CtorKind::Fn) => { - let enum_def = self.tcx.parent(def_id).unwrap(); - (self.cat_downcast_if_needed(pat, cmt, def_id), - self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len()) + Def::Ctor(hir::CtorOf::Variant, variant_ctor_did, CtorKind::Fn) => { + let variant_did = self.tcx.parent(variant_ctor_did).unwrap(); + let enum_did = self.tcx.parent(variant_did).unwrap(); + (self.cat_downcast_if_needed(pat, cmt, variant_did), + self.tcx.adt_def(enum_did) + .variant_with_ctor_id(variant_ctor_did).fields.len()) } - Def::StructCtor(_, CtorKind::Fn) | Def::SelfCtor(..) => { + Def::Ctor(hir::CtorOf::Struct, _, CtorKind::Fn) | Def::SelfCtor(..) => { let ty = self.pat_ty_unadjusted(&pat)?; match ty.sty { ty::Adt(adt_def, _) => { @@ -1314,8 +1316,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { debug!("access to unresolvable pattern {:?}", pat); return Err(()) } - Def::Variant(variant_did) | - Def::VariantCtor(variant_did, ..) => { + Def::Ctor(hir::CtorOf::Variant, variant_ctor_did, _) => { + let variant_did = self.tcx.parent(variant_ctor_did).unwrap(); + self.cat_downcast_if_needed(pat, cmt, variant_did) + } + Def::Variant(variant_did) => { self.cat_downcast_if_needed(pat, cmt, variant_did) } _ => cmt, diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index a7294dbf07c..b57f96f2d46 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -311,7 +311,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Nothing to recurse on for these Node::ForeignItem(_) | Node::Variant(_) | - Node::StructCtor(_) | + Node::Ctor(..) | Node::Field(_) | Node::Ty(_) | Node::MacroDef(_) => {} diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 72c90b25860..772c6ab4745 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -258,8 +258,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { self.in_trait_impl = true; } hir::ItemKind::Struct(ref sd, _) => { - if !sd.is_struct() { - self.annotate(sd.hir_id(), &i.attrs, i.span, AnnotationKind::Required, |_| {}) + if let Some(ctor_hir_id) = sd.ctor_hir_id() { + self.annotate(ctor_hir_id, &i.attrs, i.span, AnnotationKind::Required, |_| {}) } } _ => {} @@ -289,8 +289,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: HirId) { - self.annotate(var.node.data.hir_id(), &var.node.attrs, var.span, AnnotationKind::Required, - |v| { intravisit::walk_variant(v, var, g, item_id) }) + self.annotate(var.node.id, &var.node.attrs, var.span, AnnotationKind::Required, + |v| { + if let Some(ctor_hir_id) = var.node.data.ctor_hir_id() { + v.annotate(ctor_hir_id, &var.node.attrs, var.span, AnnotationKind::Required, + |_| {}); + } + + intravisit::walk_variant(v, var, g, item_id) + }) } fn visit_struct_field(&mut self, s: &'tcx StructField) { @@ -364,7 +371,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> { } fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: HirId) { - self.check_missing_stability(var.node.data.hir_id(), var.span, "variant"); + self.check_missing_stability(var.node.id, var.span, "variant"); intravisit::walk_variant(self, var, g, item_id); } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9f2027e7d05..b54b92b798e 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2405,12 +2405,13 @@ impl<'tcx> Debug for Rvalue<'tcx> { AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => { let variant_def = &adt_def.variants[variant]; + let did = variant_def.variant_did_or_parent_struct_did(); let f = &mut *fmt; ty::tls::with(|tcx| { let substs = tcx.lift(&substs).expect("could not lift for printing"); FmtPrinter::new(tcx, f, Namespace::ValueNS) - .print_def_path(variant_def.did, substs)?; + .print_def_path(did, substs)?; Ok(()) })?; diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index f5f2ec38bdf..ef232c06921 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1077,23 +1077,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { _ => ArgKind::empty() }).collect::>()) } - Node::Variant(&hir::Variant { - span, - node: hir::VariantKind { - data: hir::VariantData::Tuple(ref fields, ..), - .. - }, - .. - }) => { - (self.tcx.sess.source_map().def_span(span), - fields.iter().map(|field| - ArgKind::Arg(field.ident.to_string(), "_".to_string()) - ).collect::>()) - } - Node::StructCtor(ref variant_data) => { - (self.tcx.sess.source_map().def_span( - self.tcx.hir().span_by_hir_id(variant_data.hir_id())), - vec![ArgKind::empty(); variant_data.fields().len()]) + Node::Ctor(_, ref variant_data) => { + let span = variant_data.ctor_hir_id() + .map(|hir_id| self.tcx.hir().span_by_hir_id(hir_id)) + .unwrap_or(DUMMY_SP); + let span = self.tcx.sess.source_map().def_span(span); + + (span, vec![ArgKind::empty(); variant_data.fields().len()]) } _ => panic!("non-FnLike node found: {:?}", node), } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 995e85fc5f4..84ce826c6a5 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -150,8 +150,7 @@ impl<'tcx> InstanceDef<'tcx> { _ => return true }; match tcx.def_key(def_id).disambiguated_data.data { - DefPathData::StructCtor | - DefPathData::EnumVariant(..) | + DefPathData::StructCtor | DefPathData::VariantCtor | DefPathData::ClosureExpr => true, _ => false } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 91b84b68802..0de91af8460 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -8,7 +8,6 @@ use crate::hir::{map as hir_map, FreevarMap, GlobMap, TraitMap}; use crate::hir::{HirId, Node}; use crate::hir::def::{Def, CtorKind, ExportMap}; use crate::hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use crate::hir::map::DefPathData; use rustc_data_structures::svh::Svh; use rustc_macros::HashStable; use crate::ich::Fingerprint; @@ -1775,12 +1774,19 @@ bitflags! { #[derive(HashStable)] pub struct AdtFlags: u32 { const NO_ADT_FLAGS = 0; + /// Indicates whether the ADT is an enum. const IS_ENUM = 1 << 0; + /// Indicates whether the ADT is a union. const IS_UNION = 1 << 1; + /// Indicates whether the ADT is a struct. const IS_STRUCT = 1 << 2; + /// Indicates whether the ADT is a struct and has a constructor. const HAS_CTOR = 1 << 3; + /// Indicates whether the type is a `PhantomData`. const IS_PHANTOM_DATA = 1 << 4; + /// Indicates whether the type has a `#[fundamental]` attribute. const IS_FUNDAMENTAL = 1 << 5; + /// Indicates whether the type is a `Box`. const IS_BOX = 1 << 6; /// Indicates whether the type is an `Arc`. const IS_ARC = 1 << 7; @@ -1801,77 +1807,149 @@ bitflags! { } } +/// Definition of a variant -- a struct's fields or a enum variant. #[derive(Debug)] pub struct VariantDef { - /// The variant's `DefId`. If this is a tuple-like struct, - /// this is the `DefId` of the struct's ctor. - pub did: DefId, - pub ident: Ident, // struct's name if this is a struct + /// `DefId` that identifies this enum variant. If this `VariantDef` is part of a struct or + /// union then this is `None`. + variant_did: Option, + /// `DefId` that identifies this enum variant or struct's constructor. If this is a + /// `Struct`-variant then this is `None`. + ctor_did: Option, + /// Variant or struct name. + pub ident: Ident, + /// Discriminant of this variant. pub discr: VariantDiscr, + /// Fields of this variant. pub fields: Vec, + /// Type of constructor of variant. pub ctor_kind: CtorKind, + /// `DefId` of the parent `AdtDef` representing the struct or enum. This is required as there + /// is a valid scenario where this type represents a `Struct`-struct and both `ctor_did` and + /// `variant_did` would be `None` and we would still want a way to get back to the original + /// `AdtDef`. + parent_did: DefId, + /// Flags of the variant (e.g. is field list non-exhaustive)? flags: VariantFlags, + /// Recovered? pub recovered: bool, } impl<'a, 'gcx, 'tcx> VariantDef { /// Creates a new `VariantDef`. /// - /// - `did` is the `DefId` used for the variant. - /// This is the constructor `DefId` for tuple stucts, and the variant `DefId` for everything - /// else. - /// - `attribute_def_id` is the DefId that has the variant's attributes. - /// This is the struct `DefId` for structs, and the variant `DefId` for variants. + /// `variant_did` is the `DefId` that identifies the enum variant (if this `VariantDef` + /// represents an enum variant). /// - /// Note that we *could* use the constructor `DefId`, because the constructor attributes - /// redirect to the base attributes, but compiling a small crate requires - /// loading the `AdtDef`s for all the structs in the universe (e.g., coherence for any + /// `ctor_did` is the `DefId` that identifies the constructor of unit or + /// tuple-variants/structs. If this is a `struct`-variant then this should be `None`. + /// + /// `parent_did` is the `DefId` of the `AdtDef` representing the enum or struct that + /// owns this variant. It is used for checking if a struct has `#[non_exhaustive]` w/out having + /// to go through the redirect of checking the ctor's attributes - but compiling a small crate + /// requires loading the `AdtDef`s for all the structs in the universe (e.g., coherence for any /// built-in trait), and we do not want to load attributes twice. /// /// If someone speeds up attribute loading to not be a performance concern, they can /// remove this hack and use the constructor `DefId` everywhere. pub fn new( tcx: TyCtxt<'a, 'gcx, 'tcx>, - did: DefId, ident: Ident, + variant_did: Option, + ctor_did: Option, discr: VariantDiscr, fields: Vec, - adt_kind: AdtKind, ctor_kind: CtorKind, - attribute_def_id: DefId, + adt_kind: AdtKind, + parent_did: DefId, recovered: bool, ) -> Self { - debug!("VariantDef::new({:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?})", did, ident, discr, - fields, adt_kind, ctor_kind, attribute_def_id); + debug!( + "VariantDef::new(ident = {:?}, variant_did = {:?}, ctor_did = {:?}, discr = {:?}, + fields = {:?}, ctor_kind = {:?}, adt_kind = {:?}, parent_did = {:?})", + ident, variant_did, ctor_did, discr, fields, ctor_kind, adt_kind, parent_did, + ); + let mut flags = VariantFlags::NO_VARIANT_FLAGS; - if adt_kind == AdtKind::Struct && tcx.has_attr(attribute_def_id, "non_exhaustive") { - debug!("found non-exhaustive field list for {:?}", did); + if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, "non_exhaustive") { + debug!("found non-exhaustive field list for {:?}", parent_did); flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; } + VariantDef { - did, + variant_did, + ctor_did, ident, discr, fields, ctor_kind, flags, + parent_did, recovered, } } + /// Is this field list non-exhaustive? #[inline] pub fn is_field_list_non_exhaustive(&self) -> bool { self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE) } + + /// Returns `true` if this `VariantDef` represents a enum's variant. + #[inline] + pub fn is_enum_variant(&self) -> bool { + self.variant_did.is_some() + } + + /// Returns `true` if this `VariantDef` represents a struct. + #[inline] + pub fn is_struct(&self) -> bool { + !self.is_enum_variant() + } + + /// Returns the `DefId` of this variant if this `VariantDef` represents an enum's variant, or + /// returns the `DefId` of the parent struct. + #[inline] + pub fn variant_did_or_parent_struct_did(&self) -> DefId { + self.variant_did.unwrap_or(self.parent_did) + } + + /// Returns `true` if the variant is defined in the local crate. + #[inline] + pub fn is_local(&self) -> bool { + self.variant_did_or_parent_struct_did().krate == LOCAL_CRATE + } + + /// Returns the `DefId` of this variant if this `VariantDef` represents an enum's variant or + /// panics. + #[inline] + pub fn variant_did(&self) -> DefId { + self.variant_did.expect("enum variant without a variant id") + } + + /// Returns the `DefId` of this variant's constructor if this is a unit or + /// tuple-variant/struct. + #[inline] + pub fn ctor_did(&self) -> Option { + self.ctor_did + } + + /// Returns the `AdtDef` representing the struct or enum associated with this `VariantDef`. + #[inline] + pub fn adt_def(&self, tcx: TyCtxt<'a, 'tcx, 'gcx>) -> &'tcx AdtDef { + tcx.adt_def(self.parent_did) + } } impl_stable_hash_for!(struct VariantDef { - did, + variant_did, + ctor_did, ident -> (ident.name), discr, fields, ctor_kind, flags, + parent_did, recovered }); @@ -1898,12 +1976,15 @@ pub struct FieldDef { /// The definition of an abstract data type -- a struct or enum. /// -/// These are all interned (by `intern_adt_def`) into the `adt_defs` -/// table. +/// These are all interned (by `intern_adt_def`) into the `adt_defs` table. pub struct AdtDef { + /// `DefId` of the struct, enum or union item. pub did: DefId, + /// Variants of the ADT. If this is a struct or enum, then there will be a single variant. pub variants: IndexVec, + /// Flags of the ADT (e.g. is this a struct? is this non-exhaustive?) flags: AdtFlags, + /// Repr options provided by the user. pub repr: ReprOptions, } @@ -2102,11 +2183,14 @@ impl ReprOptions { } impl<'a, 'gcx, 'tcx> AdtDef { - fn new(tcx: TyCtxt<'_, '_, '_>, - did: DefId, - kind: AdtKind, - variants: IndexVec, - repr: ReprOptions) -> Self { + /// Creates a new `AdtDef`. + fn new( + tcx: TyCtxt<'_, '_, '_>, + did: DefId, + kind: AdtKind, + variants: IndexVec, + repr: ReprOptions + ) -> Self { debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr); let mut flags = AdtFlags::NO_ADT_FLAGS; @@ -2120,13 +2204,8 @@ impl<'a, 'gcx, 'tcx> AdtDef { AdtKind::Struct => AdtFlags::IS_STRUCT, }; - if let AdtKind::Struct = kind { - let variant_def = &variants[VariantIdx::new(0)]; - let def_key = tcx.def_key(variant_def.did); - match def_key.disambiguated_data.data { - DefPathData::StructCtor => flags |= AdtFlags::HAS_CTOR, - _ => (), - } + if kind == AdtKind::Struct && variants[VariantIdx::new(0)].ctor_did.is_some() { + flags |= AdtFlags::HAS_CTOR; } let attrs = tcx.get_attrs(did); @@ -2154,21 +2233,25 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + /// Returns `true` if this is a struct. #[inline] pub fn is_struct(&self) -> bool { self.flags.contains(AdtFlags::IS_STRUCT) } + /// Returns `true` if this is a union. #[inline] pub fn is_union(&self) -> bool { self.flags.contains(AdtFlags::IS_UNION) } + /// Returns `true` if this is a enum. #[inline] pub fn is_enum(&self) -> bool { self.flags.contains(AdtFlags::IS_ENUM) } + /// Returns `true` if the variant list of this ADT is `#[non_exhaustive]`. #[inline] pub fn is_variant_list_non_exhaustive(&self) -> bool { self.flags.contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE) @@ -2186,6 +2269,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + /// Returns a description of this abstract data type. pub fn descr(&self) -> &'static str { match self.adt_kind() { AdtKind::Struct => "struct", @@ -2194,6 +2278,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + /// Returns a description of a variant of this abstract data type. #[inline] pub fn variant_descr(&self) -> &'static str { match self.adt_kind() { @@ -2266,25 +2351,53 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.variants.iter().all(|v| v.fields.is_empty()) } - pub fn variant_with_id(&self, vid: DefId) -> &VariantDef { + pub fn variant_with_variant_id(&self, vid: DefId) -> &VariantDef { self.variants .iter() - .find(|v| v.did == vid) - .expect("variant_with_id: unknown variant") + .find(|v| v.variant_did.map(|did| did == vid).unwrap_or(false)) + .expect("variant_with_variant_id: unknown variant") } - pub fn variant_index_with_id(&self, vid: DefId) -> VariantIdx { + pub fn variant_with_ctor_id(&self, cid: DefId) -> &VariantDef { + self.variants + .iter() + .find(|v| v.ctor_did.map(|did| did == cid).unwrap_or(false)) + .expect("variant_with_ctor_id: unknown variant") + } + + pub fn variant_index_with_variant_id(&self, vid: DefId) -> VariantIdx { self.variants .iter_enumerated() - .find(|(_, v)| v.did == vid) - .expect("variant_index_with_id: unknown variant") + .find(|(_, v)| v.variant_did.map(|did| did == vid).unwrap_or(false)) + .expect("variant_index_with_variant_id: unknown variant") + .0 + } + + pub fn variant_index_with_ctor_id(&self, cid: DefId) -> VariantIdx { + self.variants + .iter_enumerated() + .find(|(_, v)| v.ctor_did.map(|did| did == cid).unwrap_or(false)) + .expect("variant_index_with_ctor_id: unknown variant") + .0 + } + + pub fn variant_index_with_ctor_or_variant_id(&self, id: DefId) -> VariantIdx { + self.variants + .iter_enumerated() + .find(|(_, v)| { + let ctor = v.ctor_did.map(|did| did == id); + let variant = v.variant_did.map(|did| did == id); + ctor.or(variant).unwrap_or(false) + }) + .expect("variant_index_with_ctor_or_variant_id: unknown variant") .0 } pub fn variant_of_def(&self, def: Def) -> &VariantDef { match def { - Def::Variant(vid) | Def::VariantCtor(vid, ..) => self.variant_with_id(vid), - Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) | + Def::Variant(vid) => self.variant_with_variant_id(vid), + Def::Ctor(hir::CtorOf::Variant, cid, ..) => self.variant_with_ctor_id(cid), + Def::Struct(..) | Def::Ctor(..) | Def::Union(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) | Def::SelfCtor(..) => self.non_enum_variant(), _ => bug!("unexpected def {:?} in variant_of_def", def) @@ -2820,7 +2933,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option { variant.fields.iter().position(|field| { - self.adjust_ident(ident, variant.did, hir::DUMMY_HIR_ID).0 == field.ident.modern() + let did = variant.variant_did.unwrap_or(variant.parent_did); + self.adjust_ident(ident, did, hir::DUMMY_HIR_ID).0 == field.ident.modern() }) } @@ -2895,16 +3009,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // or variant or their constructors, panics otherwise. pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef { match def { - Def::Variant(did) | Def::VariantCtor(did, ..) => { + Def::Variant(did) => { let enum_did = self.parent(did).unwrap(); - self.adt_def(enum_did).variant_with_id(did) + self.adt_def(enum_did).variant_with_variant_id(did) } Def::Struct(did) | Def::Union(did) => { self.adt_def(did).non_enum_variant() } - Def::StructCtor(ctor_did, ..) => { - let did = self.parent(ctor_did).expect("struct ctor has no parent"); - self.adt_def(did).non_enum_variant() + Def::Ctor(hir::CtorOf::Variant, variant_ctor_did, ..) => { + let variant_did = self.parent(variant_ctor_did).unwrap(); + let enum_did = self.parent(variant_did).unwrap(); + self.adt_def(enum_did).variant_with_ctor_id(variant_ctor_did) + } + Def::Ctor(hir::CtorOf::Struct, ctor_did, ..) => { + let struct_did = self.parent(ctor_did).expect("struct ctor has no parent"); + self.adt_def(struct_did).non_enum_variant() } _ => bug!("expect_variant_def used with unexpected def {:?}", def) } @@ -2912,16 +3031,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Given a `VariantDef`, returns the def-id of the `AdtDef` of which it is a part. pub fn adt_def_id_of_variant(self, variant_def: &'tcx VariantDef) -> DefId { - let def_key = self.def_key(variant_def.did); - match def_key.disambiguated_data.data { - // for enum variants and tuple structs, the def-id of the ADT itself - // is the *parent* of the variant - DefPathData::EnumVariant(..) | DefPathData::StructCtor => - DefId { krate: variant_def.did.krate, index: def_key.parent.unwrap() }, - - // otherwise, for structs and unions, they share a def-id - _ => variant_def.did, - } + variant_def.parent_did } pub fn item_name(self, id: DefId) -> InternedString { @@ -2929,16 +3039,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.original_crate_name(id.krate).as_interned_str() } else { let def_key = self.def_key(id); - // The name of a StructCtor is that of its struct parent. - if let hir_map::DefPathData::StructCtor = def_key.disambiguated_data.data { - self.item_name(DefId { - krate: id.krate, - index: def_key.parent.unwrap() - }) - } else { - def_key.disambiguated_data.data.get_opt_name().unwrap_or_else(|| { + match def_key.disambiguated_data.data { + // The name of a `StructCtor` or `VariantCtor` is that of its parent. + hir_map::DefPathData::StructCtor | hir_map::DefPathData::VariantCtor => + self.item_name(DefId { + krate: id.krate, + index: def_key.parent.unwrap() + }), + _ => def_key.disambiguated_data.data.get_opt_name().unwrap_or_else(|| { bug!("item_name: no name for {:?}", self.def_path(id)); - }) + }), } } } diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 7701a10d8ee..3d6a2cf9224 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -286,13 +286,17 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key); // For a UnitStruct or TupleStruct we want the name of its parent rather than . - if let DefPathData::StructCtor = cur_def_key.disambiguated_data.data { - let parent = DefId { - krate: def_id.krate, - index: cur_def_key.parent.expect("DefPathData::StructCtor missing a parent"), - }; + match cur_def_key.disambiguated_data.data { + DefPathData::StructCtor | DefPathData::VariantCtor => { + let parent = DefId { + krate: def_id.krate, + index: cur_def_key.parent + .expect("DefPathData::StructCtor/VariantData missing a parent"), + }; - cur_def_key = self.tcx().def_key(parent); + cur_def_key = self.tcx().def_key(parent); + }, + _ => {}, } let visible_parent = match visible_parent_map.get(&def_id).cloned() { @@ -860,6 +864,7 @@ impl TyCtxt<'_, '_, '_> { DefPathData::AnonConst | DefPathData::ConstParam(..) | DefPathData::ClosureExpr | + DefPathData::VariantCtor | DefPathData::StructCtor => Namespace::ValueNS, DefPathData::MacroDef(..) => Namespace::MacroNS, @@ -1024,7 +1029,7 @@ impl Printer<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> { // Skip `::{{constructor}}` on tuple/unit structs. match disambiguated_data.data { - DefPathData::StructCtor => return Ok(self), + DefPathData::StructCtor | DefPathData::VariantCtor => return Ok(self), _ => {} } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 4e1d360562d..7e38ce6377c 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -85,8 +85,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) let owner_id = tcx.hir().as_local_hir_id(owner_def_id).unwrap(); match tcx.hir().get_by_hir_id(owner_id) { - Node::StructCtor(_) | - Node::Variant(_) => { + Node::Ctor(_, _) => { // We get invoked with anything that has MIR, but some of // those things (notably the synthesized constructors from // tuple structs/variants) do not have an associated body diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 8153653e48b..6d694dcfac7 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -528,7 +528,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant, _: &hir::Generics) { self.check_missing_docs_attrs(cx, - Some(v.node.data.hir_id()), + Some(v.node.id), &v.node.attrs, v.span, "a variant"); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 67a249e605e..995532a00cd 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -407,6 +407,14 @@ impl cstore::CStore { self.get_crate_data(def.krate).get_struct_field_names(def.index) } + pub fn ctor_kind_untracked(&self, def: DefId) -> def::CtorKind { + self.get_crate_data(def.krate).get_ctor_kind(def.index) + } + + pub fn item_attrs_untracked(&self, def: DefId, sess: &Session) -> Lrc<[ast::Attribute]> { + self.get_crate_data(def.krate).get_item_attrs(def.index, sess) + } + pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec { let mut result = vec![]; self.get_crate_data(def_id.krate) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index c608c03095a..c6f7b46d383 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -544,13 +544,14 @@ impl<'a, 'tcx> CrateMetadata { } } - fn get_variant(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - item: &Entry<'_>, - index: DefIndex, - adt_kind: ty::AdtKind) - -> ty::VariantDef - { + fn get_variant( + &self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + item: &Entry<'_>, + index: DefIndex, + parent_did: DefId, + adt_kind: ty::AdtKind + ) -> ty::VariantDef { let data = match item.kind { EntryKind::Variant(data) | EntryKind::Struct(data, _) | @@ -558,13 +559,18 @@ impl<'a, 'tcx> CrateMetadata { _ => bug!(), }; - let def_id = self.local_def_id(data.struct_ctor.unwrap_or(index)); - let attribute_def_id = self.local_def_id(index); + let variant_did = if adt_kind == ty::AdtKind::Enum { + Some(self.local_def_id(index)) + } else { + None + }; + let ctor_did = data.ctor.map(|index| self.local_def_id(index)); ty::VariantDef::new( tcx, - def_id, Ident::from_interned_str(self.item_name(index)), + variant_did, + ctor_did, data.discr, item.children.decode(self).map(|index| { let f = self.entry(index); @@ -574,9 +580,9 @@ impl<'a, 'tcx> CrateMetadata { vis: f.visibility.decode(self) } }).collect(), - adt_kind, data.ctor_kind, - attribute_def_id, + adt_kind, + parent_did, false, ) } @@ -599,11 +605,11 @@ impl<'a, 'tcx> CrateMetadata { item.children .decode(self) .map(|index| { - self.get_variant(tcx, &self.entry(index), index, kind) + self.get_variant(tcx, &self.entry(index), index, did, kind) }) .collect() } else { - std::iter::once(self.get_variant(tcx, &item, item_id, kind)).collect() + std::iter::once(self.get_variant(tcx, &item, item_id, did, kind)).collect() }; tcx.alloc_adt_def(did, kind, variants, repr) @@ -808,23 +814,22 @@ impl<'a, 'tcx> CrateMetadata { // Re-export lists automatically contain constructors when necessary. match def { Def::Struct(..) => { - if let Some(ctor_def_id) = self.get_struct_ctor_def_id(child_index) { + if let Some(ctor_def_id) = self.get_ctor_def_id(child_index) { let ctor_kind = self.get_ctor_kind(child_index); - let ctor_def = Def::StructCtor(ctor_def_id, ctor_kind); - callback(def::Export { - def: ctor_def, - vis: self.get_visibility(ctor_def_id.index), - ident, span, - }); + let ctor_def = Def::Ctor( + hir::CtorOf::Struct, ctor_def_id, ctor_kind); + let vis = self.get_visibility(ctor_def_id.index); + callback(def::Export { def: ctor_def, vis, ident, span }); } } - Def::Variant(def_id) => { - // Braced variants, unlike structs, generate unusable names in - // value namespace, they are reserved for possible future use. - let ctor_kind = self.get_ctor_kind(child_index); - let ctor_def = Def::VariantCtor(def_id, ctor_kind); - let vis = self.get_visibility(child_index); - callback(def::Export { def: ctor_def, ident, vis, span }); + Def::Variant(..) => { + if let Some(ctor_def_id) = self.get_ctor_def_id(child_index) { + let ctor_kind = self.get_ctor_kind(child_index); + let ctor_def = Def::Ctor( + hir::CtorOf::Variant, ctor_def_id, ctor_kind); + let vis = self.get_visibility(ctor_def_id.index); + callback(def::Export { def: ctor_def, ident, vis, span }); + } } _ => {} } @@ -925,10 +930,13 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option { + pub fn get_ctor_def_id(&self, node_id: DefIndex) -> Option { match self.entry(node_id).kind { EntryKind::Struct(data, _) => { - data.decode(self).struct_ctor.map(|index| self.local_def_id(index)) + data.decode(self).ctor.map(|index| self.local_def_id(index)) + } + EntryKind::Variant(data) => { + data.decode(self).ctor.map(|index| self.local_def_id(index)) } _ => None, } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ce0618d4599..1af59f314bc 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -572,24 +572,21 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { /// will have to lookup the adt-def by its id, and that gives us /// the right to access any information in the adt-def (including, /// e.g., the length of the various vectors). - fn encode_enum_variant_info(&mut self, - (enum_did, Untracked(index)): (DefId, Untracked)) - -> Entry<'tcx> { + fn encode_enum_variant_info( + &mut self, + (enum_did, Untracked(index)): (DefId, Untracked), + ) -> Entry<'tcx> { let tcx = self.tcx; let def = tcx.adt_def(enum_did); let variant = &def.variants[index]; - let def_id = variant.did; + let def_id = variant.variant_did(); debug!("IsolatedEncoder::encode_enum_variant_info({:?})", def_id); let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - struct_ctor: None, - ctor_sig: if variant.ctor_kind == CtorKind::Fn { - Some(self.lazy(&tcx.fn_sig(def_id))) - } else { - None - } + ctor: variant.ctor_did().map(|did| did.index), + ctor_sig: None, }; let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap(); @@ -622,6 +619,57 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } } + /// Encode the constructor for the given variant of the given ADT. See + /// `encode_enum_variant_info` for an explanation about why the index is untracked. + fn encode_enum_variant_ctor( + &mut self, + (enum_did, Untracked(index)): (DefId, Untracked), + ) -> Entry<'tcx> { + let tcx = self.tcx; + let def = tcx.adt_def(enum_did); + let variant = &def.variants[index]; + let def_id = variant.ctor_did().unwrap(); + debug!("IsolatedEncoder::encode_enum_variant_ctor({:?})", def_id); + + let data = VariantData { + ctor_kind: variant.ctor_kind, + discr: variant.discr, + ctor: Some(def_id.index), + ctor_sig: if variant.ctor_kind == CtorKind::Fn { + Some(self.lazy(&tcx.fn_sig(def_id))) + } else { + None + } + }; + + // Variant constructors have the same visibility as the parent enums. + let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap(); + let enum_vis = &tcx.hir().expect_item_by_hir_id(enum_id).vis; + + Entry { + kind: EntryKind::Variant(self.lazy(&data)), + visibility: self.lazy(&ty::Visibility::from_hir(enum_vis, enum_id, tcx)), + span: self.lazy(&tcx.def_span(def_id)), + attributes: LazySeq::empty(), + children: LazySeq::empty(), + stability: self.encode_stability(def_id), + deprecation: self.encode_deprecation(def_id), + + ty: Some(self.encode_item_type(def_id)), + inherent_impls: LazySeq::empty(), + variances: if variant.ctor_kind == CtorKind::Fn { + self.encode_variances_of(def_id) + } else { + LazySeq::empty() + }, + generics: Some(self.encode_generics(def_id)), + predicates: Some(self.encode_predicates(def_id)), + predicates_defined_on: None, + + mir: self.encode_optimized_mir(def_id), + } + } + fn encode_info_for_mod(&mut self, FromId(id, (md, attrs, vis)): FromId<(&hir::Mod, &[ast::Attribute], @@ -678,7 +726,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let def_id = field.did; debug!("IsolatedEncoder::encode_field({:?})", def_id); - let variant_id = tcx.hir().as_local_hir_id(variant.did).unwrap(); + let variant_id = tcx.hir() + .as_local_hir_id(variant.variant_did_or_parent_struct_did()) + .unwrap(); let variant_data = tcx.hir().expect_variant_data(variant_id); Entry { @@ -710,7 +760,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - struct_ctor: Some(def_id.index), + ctor: Some(def_id.index), ctor_sig: if variant.ctor_kind == CtorKind::Fn { Some(self.lazy(&tcx.fn_sig(def_id))) } else { @@ -1072,18 +1122,15 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { // Encode def_ids for each field and method // for methods, write all the stuff get_trait_method // needs to know - let struct_ctor = if !struct_def.is_struct() { - Some(tcx.hir().local_def_id_from_hir_id(struct_def.hir_id()).index) - } else { - None - }; + let ctor = struct_def.ctor_hir_id() + .map(|ctor_hir_id| tcx.hir().local_def_id_from_hir_id(ctor_hir_id).index); let repr_options = get_repr_options(&tcx, def_id); EntryKind::Struct(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - struct_ctor, + ctor, ctor_sig: None, }), repr_options) } @@ -1094,7 +1141,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { EntryKind::Union(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, - struct_ctor: None, + ctor: None, ctor_sig: None, }), repr_options) } @@ -1171,8 +1218,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { hir::ItemKind::Enum(..) => { let def = self.tcx.adt_def(def_id); self.lazy_seq(def.variants.iter().map(|v| { - assert!(v.did.is_local()); - v.did.index + let did = v.variant_did(); + assert!(did.is_local()); + did.index })) } hir::ItemKind::Struct(..) | @@ -1765,17 +1813,23 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { let def = self.tcx.adt_def(def_id); for (i, variant) in def.variants.iter_enumerated() { - self.record(variant.did, + self.record(variant.variant_did(), IsolatedEncoder::encode_enum_variant_info, (def_id, Untracked(i))); + + if let Some(ctor_hir_did) = variant.ctor_did() { + self.record(ctor_hir_did, + IsolatedEncoder::encode_enum_variant_ctor, + (def_id, Untracked(i))); + } } } hir::ItemKind::Struct(ref struct_def, _) => { self.encode_fields(def_id); // If the struct has a constructor, encode it. - if !struct_def.is_struct() { - let ctor_def_id = self.tcx.hir().local_def_id_from_hir_id(struct_def.hir_id()); + if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { + let ctor_def_id = self.tcx.hir().local_def_id_from_hir_id(ctor_hir_id); self.record(ctor_def_id, IsolatedEncoder::encode_struct_ctor, (def_id, ctor_def_id)); diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index afeea9947b5..5b6166ebeaf 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -445,11 +445,8 @@ impl_stable_hash_for!(struct FnData<'tcx> { constness, arg_names, sig }); pub struct VariantData<'tcx> { pub ctor_kind: CtorKind, pub discr: ty::VariantDiscr, - - /// If this is a struct's only variant, this - /// is the index of the "struct ctor" item. - pub struct_ctor: Option, - + /// If this is unit or tuple-variant/struct, then this is the index of the ctor id. + pub ctor: Option, /// If this is a tuple struct or variant /// ctor, this is its "function" signature. pub ctor_sig: Option>>, @@ -458,7 +455,7 @@ pub struct VariantData<'tcx> { impl_stable_hash_for!(struct VariantData<'tcx> { ctor_kind, discr, - struct_ctor, + ctor, ctor_sig }); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 1138edcb375..0283352066c 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -31,10 +31,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t // Figure out what primary body this item has. let (body_id, return_ty_span) = match tcx.hir().get_by_hir_id(id) { - Node::Variant(variant) => - return create_constructor_shim(tcx, id, &variant.node.data), - Node::StructCtor(ctor) => - return create_constructor_shim(tcx, id, ctor), + Node::Ctor(_, ctor) => return create_constructor_shim(tcx, id, ctor), Node::Expr(hir::Expr { node: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) | Node::Item(hir::Item { node: hir::ItemKind::Fn(decl, _, _, body_id), .. }) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index b83f048114b..eb50bd727db 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -261,10 +261,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. expr_ty.ty_adt_def().and_then(|adt_def| { match path.def { - Def::VariantCtor(variant_id, CtorKind::Fn) => { - Some((adt_def, adt_def.variant_index_with_id(variant_id))) + Def::Ctor(hir::CtorOf::Variant, variant_ctor_id, CtorKind::Fn) => { + Some((adt_def, adt_def.variant_index_with_ctor_id(variant_ctor_id))) } - Def::StructCtor(_, CtorKind::Fn) | + Def::Ctor(hir::CtorOf::Struct, _, CtorKind::Fn) | Def::SelfCtor(..) => Some((adt_def, VariantIdx::new(0))), _ => None, } @@ -486,7 +486,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::Variant(variant_id) => { assert!(base.is_none()); - let index = adt.variant_index_with_id(variant_id); + let index = adt.variant_index_with_variant_id(variant_id); let user_provided_types = cx.tables().user_provided_types(); let user_ty = user_provided_types.get(expr.hir_id) .map(|u_ty| *u_ty); @@ -677,8 +677,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, .ty_adt_def() .and_then(|adt_def| { match def { - Def::VariantCtor(variant_id, CtorKind::Const) => { - let idx = adt_def.variant_index_with_id(variant_id); + Def::Ctor(hir::CtorOf::Variant, variant_ctor_id, CtorKind::Const) => { + let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); let (d, o) = adt_def.discriminant_def_for_variant(idx); use rustc::ty::util::IntTypeExt; let ty = adt_def.repr.discr_type(); @@ -804,8 +804,7 @@ fn user_substs_applied_to_def( // `Fn` but with the user-given substitutions. Def::Fn(_) | Def::Method(_) | - Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Fn) | + Def::Ctor(_, _, CtorKind::Fn) | Def::Const(_) | Def::AssociatedConst(_) => cx.tables().user_provided_types().get(hir_id).map(|u_ty| *u_ty), @@ -813,8 +812,7 @@ fn user_substs_applied_to_def( // `None`). This has the type of the enum/struct that defines // this variant -- but with the substitutions given by the // user. - Def::StructCtor(_def_id, CtorKind::Const) | - Def::VariantCtor(_def_id, CtorKind::Const) => + Def::Ctor(_, _, CtorKind::Const) => cx.user_substs_applied_to_ty_of_hir_id(hir_id), // `Self` is used in expression as a tuple struct constructor or an unit struct constructor @@ -911,8 +909,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // A regular function, constructor function or a constant. Def::Fn(_) | Def::Method(_) | - Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Fn) | + Def::Ctor(_, _, CtorKind::Fn) | Def::SelfCtor(..) => { let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def); debug!("convert_path_expr: user_ty={:?}", user_ty); @@ -956,8 +953,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } }, - Def::StructCtor(def_id, CtorKind::Const) | - Def::VariantCtor(def_id, CtorKind::Const) => { + Def::Ctor(_, def_id, CtorKind::Const) => { let user_provided_types = cx.tables.user_provided_types(); let user_provided_type = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty); debug!("convert_path_expr: user_provided_type={:?}", user_provided_type); @@ -968,7 +964,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty::Adt(adt_def, substs) => { ExprKind::Adt { adt_def, - variant_index: adt_def.variant_index_with_id(def_id), + variant_index: adt_def.variant_index_with_ctor_id(def_id), substs, user_ty: user_provided_type, fields: vec![], diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 88d1eb2ee0b..9637a111f42 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -435,7 +435,7 @@ impl<'tcx> Constructor<'tcx> { adt: &'tcx ty::AdtDef, ) -> VariantIdx { match self { - &Variant(vid) => adt.variant_index_with_id(vid), + &Variant(id) => adt.variant_index_with_ctor_or_variant_id(id), &Single => { assert!(!adt.is_enum()); VariantIdx::new(0) @@ -659,7 +659,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, ty::Adt(def, substs) if def.is_enum() => { def.variants.iter() .filter(|v| !cx.is_variant_uninhabited(v, substs)) - .map(|v| Variant(v.did)) + .map(|v| v.ctor_did().map_or_else(|| Variant(v.variant_did()), |did| Variant(did))) .collect() } ty::Char => { @@ -1307,7 +1307,9 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>, PatternKind::Binding { .. } | PatternKind::Wild => None, PatternKind::Leaf { .. } | PatternKind::Deref { .. } => Some(vec![Single]), PatternKind::Variant { adt_def, variant_index, .. } => { - Some(vec![Variant(adt_def.variants[variant_index].did)]) + let variant = &adt_def.variants[variant_index]; + Some(variant.ctor_did() + .map_or_else(|| vec![Variant(variant.variant_did())], |did| vec![Variant(did)])) } PatternKind::Constant { value } => Some(vec![ConstantValue(value)]), PatternKind::Range(PatternRange { lo, hi, ty, end }) => @@ -1742,11 +1744,11 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { let ref variant = adt_def.variants[variant_index]; - if *constructor == Variant(variant.did) { - Some(patterns_for_variant(subpatterns, wild_patterns)) - } else { - None - } + variant.ctor_did() + .map(|did| Variant(did)) + .or_else(|| Some(Variant(variant.variant_did()))) + .filter(|variant_constructor| variant_constructor == constructor) + .map(|_| patterns_for_variant(subpatterns, wild_patterns)) } PatternKind::Leaf { ref subpatterns } => { diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 8614be8d407..8349f21cdb4 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -733,8 +733,16 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty: Ty<'tcx>, subpatterns: Vec>, ) -> PatternKind<'tcx> { + let def = match def { + Def::Ctor(hir::CtorOf::Variant, variant_ctor_id, ..) => { + let variant_id = self.tcx.parent(variant_ctor_id).unwrap(); + Def::Variant(variant_id) + }, + def => def, + }; + let mut kind = match def { - Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => { + Def::Variant(variant_id) => { let enum_id = self.tcx.parent(variant_id).unwrap(); let adt_def = self.tcx.adt_def(enum_id); if adt_def.is_enum() { @@ -749,7 +757,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatternKind::Variant { adt_def, substs, - variant_index: adt_def.variant_index_with_id(variant_id), + variant_index: adt_def.variant_index_with_variant_id(variant_id), subpatterns, } } else { @@ -757,7 +765,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } - Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) | + Def::Struct(..) | Def::Ctor(hir::CtorOf::Struct, ..) | Def::Union(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) | Def::SelfCtor(..) => { PatternKind::Leaf { subpatterns } } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index f1fbc80edfb..cb25db73cd2 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -880,7 +880,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, }; let variant_no = if adt_def.is_enum() { - adt_def.variant_index_with_id(def_id) + adt_def.variant_index_with_ctor_id(def_id) } else { VariantIdx::new(0) }; diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 13bcdc26a5e..5e5e451b75b 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -1,5 +1,4 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE}; -use rustc::hir::def::CtorKind; use rustc::mir::*; use rustc::mir::visit::Visitor; use rustc::ty::{self, TyCtxt}; @@ -587,15 +586,12 @@ fn write_mir_sig( trace!("write_mir_sig: {:?}", src.instance); let descr = tcx.describe_def(src.def_id()); let is_function = match descr { - Some(Def::Fn(_)) | Some(Def::Method(_)) | Some(Def::Variant(..)) | - Some(Def::StructCtor(_, CtorKind::Fn)) => true, + Some(Def::Fn(_)) | Some(Def::Method(_)) | Some(Def::Ctor(..)) => true, _ => tcx.is_closure(src.def_id()), }; match (descr, src.promoted) { (_, Some(i)) => write!(w, "{:?} in ", i)?, - (Some(Def::StructCtor(..)), _) => write!(w, "struct ")?, - (Some(Def::Const(_)), _) - | (Some(Def::AssociatedConst(_)), _) => write!(w, "const ")?, + (Some(Def::Const(_)), _) | (Some(Def::AssociatedConst(_)), _) => write!(w, "const ")?, (Some(Def::Static(_, /*is_mutbl*/false)), _) => write!(w, "static ")?, (Some(Def::Static(_, /*is_mutbl*/true)), _) => write!(w, "static mut ")?, (_, _) if is_function => write!(w, "fn ")?, diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index 6de98675a3d..71eb6ed7e05 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -322,8 +322,8 @@ fn check_expr_kind<'a, 'tcx>( hir::ExprKind::Path(ref qpath) => { let def = v.tables.qpath_def(qpath, e.hir_id); match def { - Def::VariantCtor(..) | Def::StructCtor(..) | - Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) => Promotable, + Def::Ctor(..) | Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) => + Promotable, // References to a static that are themselves within a static // are inherently promotable with the exception @@ -387,8 +387,7 @@ fn check_expr_kind<'a, 'tcx>( Def::Err }; let def_result = match def { - Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Fn) | + Def::Ctor(_, _, CtorKind::Fn) | Def::SelfCtor(..) => Promotable, Def::Fn(did) => v.handle_const_fn_call(did), Def::Method(did) => { diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 19b5fa1bfbe..96fdb6a4382 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -225,7 +225,7 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) let vis = match tcx.hir().get_by_hir_id(hir_id) { Node::Item(item) => &item.vis, Node::ForeignItem(foreign_item) => &foreign_item.vis, - Node::TraitItem(..) | Node::Variant(..) => { + Node::TraitItem(..) | Node::Variant(..) | Node::Ctor(hir::CtorOf::Variant, ..) => { return def_id_visibility(tcx, tcx.hir().get_parent_did_by_hir_id(hir_id)); } Node::ImplItem(impl_item) => { @@ -239,7 +239,7 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) node => bug!("unexpected node kind: {:?}", node), } } - Node::StructCtor(vdata) => { + Node::Ctor(hir::CtorOf::Struct, vdata) => { let struct_hir_id = tcx.hir().get_parent_item(hir_id); let item = match tcx.hir().get_by_hir_id(struct_hir_id) { Node::Item(item) => item, @@ -504,7 +504,10 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { match item.node { hir::ItemKind::Enum(ref def, _) => { for variant in &def.variants { - let variant_level = self.update(variant.node.data.hir_id(), item_level); + let variant_level = self.update(variant.node.id, item_level); + if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() { + self.update(ctor_hir_id, item_level); + } for field in variant.node.data.fields() { self.update(field.hir_id, variant_level); } @@ -523,8 +526,8 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } } hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => { - if !def.is_struct() { - self.update(def.hir_id(), item_level); + if let Some(ctor_hir_id) = def.ctor_hir_id() { + self.update(ctor_hir_id, item_level); } for field in def.fields() { if field.vis.node.is_pub() { @@ -624,7 +627,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { self.reach(item.hir_id, item_level).generics().predicates(); } for variant in &def.variants { - let variant_level = self.get(variant.node.data.hir_id()); + let variant_level = self.get(variant.node.id); if variant_level.is_some() { for field in variant.node.data.fields() { self.reach(field.hir_id, variant_level).ty(); @@ -1468,7 +1471,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { v: &'tcx hir::Variant, g: &'tcx hir::Generics, item_id: hir::HirId) { - if self.access_levels.is_reachable(v.node.data.hir_id()) { + if self.access_levels.is_reachable(v.node.id) { self.in_variant = true; intravisit::walk_variant(self, v, g, item_id); self.in_variant = false; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 6fad4b2db97..72197d4a17a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -12,7 +12,7 @@ use crate::Namespace::{self, TypeNS, ValueNS, MacroNS}; use crate::{resolve_error, resolve_struct_error, ResolutionError}; use rustc::bug; -use rustc::hir::def::*; +use rustc::hir::{self, def::*}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; use rustc::ty; use rustc::middle::cstore::CrateStore; @@ -532,9 +532,10 @@ impl<'a> Resolver<'a> { // If this is a tuple or unit struct, define a name // in the value namespace as well. - if !struct_def.is_struct() { - let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()), - CtorKind::from_ast(struct_def)); + if let Some(ctor_node_id) = struct_def.ctor_id() { + let ctor_def = Def::Ctor(hir::CtorOf::Struct, + self.definitions.local_def_id(ctor_node_id), + CtorKind::from_ast(struct_def)); self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, sp, expansion)); self.struct_constructors.insert(def.def_id(), (ctor_def, ctor_vis)); } @@ -581,7 +582,7 @@ impl<'a> Resolver<'a> { vis: ty::Visibility, expansion: Mark) { let ident = variant.node.ident; - let def_id = self.definitions.local_def_id(variant.node.data.id()); + let def_id = self.definitions.local_def_id(variant.node.id); // Define a name in the type namespace. let def = Def::Variant(def_id); @@ -590,10 +591,22 @@ impl<'a> Resolver<'a> { // Define a constructor name in the value namespace. // Braced variants, unlike structs, generate unusable names in // value namespace, they are reserved for possible future use. - let ctor_kind = CtorKind::from_ast(&variant.node.data); - let ctor_def = Def::VariantCtor(def_id, ctor_kind); + if let Some(ctor_node_id) = variant.node.data.ctor_id() { + let ctor_def_id = self.definitions.local_def_id(ctor_node_id); + let ctor_kind = CtorKind::from_ast(&variant.node.data); + let ctor_def = Def::Ctor(hir::CtorOf::Variant, ctor_def_id, ctor_kind); - self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion)); + self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion)); + } else { + // We normally don't have a `Def::Ctor(hir::CtorOf::Variant, ..)` for + // `Struct`-variants, but we must define one for name resolution to succeed. This also + // takes place in `build_reduced_graph_for_external_crate_def`. + let def_id = self.definitions.local_def_id(variant.node.id); + let ctor_kind = CtorKind::from_ast(&variant.node.data); + let ctor_def = Def::Ctor(hir::CtorOf::Variant, def_id, ctor_kind); + + self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion)); + } } /// Constructs the reduced graph for one foreign item. @@ -645,14 +658,29 @@ impl<'a> Resolver<'a> { span); self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); } - Def::Variant(..) | Def::TyAlias(..) | Def::ForeignTy(..) | Def::Existential(..) | - Def::TraitAlias(..) | Def::PrimTy(..) | Def::ToolMod => { + Def::Variant(def_id) => { + self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion)); + + if hir::def::CtorKind::Fictive == self.cstore.ctor_kind_untracked(def_id) { + // We do not normally generate `Def::Ctor(hir::CtorOf::Variant, ..)` for + // `Struct`-variants. Therefore, `build_reduced_graph_for_external_crate_def` + // will not be called to define one. However, name resolution currently expects + // there to be one, so we generate one here. This is easy to solve for local + // code, see `build_reduced_graph_for_variant` for this case. + let ctor_def = Def::Ctor(hir::CtorOf::Variant, def_id, + hir::def::CtorKind::Fictive); + + let _ = self.try_define( + parent, ident, ValueNS, + (ctor_def, vis, DUMMY_SP, expansion).to_name_binding(self.arenas), + ); + } + } + Def::TyAlias(..) | Def::ForeignTy(..) | Def::Existential(..) | Def::TraitAlias(..) | + Def::PrimTy(..) | Def::ToolMod => { self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion)); } - Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::VariantCtor(..) => { - self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, expansion)); - } - Def::StructCtor(def_id, ..) => { + Def::Ctor(hir::CtorOf::Struct, def_id, ..) => { self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, expansion)); if let Some(struct_def_id) = @@ -661,6 +689,15 @@ impl<'a> Resolver<'a> { self.struct_constructors.insert(struct_def_id, (def, vis)); } } + Def::Ctor(hir::CtorOf::Variant, ..) => { + let _ = self.try_define( + parent, ident, ValueNS, + (def, vis, DUMMY_SP, expansion).to_name_binding(self.arenas), + ); + } + Def::Fn(..) | Def::Static(..) | Def::Const(..) => { + self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, expansion)); + } Def::Trait(def_id) => { let module_kind = ModuleKind::Def(def, ident.name); let module = self.new_module(parent, diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs index 828ffc6d320..6426ca12c6c 100644 --- a/src/librustc_resolve/error_reporting.rs +++ b/src/librustc_resolve/error_reporting.rs @@ -2,7 +2,7 @@ use std::cmp::Reverse; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use log::debug; -use rustc::hir::def::*; +use rustc::hir::{self, def::*}; use rustc::hir::def::Namespace::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::session::config::nightly_options; @@ -417,7 +417,7 @@ impl<'a> Resolver<'a> { } (Def::Union(..), _) | (Def::Variant(..), _) | - (Def::VariantCtor(_, CtorKind::Fictive), _) if ns == ValueNS => { + (Def::Ctor(hir::CtorOf::Variant, _, CtorKind::Fictive), _) if ns == ValueNS => { err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", path_str)); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 38ca5f0b664..e421a9edf89 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -571,24 +571,20 @@ impl<'a> PathSource<'a> { _ => false, }, PathSource::Expr(..) => match def { - Def::StructCtor(_, CtorKind::Const) | Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Const) | Def::VariantCtor(_, CtorKind::Fn) | + Def::Ctor(_, _, CtorKind::Const) | Def::Ctor(_, _, CtorKind::Fn) | Def::Const(..) | Def::Static(..) | Def::Local(..) | Def::Upvar(..) | Def::Fn(..) | Def::Method(..) | Def::AssociatedConst(..) | Def::SelfCtor(..) | Def::ConstParam(..) => true, _ => false, }, PathSource::Pat => match def { - Def::StructCtor(_, CtorKind::Const) | - Def::VariantCtor(_, CtorKind::Const) | + Def::Ctor(_, _, CtorKind::Const) | Def::Const(..) | Def::AssociatedConst(..) | Def::SelfCtor(..) => true, _ => false, }, PathSource::TupleStruct => match def { - Def::StructCtor(_, CtorKind::Fn) | - Def::VariantCtor(_, CtorKind::Fn) | - Def::SelfCtor(..) => true, + Def::Ctor(_, _, CtorKind::Fn) | Def::SelfCtor(..) => true, _ => false, }, PathSource::Struct => match def { @@ -1364,7 +1360,7 @@ impl<'a> NameBinding<'a> { fn is_variant(&self) -> bool { match self.kind { NameBindingKind::Def(Def::Variant(..), _) | - NameBindingKind::Def(Def::VariantCtor(..), _) => true, + NameBindingKind::Def(Def::Ctor(hir::CtorOf::Variant, ..), _) => true, _ => false, } } @@ -3089,16 +3085,14 @@ impl<'a> Resolver<'a> { let is_syntactic_ambiguity = opt_pat.is_none() && bmode == BindingMode::ByValue(Mutability::Immutable); match def { - Def::StructCtor(_, CtorKind::Const) | - Def::VariantCtor(_, CtorKind::Const) | + Def::Ctor(_, _, CtorKind::Const) | Def::Const(..) if is_syntactic_ambiguity => { // Disambiguate in favor of a unit struct/variant // or constant pattern. self.record_use(ident, ValueNS, binding.unwrap(), false); Some(PathResolution::new(def)) } - Def::StructCtor(..) | Def::VariantCtor(..) | - Def::Const(..) | Def::Static(..) => { + Def::Ctor(..) | Def::Const(..) | Def::Static(..) => { // This is unambiguously a fresh binding, either syntactically // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves // to something unusable as a pattern (e.g., constructor function), @@ -4458,8 +4452,7 @@ impl<'a> Resolver<'a> { // outside crate private modules => no need to check this) if !in_module_is_extern || name_binding.vis == ty::Visibility::Public { let did = match def { - Def::StructCtor(did, _) | Def::VariantCtor(did, _) => - self.parent(did), + Def::Ctor(_, did, _) => self.parent(did), _ => def.opt_def_id(), }; candidates.push(ImportSuggestion { did, path }); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 9daffd522bf..77fe57910cb 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -880,10 +880,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { Ok(binding) => { let imported_binding = this.import(binding, directive); target_bindings[ns].set(Some(imported_binding)); - let conflict = this.try_define(parent, target, ns, imported_binding); - if let Err(old_binding) = conflict { - this.report_conflict(parent, target, ns, imported_binding, old_binding); - } + this.define(parent, target, ns, imported_binding); } } }); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 76fd8b22f74..263f5acb662 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -488,8 +488,8 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { }; let (value, fields) = match item.node { - ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, ..), _) | - ast::ItemKind::Union(ast::VariantData::Struct(ref fields, ..), _) => { + ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, ..), ..) | + ast::ItemKind::Union(ast::VariantData::Struct(ref fields, ..), ..) => { let include_priv_fields = !self.save_ctxt.config.pub_only; let fields_str = fields .iter() @@ -581,7 +581,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str); if !self.span.filter_generated(name_span) { let span = self.span_from_span(name_span); - let id = id_from_node_id(variant.node.data.id(), &self.save_ctxt); + let id = id_from_node_id(variant.node.id, &self.save_ctxt); let parent = Some(id_from_node_id(item.id, &self.save_ctxt)); self.dumper.dump_def( @@ -619,7 +619,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { } if !self.span.filter_generated(name_span) { let span = self.span_from_span(name_span); - let id = id_from_node_id(variant.node.data.id(), &self.save_ctxt); + let id = id_from_node_id(variant.node.id, &self.save_ctxt); let parent = Some(id_from_node_id(item.id, &self.save_ctxt)); self.dumper.dump_def( @@ -648,7 +648,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { for field in variant.node.data.fields() { - self.process_struct_field_def(field, variant.node.data.id()); + self.process_struct_field_def(field, variant.node.id); self.visit_ty(&field.ty); } } @@ -957,8 +957,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { ); } } - HirDef::StructCtor(..) | - HirDef::VariantCtor(..) | + HirDef::Ctor(_, _, _) | HirDef::Const(..) | HirDef::AssociatedConst(..) | HirDef::Struct(..) | diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 7ad5b7ce8c7..de9a4b92c82 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -298,7 +298,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: None, children: def.variants .iter() - .map(|v| id_from_node_id(v.node.data.id(), self)) + .map(|v| id_from_node_id(v.node.id, self)) .collect(), decl_id: None, docs: self.docs_for_attrs(&item.attrs), @@ -725,16 +725,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ref_id: id_from_node_id(id, self), }) } - HirDef::Static(..) | - HirDef::Const(..) | - HirDef::AssociatedConst(..) | - HirDef::VariantCtor(..) => { - Some(Ref { - kind: RefKind::Variable, - span, - ref_id: id_from_def_id(def.def_id()), - }) - } HirDef::Trait(def_id) if fn_type(path_seg) => { Some(Ref { kind: RefKind::Type, @@ -767,7 +757,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ref_id: id_from_def_id(def_id), }) } - HirDef::StructCtor(def_id, _) => { + HirDef::Ctor(hir::CtorOf::Struct, def_id, _) => { // This is a reference to a tuple struct where the def_id points // to an invisible constructor function. That is not a very useful // def, so adjust to point to the tuple struct itself. @@ -778,6 +768,16 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ref_id: id_from_def_id(parent_def_id), }) } + HirDef::Static(..) | + HirDef::Const(..) | + HirDef::AssociatedConst(..) | + HirDef::Ctor(..) => { + Some(Ref { + kind: RefKind::Variable, + span, + ref_id: id_from_def_id(def.def_id()), + }) + } HirDef::Method(decl_id) => { let def_id = if decl_id.is_local() { let ti = self.tcx.associated_item(decl_id); diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 6e47ae6b159..76034f32c74 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -586,7 +586,7 @@ impl Sig for ast::Path { refs: vec![], }) } - Def::AssociatedConst(..) | Def::Variant(..) | Def::VariantCtor(..) => { + Def::AssociatedConst(..) | Def::Variant(..) | Def::Ctor(..) => { let len = self.segments.len(); if len < 2 { return Err("Bad path"); @@ -700,10 +700,11 @@ impl Sig for ast::StructField { impl Sig for ast::Variant_ { - fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext<'_, '_>) -> Result { + fn make(&self, offset: usize, parent_id: Option, scx: &SaveContext<'_, '_>) -> Result { let mut text = self.ident.to_string(); match self.data { - ast::VariantData::Struct(ref fields, id, r) => { + ast::VariantData::Struct(ref fields, r) => { + let id = parent_id.unwrap(); let name_def = SigElement { id: id_from_node_id(id, scx), start: offset, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index e470748e344..ad62d2160b1 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1318,10 +1318,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { tcx.hygienic_eq(assoc_ident, vd.ident, adt_def.did) }); if let Some(variant_def) = variant_def { - let def = Def::Variant(variant_def.did); + let did = variant_def.variant_did(); + let def = Def::Variant(did); if permit_variants { check_type_alias_enum_variants_enabled(tcx, span); - tcx.check_stability(variant_def.did, Some(hir_ref_id), span); + tcx.check_stability(did, Some(hir_ref_id), span); return (qself_ty, def); } else { variant_resolution = Some(def); @@ -1596,7 +1597,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { match def { // Case 1. Reference to a struct constructor. - Def::StructCtor(def_id, ..) | + Def::Ctor(hir::CtorOf::Struct, def_id, ..) | Def::SelfCtor(.., def_id) => { // Everything but the final segment should have no // parameters at all. @@ -1608,8 +1609,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } // Case 2. Reference to a variant constructor. - Def::Variant(def_id) | - Def::VariantCtor(def_id, ..) => { + Def::Ctor(hir::CtorOf::Variant, def_id, ..) | Def::Variant(def_id, ..) => { let adt_def = self_ty.map(|t| t.ty_adt_def().unwrap()); let (generics_def_id, index) = if let Some(adt_def) = adt_def { debug_assert!(adt_def.is_enum()); @@ -1617,6 +1617,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } else if last >= 1 && segments[last - 1].args.is_some() { // Everything but the penultimate segment should have no // parameters at all. + let mut def_id = def_id; + + // `Def::Ctor` -> `Def::Variant` + if let Def::Ctor(..) = def { + def_id = tcx.parent(def_id).unwrap() + } + + // `Def::Variant` -> `Def::Item` (enum) let enum_def_id = tcx.parent(def_id).unwrap(); (enum_def_id, last - 1) } else { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index c30b9d65fec..6d441521a9e 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -807,15 +807,13 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); report_unexpected_variant_def(tcx, &def, pat.span, qpath); return tcx.types.err; } - Def::VariantCtor(_, CtorKind::Fictive) | - Def::VariantCtor(_, CtorKind::Fn) => { + Def::Ctor(hir::CtorOf::Variant, _, CtorKind::Fictive) | + Def::Ctor(hir::CtorOf::Variant, _, CtorKind::Fn) => { report_unexpected_variant_def(tcx, &def, pat.span, qpath); return tcx.types.err; } - Def::VariantCtor(_, CtorKind::Const) | - Def::StructCtor(_, CtorKind::Const) | - Def::SelfCtor(..) | - Def::Const(..) | Def::AssociatedConst(..) => {} // OK + Def::Ctor(_, _, CtorKind::Const) | Def::SelfCtor(..) | Def::Const(..) | + Def::AssociatedConst(..) => {} // OK _ => bug!("unexpected pattern definition: {:?}", def) } @@ -876,8 +874,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); report_unexpected_def(def); return tcx.types.err; } - Def::VariantCtor(_, CtorKind::Fn) | - Def::StructCtor(_, CtorKind::Fn) => { + Def::Ctor(_, _, CtorKind::Fn) => { tcx.expect_variant_def(def) } _ => bug!("unexpected pattern definition: {:?}", def) @@ -950,7 +947,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let mut inexistent_fields = vec![]; // Typecheck each field. for &Spanned { node: ref field, span } in fields { - let ident = tcx.adjust_ident(field.ident, variant.did, self.body_id).0; + let ident = tcx.adjust_ident( + field.ident, variant.variant_did_or_parent_struct_did(), self.body_id).0; let field_ty = match used_fields.entry(ident) { Occupied(occupied) => { struct_span_err!(tcx.sess, span, E0025, @@ -998,18 +996,19 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); .join(", ")), "these", "s") }; let spans = inexistent_fields.iter().map(|(span, _)| *span).collect::>(); + let did = variant.variant_did_or_parent_struct_did(); let mut err = struct_span_err!(tcx.sess, spans, E0026, "{} `{}` does not have {}", kind_name, - tcx.def_path_str(variant.did), + tcx.def_path_str(did), field_names); if let Some((span, ident)) = inexistent_fields.last() { err.span_label(*span, format!("{} `{}` does not have {} field{}", kind_name, - tcx.def_path_str(variant.did), + tcx.def_path_str(did), t, plural)); if plural == "" { diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 3a7308d0917..5d10f531ced 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -130,7 +130,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let sole_field = &variant.fields[0]; let sole_field_ty = sole_field.ty(self.tcx, substs); if self.can_coerce(expr_ty, sole_field_ty) { - let variant_path = self.tcx.def_path_str(variant.did); + let variant_path = self.tcx.def_path_str(variant.variant_did()); // FIXME #56861: DRYer prelude filtering Some(variant_path.trim_start_matches("std::prelude::v1::").to_string()) } else { diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 5e3ebcb3446..f860ab649f9 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -417,7 +417,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(variant_def) = variant_def { check_type_alias_enum_variants_enabled(tcx, span); - let def = Def::VariantCtor(variant_def.did, variant_def.ctor_kind); + let def = if let Some(ctor_did) = variant_def.ctor_did() { + Def::Ctor(hir::CtorOf::Variant, ctor_did, variant_def.ctor_kind) + } else { + // Normally, there do not exist any `Def::Ctor` for `Struct`-variants but + // in this case, we can get better error messages as diagnostics will + // specialize the message around a `CtorKind::Fictive`. + Def::Ctor(hir::CtorOf::Variant, variant_def.variant_did(), + hir::def::CtorKind::Fictive) + }; + tcx.check_stability(def.def_id(), Some(expr_id), span); return Ok(def); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1054619f0f8..fe17f247916 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1863,7 +1863,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for ((_, discr), v) in def.discriminants(tcx).zip(vs) { // Check for duplicate discriminant values if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) { - let variant_did = def.variants[VariantIdx::new(i)].did; + let variant_did = def.variants[VariantIdx::new(i)].variant_did(); let variant_i_hir_id = tcx.hir().as_local_hir_id(variant_did).unwrap(); let variant_i = tcx.hir().expect_variant(variant_i_hir_id); let i_span = match variant_i.node.disr_expr { @@ -3693,7 +3693,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let names = variant.fields.iter().filter_map(|field| { // ignore already set fields and private fields from non-local crates if skip.iter().any(|x| *x == field.ident.as_str()) || - (variant.did.krate != LOCAL_CRATE && field.vis != Visibility::Public) { + (!variant.is_local() && field.vis != Visibility::Public) + { None } else { Some(&field.ident.name) @@ -3705,7 +3706,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec { variant.fields.iter().filter(|field| { - let def_scope = self.tcx.adjust_ident(field.ident, variant.did, self.body_id).1; + let did = variant.variant_did_or_parent_struct_did(); + let def_scope = self.tcx.adjust_ident(field.ident, did, self.body_id).1; field.vis.is_accessible_from(def_scope, self.tcx) }) .map(|field| field.ident.name) @@ -3823,7 +3825,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Type-check each field. for field in ast_fields { - let ident = tcx.adjust_ident(field.ident, variant.did, self.body_id).0; + let ident = tcx.adjust_ident( + field.ident, variant.variant_did_or_parent_struct_did(), self.body_id).0; let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) { seen_fields.insert(ident, field.span); self.write_field_index(field.hir_id, i); @@ -4237,7 +4240,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.set_tainted_by_errors(); tcx.types.err } - Def::VariantCtor(_, CtorKind::Fictive) => { + Def::Ctor(hir::CtorOf::Variant, _, CtorKind::Fictive) => { report_unexpected_variant_def(tcx, &def, expr.span, qpath); tcx.types.err } @@ -5343,8 +5346,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match adt_def { Some(adt_def) if adt_def.has_ctor() => { let variant = adt_def.non_enum_variant(); - let def = Def::StructCtor(variant.did, variant.ctor_kind); - (def, variant.did, tcx.type_of(variant.did)) + let ctor_did = variant.ctor_did().unwrap(); + let def = Def::Ctor(hir::CtorOf::Struct, ctor_did, variant.ctor_kind); + (def, ctor_did, tcx.type_of(ctor_did)) } _ => { let mut err = tcx.sess.struct_span_err(span, @@ -5416,7 +5420,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut user_self_ty = None; let mut is_alias_variant_ctor = false; match def { - Def::VariantCtor(_, _) => { + Def::Ctor(hir::CtorOf::Variant, _, _) => { if let Some(self_ty) = self_ty { let adt_def = self_ty.ty_adt_def().unwrap(); user_self_ty = Some(UserSelfTy { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c0739db3df6..56129479f77 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -446,8 +446,8 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: hir::HirId) { tcx.predicates_of(def_id); } - if !struct_def.is_struct() { - convert_variant_ctor(tcx, struct_def.hir_id()); + if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { + convert_variant_ctor(tcx, ctor_hir_id); } } @@ -556,21 +556,24 @@ fn convert_enum_variant_types<'a, 'tcx>( // Convert the ctor, if any. This also registers the variant as // an item. - convert_variant_ctor(tcx, variant.node.data.hir_id()); + if let Some(ctor_hir_id) = variant.node.data.ctor_hir_id() { + convert_variant_ctor(tcx, ctor_hir_id); + } } } fn convert_variant<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId, + variant_did: Option, + ctor_did: Option, ident: Ident, discr: ty::VariantDiscr, def: &hir::VariantData, adt_kind: ty::AdtKind, - attribute_def_id: DefId + parent_did: DefId ) -> ty::VariantDef { let mut seen_fields: FxHashMap = Default::default(); - let hir_id = tcx.hir().as_local_hir_id(did).unwrap(); + let hir_id = tcx.hir().as_local_hir_id(variant_did.unwrap_or(parent_did)).unwrap(); let fields = def .fields() .iter() @@ -599,17 +602,19 @@ fn convert_variant<'a, 'tcx>( }) .collect(); let recovered = match def { - hir::VariantData::Struct(_, _, r) => *r, + hir::VariantData::Struct(_, r) => *r, _ => false, }; - ty::VariantDef::new(tcx, - did, + ty::VariantDef::new( + tcx, ident, + variant_did, + ctor_did, discr, fields, - adt_kind, CtorKind::from_hir(def), - attribute_def_id, + adt_kind, + parent_did, recovered, ) } @@ -627,58 +632,52 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad let (kind, variants) = match item.node { ItemKind::Enum(ref def, _) => { let mut distance_from_explicit = 0; - ( - AdtKind::Enum, - def.variants - .iter() - .map(|v| { - let did = tcx.hir().local_def_id_from_hir_id(v.node.data.hir_id()); - let discr = if let Some(ref e) = v.node.disr_expr { - distance_from_explicit = 0; - ty::VariantDiscr::Explicit(tcx.hir().local_def_id_from_hir_id(e.hir_id)) - } else { - ty::VariantDiscr::Relative(distance_from_explicit) - }; - distance_from_explicit += 1; + let variants = def.variants + .iter() + .map(|v| { + let variant_did = Some(tcx.hir().local_def_id_from_hir_id(v.node.id)); + let ctor_did = v.node.data.ctor_hir_id() + .map(|hir_id| tcx.hir().local_def_id_from_hir_id(hir_id)); - convert_variant(tcx, did, v.node.ident, discr, &v.node.data, AdtKind::Enum, - did) - }) - .collect(), - ) + let discr = if let Some(ref e) = v.node.disr_expr { + distance_from_explicit = 0; + ty::VariantDiscr::Explicit(tcx.hir().local_def_id_from_hir_id(e.hir_id)) + } else { + ty::VariantDiscr::Relative(distance_from_explicit) + }; + distance_from_explicit += 1; + + convert_variant(tcx, variant_did, ctor_did, v.node.ident, discr, + &v.node.data, AdtKind::Enum, def_id) + }) + .collect(); + + (AdtKind::Enum, variants) } ItemKind::Struct(ref def, _) => { - // Use separate constructor id for unit/tuple structs and reuse did for braced structs. - let ctor_id = if !def.is_struct() { - Some(tcx.hir().local_def_id_from_hir_id(def.hir_id())) - } else { - None - }; - ( - AdtKind::Struct, - std::iter::once(convert_variant( - tcx, - ctor_id.unwrap_or(def_id), - item.ident, - ty::VariantDiscr::Relative(0), - def, - AdtKind::Struct, - def_id - )).collect(), - ) + let variant_did = None; + let ctor_did = def.ctor_hir_id() + .map(|hir_id| tcx.hir().local_def_id_from_hir_id(hir_id)); + + let variants = std::iter::once(convert_variant( + tcx, variant_did, ctor_did, item.ident, ty::VariantDiscr::Relative(0), def, + AdtKind::Struct, def_id, + )).collect(); + + (AdtKind::Struct, variants) } - ItemKind::Union(ref def, _) => ( - AdtKind::Union, - std::iter::once(convert_variant( - tcx, - def_id, - item.ident, - ty::VariantDiscr::Relative(0), - def, - AdtKind::Union, - def_id - )).collect(), - ), + ItemKind::Union(ref def, _) => { + let variant_did = None; + let ctor_did = def.ctor_hir_id() + .map(|hir_id| tcx.hir().local_def_id_from_hir_id(hir_id)); + + let variants = std::iter::once(convert_variant( + tcx, variant_did, ctor_did, item.ident, ty::VariantDiscr::Relative(0), def, + AdtKind::Union, def_id, + )).collect(); + + (AdtKind::Union, variants) + }, _ => bug!(), }; tcx.alloc_adt_def(def_id, kind, variants, repr) @@ -889,8 +888,8 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty let node = tcx.hir().get_by_hir_id(hir_id); let parent_def_id = match node { - Node::ImplItem(_) | Node::TraitItem(_) | Node::Variant(_) - | Node::StructCtor(_) | Node::Field(_) => { + Node::ImplItem(_) | Node::TraitItem(_) | Node::Variant(_) | + Node::Ctor(..) | Node::Field(_) => { let parent_id = tcx.hir().get_parent_item(hir_id); Some(tcx.hir().local_def_id_from_hir_id(parent_id)) } @@ -1248,8 +1247,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { ForeignItemKind::Type => tcx.mk_foreign(def_id), }, - Node::StructCtor(&ref def) - | Node::Variant(&Spanned { + Node::Ctor(_, &ref def) | Node::Variant(&Spanned { node: hir::VariantKind { data: ref def, .. }, .. }) => match *def { @@ -1627,17 +1625,12 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::PolyFnSig compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) } - StructCtor(&VariantData::Tuple(ref fields, ..)) - | Variant(&Spanned { - node: - hir::VariantKind { - data: VariantData::Tuple(ref fields, ..), - .. - }, + Ctor(_, data) | Variant(Spanned { + node: hir::VariantKind { data, .. }, .. - }) => { + }) if data.ctor_hir_id().is_some() => { let ty = tcx.type_of(tcx.hir().get_parent_did_by_hir_id(hir_id)); - let inputs = fields + let inputs = data.fields() .iter() .map(|f| tcx.type_of(tcx.hir().local_def_id_from_hir_id(f.hir_id))); ty::Binder::bind(tcx.mk_fn_sig( diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 20eae5d8835..f2406bd8540 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -75,7 +75,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { self.visit_node_helper(item.hir_id); if let hir::VariantData::Tuple(..) = *struct_def { - self.visit_node_helper(struct_def.hir_id()); + self.visit_node_helper(struct_def.ctor_hir_id().unwrap()); } } @@ -84,7 +84,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { for variant in &enum_def.variants { if let hir::VariantData::Tuple(..) = variant.node.data { - self.visit_node_helper(variant.node.data.hir_id()); + self.visit_node_helper(variant.node.data.ctor_hir_id().unwrap()); } } } diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index c2f79207a56..9b9a6bace96 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -79,7 +79,7 @@ fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId) _ => unsupported() }, - Node::Variant(_) | Node::StructCtor(_) => {} + Node::Variant(_) | Node::Ctor(..) => {} _ => unsupported() } diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 50c8d5adfa3..ac686e40076 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -136,7 +136,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { self.add_inferreds_for_item(item.hir_id); if let hir::VariantData::Tuple(..) = *struct_def { - self.add_inferreds_for_item(struct_def.hir_id()); + self.add_inferreds_for_item(struct_def.ctor_hir_id().unwrap()); } } @@ -145,7 +145,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { for variant in &enum_def.variants { if let hir::VariantData::Tuple(..) = variant.node.data { - self.add_inferreds_for_item(variant.node.data.hir_id()); + self.add_inferreds_for_item(variant.node.data.ctor_hir_id().unwrap()); } } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 880f67281b9..5969aa758df 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -88,9 +88,7 @@ pub fn try_inline( Def::Variant(..) => return None, // Assume that enum variants and struct types are re-exported next to // their constructors. - Def::VariantCtor(..) | - Def::StructCtor(..) | - Def::SelfCtor(..) => return Some(Vec::new()), + Def::Ctor(..) | Def::SelfCtor(..) => return Some(Vec::new()), Def::Mod(did) => { record_extern_fqn(cx, did, clean::TypeKind::Module); clean::ModuleItem(build_module(cx, did, visited)) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ba4481733d5..3ebca05f7dd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3133,7 +3133,7 @@ impl Clean for doctree::Variant { visibility: None, stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - def_id: cx.tcx.hir().local_def_id_from_hir_id(self.def.hir_id()), + def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id), inner: VariantItem(Variant { kind: self.def.clean(cx), }), @@ -3169,15 +3169,16 @@ impl<'tcx> Clean for ty::VariantDef { }) } }; + let did = self.variant_did_or_parent_struct_did(); Item { name: Some(self.ident.clean(cx)), - attrs: inline::load_attrs(cx, self.did), - source: cx.tcx.def_span(self.did).clean(cx), + attrs: inline::load_attrs(cx, did), + source: cx.tcx.def_span(did).clean(cx), visibility: Some(Inherited), - def_id: self.did, + def_id: did, inner: VariantItem(Variant { kind }), - stability: get_stability(cx, self.did), - deprecation: get_deprecation(cx, self.did), + stability: get_stability(cx, did), + deprecation: get_deprecation(cx, did), } } } diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 9c54b40b422..7a528e50e9c 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -125,6 +125,7 @@ pub struct Enum { pub struct Variant { pub name: Name, + pub id: hir::HirId, pub attrs: hir::HirVec, pub def: hir::VariantData, pub stab: Option, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 7c1a61449a2..ee182237b49 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -344,9 +344,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { .and_then(|(def, fragment)| { // Constructors are picked up in the type namespace. match def { - Def::StructCtor(..) - | Def::VariantCtor(..) - | Def::SelfCtor(..) => None, + Def::Ctor(..) | Def::SelfCtor(..) => None, _ => Some((def, fragment)) } }), diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index b4db121fb53..a7e2b2155e9 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -141,9 +141,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { name, variants: def.variants.iter().map(|v| Variant { name: v.node.ident.name, + id: v.node.id, attrs: v.node.attrs.clone(), - stab: self.stability(v.node.data.hir_id()), - depr: self.deprecation(v.node.data.hir_id()), + stab: self.stability(v.node.id), + depr: self.deprecation(v.node.id), def: v.node.data.clone(), whence: v.span, }).collect(), @@ -420,8 +421,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // Struct and variant constructors and proc macro stubs always show up alongside // their definitions, we've already processed them so just discard these. match path.def { - Def::StructCtor(..) | Def::VariantCtor(..) | Def::SelfCtor(..) | - Def::Macro(_, MacroKind::ProcMacroStub) => return, + Def::Ctor(..) | Def::SelfCtor(..) | Def::Macro(_, MacroKind::ProcMacroStub) => + return, _ => {} } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2cbd2dfeb25..c64ffb1232f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1956,8 +1956,13 @@ pub struct EnumDef { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Variant_ { + /// Name of the variant. pub ident: Ident, + /// Attributes of the variant. pub attrs: Vec, + /// Id of the variant (not the constructor, see `VariantData::ctor_id()`). + pub id: NodeId, + /// Fields and constructor id of the variant. pub data: VariantData, /// Explicit discriminant, e.g., `Foo = 1`. pub disr_expr: Option, @@ -2117,23 +2122,13 @@ pub struct StructField { pub attrs: Vec, } -/// 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`. +/// Fields and constructor ids of enum variants and structs. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum VariantData { /// Struct variant. /// /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`. - Struct(Vec, NodeId, bool), + Struct(Vec, bool), /// Tuple variant. /// /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`. @@ -2145,17 +2140,23 @@ pub enum VariantData { } impl VariantData { + /// Return the fields of this variant. pub fn fields(&self) -> &[StructField] { match *self { VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, _) => fields, _ => &[], } } - pub fn id(&self) -> NodeId { + + /// Return the `NodeId` of this variant's constructor, if it has one. + pub fn ctor_id(&self) -> Option { match *self { - VariantData::Struct(_, id, _) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id, + VariantData::Struct(..) => None, + VariantData::Tuple(_, id) | VariantData::Unit(id) => Some(id), } } + + /// Does this `VariantData` represent a `Struct`-struct/variant? pub fn is_struct(&self) -> bool { if let VariantData::Struct(..) = *self { true @@ -2163,6 +2164,8 @@ impl VariantData { false } } + + /// Does this `VariantData` represent a tuple struct/variant? pub fn is_tuple(&self) -> bool { if let VariantData::Tuple(..) = *self { true @@ -2170,6 +2173,8 @@ impl VariantData { false } } + + /// Does this `VariantData` represent a unit struct/variant? pub fn is_unit(&self) -> bool { if let VariantData::Unit(..) = *self { true diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 7159c949513..18173628a26 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -225,10 +225,9 @@ impl<'a> StripUnconfigured<'a> { fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) { match vdata { - ast::VariantData::Struct(fields, _id, _) | - ast::VariantData::Tuple(fields, _id) => + ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) => fields.flat_map_in_place(|field| self.configure(field)), - ast::VariantData::Unit(_id) => {} + ast::VariantData::Unit(_) => {} } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index e95f0589449..614967bdeb4 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -1062,6 +1062,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { respan(span, ast::Variant_ { ident, + id: ast::DUMMY_NODE_ID, attrs: Vec::new(), data: vdata, disr_expr: None, diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 5bb1d8a4b94..784d0049ac5 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -450,9 +450,10 @@ pub fn noop_visit_foreign_mod(foreign_mod: &mut ForeignMod, vis: } pub fn noop_visit_variant(variant: &mut Variant, vis: &mut T) { - let Spanned { node: Variant_ { ident, attrs, data, disr_expr }, span } = variant; + let Spanned { node: Variant_ { ident, attrs, id, data, disr_expr }, span } = variant; vis.visit_ident(ident); visit_attrs(attrs, vis); + vis.visit_id(id); vis.visit_variant_data(data); visit_opt(disr_expr, |disr_expr| vis.visit_anon_const(disr_expr)); vis.visit_span(span); @@ -765,11 +766,11 @@ pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: pub fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut T) { match vdata { - VariantData::Struct(fields, id, _) | + VariantData::Struct(fields, ..) => visit_vec(fields, |field| vis.visit_struct_field(field)), VariantData::Tuple(fields, id) => { visit_vec(fields, |field| vis.visit_struct_field(field)); vis.visit_id(id); - } + }, VariantData::Unit(id) => vis.visit_id(id), } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 99260314054..d7a2170342d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6844,7 +6844,7 @@ impl<'a> Parser<'a> { } else { // If we see: `struct Foo where T: Copy { ... }` let (fields, recovered) = self.parse_record_struct_body()?; - VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered) + VariantData::Struct(fields, recovered) } // No `where` so: `struct Foo;` } else if self.eat(&token::Semi) { @@ -6852,7 +6852,7 @@ impl<'a> Parser<'a> { // Record-style struct definition } else if self.token == token::OpenDelim(token::Brace) { let (fields, recovered) = self.parse_record_struct_body()?; - VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered) + VariantData::Struct(fields, recovered) // Tuple-style struct definition with optional where-clause. } else if self.token == token::OpenDelim(token::Paren) { let body = VariantData::Tuple(self.parse_tuple_struct_body()?, ast::DUMMY_NODE_ID); @@ -6881,10 +6881,10 @@ impl<'a> Parser<'a> { let vdata = if self.token.is_keyword(keywords::Where) { generics.where_clause = self.parse_where_clause()?; let (fields, recovered) = self.parse_record_struct_body()?; - VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered) + VariantData::Struct(fields, recovered) } else if self.token == token::OpenDelim(token::Brace) { let (fields, recovered) = self.parse_record_struct_body()?; - VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered) + VariantData::Struct(fields, recovered) } else { let token_str = self.this_token_descr(); let mut err = self.fatal(&format!( @@ -7708,7 +7708,7 @@ impl<'a> Parser<'a> { // Parse a struct variant. all_nullary = false; let (fields, recovered) = self.parse_record_struct_body()?; - struct_def = VariantData::Struct(fields, ast::DUMMY_NODE_ID, recovered); + struct_def = VariantData::Struct(fields, recovered); } else if self.check(&token::OpenDelim(token::Paren)) { all_nullary = false; struct_def = VariantData::Tuple( @@ -7730,6 +7730,7 @@ impl<'a> Parser<'a> { let vr = ast::Variant_ { ident, + id: ast::DUMMY_NODE_ID, attrs: variant_attrs, data: struct_def, disr_expr, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 07df14ddc72..946fdc0c469 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -3266,6 +3266,7 @@ mod tests { let var = source_map::respan(syntax_pos::DUMMY_SP, ast::Variant_ { ident, attrs: Vec::new(), + id: ast::DUMMY_NODE_ID, // making this up as I go.... ? data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), disr_expr: None, diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs index ef41373d774..29c97ed6d38 100644 --- a/src/test/mir-opt/unusual-item-types.rs +++ b/src/test/mir-opt/unusual-item-types.rs @@ -72,7 +72,7 @@ fn main() { // } // END rustc.ptr-real_drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir -// START rustc.Test-X.mir_map.0.mir +// START rustc.Test-X-{{variant constructor}}.mir_map.0.mir // fn Test::X(_1: usize) -> Test { // let mut _0: Test; // @@ -81,4 +81,4 @@ fn main() { // return; // } // } -// END rustc.Test-X.mir_map.0.mir +// END rustc.Test-X-{{variant constructor}}.mir_map.0.mir