1
Fork 0

move the is_field_list_non_exhaustive flag to VariantDef

This completely splits the IS_NON_EXHAUSTIVE flag. No functional
changes intended.
This commit is contained in:
Ariel Ben-Yehuda 2018-09-01 19:10:26 +03:00
parent 993e7e2622
commit ae2ad30bf1
9 changed files with 108 additions and 73 deletions

View file

@ -344,13 +344,13 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::AdtFlags {
} }
} }
impl_stable_hash_for!(struct ty::VariantDef { impl<'a> HashStable<StableHashingContext<'a>> for ty::VariantFlags {
did, fn hash_stable<W: StableHasherResult>(&self,
name, _: &mut StableHashingContext<'a>,
discr, hasher: &mut StableHasher<W>) {
fields, std_hash::Hash::hash(self, hasher);
ctor_kind }
}); }
impl_stable_hash_for!(enum ty::VariantDiscr { impl_stable_hash_for!(enum ty::VariantDiscr {
Explicit(def_id), Explicit(def_id),

View file

@ -1691,12 +1691,17 @@ bitflags! {
const IS_FUNDAMENTAL = 1 << 2; const IS_FUNDAMENTAL = 1 << 2;
const IS_UNION = 1 << 3; const IS_UNION = 1 << 3;
const IS_BOX = 1 << 4; const IS_BOX = 1 << 4;
/// Indicates whether this abstract data type will be expanded on in future (new /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
/// fields/variants) and as such, whether downstream crates must match exhaustively on the /// (i.e., this flag is never set unless this ADT is an enum).
/// fields/variants of this data type. const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 5;
/// }
/// See RFC 2008 (<https://github.com/rust-lang/rfcs/pull/2008>). }
const IS_NON_EXHAUSTIVE = 1 << 5;
bitflags! {
pub struct VariantFlags: u32 {
const NO_VARIANT_FLAGS = 0;
/// Indicates whether the field list of this variant is `#[non_exhaustive]`.
const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0;
} }
} }
@ -1709,8 +1714,56 @@ pub struct VariantDef {
pub discr: VariantDiscr, pub discr: VariantDiscr,
pub fields: Vec<FieldDef>, pub fields: Vec<FieldDef>,
pub ctor_kind: CtorKind, pub ctor_kind: CtorKind,
flags: VariantFlags,
} }
impl<'a, 'gcx, 'tcx> VariantDef {
/// Create a new `VariantDef`.
///
/// - `did` is the DefId used for the variant - for tuple-structs, it is the constructor DefId,
/// and for everything else, it is the variant DefId.
/// - `attribute_def_id` is the DefId that has the variant's attributes.
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
did: DefId,
name: Name,
discr: VariantDiscr,
fields: Vec<FieldDef>,
adt_kind: AdtKind,
ctor_kind: CtorKind)
-> Self
{
debug!("VariantDef::new({:?}, {:?}, {:?}, {:?}, {:?}, {:?})", did, name, discr, fields,
adt_kind, ctor_kind);
let mut flags = VariantFlags::NO_VARIANT_FLAGS;
if adt_kind == AdtKind::Struct && tcx.has_attr(did, "non_exhaustive") {
debug!("found non-exhaustive field list for {:?}", did);
flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
}
VariantDef {
did,
name,
discr,
fields,
ctor_kind,
flags
}
}
#[inline]
pub fn is_field_list_non_exhaustive(&self) -> bool {
self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE)
}
}
impl_stable_hash_for!(struct VariantDef {
did,
name,
discr,
fields,
ctor_kind,
flags
});
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum VariantDiscr { pub enum VariantDiscr {
/// Explicit value for this variant, i.e. `X = 123`. /// Explicit value for this variant, i.e. `X = 123`.
@ -1849,7 +1902,7 @@ impl_stable_hash_for!(struct ReprFlags {
/// Represents the repr options provided by the user, /// Represents the repr options provided by the user,
#[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)] #[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
pub struct ReprOptions { pub struct ReprOptions {
pub int: Option<attr::IntType>, pub int: Option<attr::IntType>,
pub align: u32, pub align: u32,
@ -1938,6 +1991,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
kind: AdtKind, kind: AdtKind,
variants: Vec<VariantDef>, variants: Vec<VariantDef>,
repr: ReprOptions) -> Self { repr: ReprOptions) -> Self {
debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
let mut flags = AdtFlags::NO_ADT_FLAGS; let mut flags = AdtFlags::NO_ADT_FLAGS;
let attrs = tcx.get_attrs(did); let attrs = tcx.get_attrs(did);
if attr::contains_name(&attrs, "fundamental") { if attr::contains_name(&attrs, "fundamental") {
@ -1949,8 +2003,9 @@ impl<'a, 'gcx, 'tcx> AdtDef {
if Some(did) == tcx.lang_items().owned_box() { if Some(did) == tcx.lang_items().owned_box() {
flags = flags | AdtFlags::IS_BOX; flags = flags | AdtFlags::IS_BOX;
} }
if tcx.has_attr(did, "non_exhaustive") { if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
flags = flags | AdtFlags::IS_NON_EXHAUSTIVE; debug!("found non-exhaustive variant list for {:?}", did);
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
} }
match kind { match kind {
AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM, AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM,
@ -1981,28 +2036,8 @@ impl<'a, 'gcx, 'tcx> AdtDef {
} }
#[inline] #[inline]
fn is_non_exhaustive(&self) -> bool { pub fn is_variant_list_non_exhaustive(&self) -> bool {
self.flags.intersects(AdtFlags::IS_NON_EXHAUSTIVE) self.flags.intersects(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
}
#[inline]
pub fn is_enum_non_exhaustive(&self) -> bool {
match self.adt_kind() {
AdtKind::Enum => self.is_non_exhaustive(),
AdtKind::Struct | AdtKind::Union => {
bug!("is_non_exhaustive_enum called on non-enum `{:?}`", self);
}
}
}
#[inline]
pub fn is_univariant_non_exhaustive(&self) -> bool {
match self.adt_kind() {
AdtKind::Struct | AdtKind::Union => self.is_non_exhaustive(),
AdtKind::Enum => {
bug!("is_non_exhaustive_enum called on non-enum `{:?}`", self);
}
}
} }
/// Returns the kind of the ADT - Struct or Enum. /// Returns the kind of the ADT - Struct or Enum.
@ -2017,19 +2052,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
} }
} }
/// Return whether `variant` is non-exhaustive as a *struct* (i.e., whether
/// it can have additional fields).
pub fn is_variant_non_exhaustive(&self, _variant: &ty::VariantDef) -> bool {
match self.adt_kind() {
// A struct is non-exhaustive if it has a `#[non_exhaustive]` attribute.
AdtKind::Struct => self.is_non_exhaustive(),
// At this moment, all enum variants are exhaustive.
AdtKind::Enum => false,
// All unions are "exhaustive", as far as that makes sense.
AdtKind::Union => false,
}
}
pub fn descr(&self) -> &'static str { pub fn descr(&self) -> &'static str {
match self.adt_kind() { match self.adt_kind() {
AdtKind::Struct => "struct", AdtKind::Struct => "struct",

View file

@ -507,7 +507,13 @@ impl<'a, 'tcx> CrateMetadata {
self.def_path_table.def_path_hash(item_id)) self.def_path_table.def_path_hash(item_id))
} }
fn get_variant(&self, item: &Entry, index: DefIndex) -> ty::VariantDef { fn get_variant(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
item: &Entry,
index: DefIndex,
adt_kind: ty::AdtKind)
-> ty::VariantDef
{
let data = match item.kind { let data = match item.kind {
EntryKind::Variant(data) | EntryKind::Variant(data) |
EntryKind::Struct(data, _) | EntryKind::Struct(data, _) |
@ -515,10 +521,12 @@ impl<'a, 'tcx> CrateMetadata {
_ => bug!(), _ => bug!(),
}; };
ty::VariantDef { ty::VariantDef::new(
did: self.local_def_id(data.struct_ctor.unwrap_or(index)), tcx,
name: self.item_name(index).as_symbol(), self.local_def_id(data.struct_ctor.unwrap_or(index)),
fields: item.children.decode(self).map(|index| { self.item_name(index).as_symbol(),
data.discr,
item.children.decode(self).map(|index| {
let f = self.entry(index); let f = self.entry(index);
ty::FieldDef { ty::FieldDef {
did: self.local_def_id(index), did: self.local_def_id(index),
@ -526,9 +534,9 @@ impl<'a, 'tcx> CrateMetadata {
vis: f.visibility.decode(self) vis: f.visibility.decode(self)
} }
}).collect(), }).collect(),
discr: data.discr, adt_kind,
ctor_kind: data.ctor_kind, data.ctor_kind
} )
} }
pub fn get_adt_def(&self, pub fn get_adt_def(&self,
@ -549,11 +557,11 @@ impl<'a, 'tcx> CrateMetadata {
item.children item.children
.decode(self) .decode(self)
.map(|index| { .map(|index| {
self.get_variant(&self.entry(index), index) self.get_variant(tcx, &self.entry(index), index, kind)
}) })
.collect() .collect()
} else { } else {
vec![self.get_variant(&item, item_id)] vec![self.get_variant(tcx, &item, item_id, kind)]
}; };
tcx.alloc_adt_def(did, kind, variants, repr) tcx.alloc_adt_def(did, kind, variants, repr)

View file

@ -740,7 +740,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
// If the structure is marked as non_exhaustive then lower the visibility // If the structure is marked as non_exhaustive then lower the visibility
// to within the crate. // to within the crate.
if adt_def.is_univariant_non_exhaustive() && ctor_vis == ty::Visibility::Public { if adt_def.non_enum_variant().is_field_list_non_exhaustive() &&
ctor_vis == ty::Visibility::Public
{
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
} }

View file

@ -381,7 +381,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
match ty.sty { match ty.sty {
ty::Adt(adt_def, ..) => adt_def.is_enum() && adt_def.is_enum_non_exhaustive(), ty::Adt(adt_def, ..) => adt_def.is_variant_list_non_exhaustive(),
_ => false, _ => false,
} }
} }

View file

@ -684,7 +684,7 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
// visibility to within the crate. // visibility to within the crate.
let struct_def_id = self.tcx.hir.get_parent_did(node_id); let struct_def_id = self.tcx.hir.get_parent_did(node_id);
let adt_def = self.tcx.adt_def(struct_def_id); let adt_def = self.tcx.adt_def(struct_def_id);
if adt_def.is_univariant_non_exhaustive() if adt_def.non_enum_variant().is_field_list_non_exhaustive()
&& ctor_vis == ty::Visibility::Public && ctor_vis == ty::Visibility::Public
{ {
ctor_vis = ty::Visibility::Restricted( ctor_vis = ty::Visibility::Restricted(

View file

@ -948,7 +948,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
} }
// Require `..` if struct has non_exhaustive attribute. // Require `..` if struct has non_exhaustive attribute.
if adt.is_variant_non_exhaustive(variant) && !adt.did.is_local() && !etc { if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc {
span_err!(tcx.sess, span, E0638, span_err!(tcx.sess, span, E0638,
"`..` required with {} marked as non-exhaustive", "`..` required with {} marked as non-exhaustive",
kind_name); kind_name);

View file

@ -3654,7 +3654,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Prohibit struct expressions when non exhaustive flag is set. // Prohibit struct expressions when non exhaustive flag is set.
let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type"); let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type");
if !adt.did.is_local() && adt.is_variant_non_exhaustive(variant) { if !adt.did.is_local() && variant.is_field_list_non_exhaustive() {
span_err!(self.tcx.sess, expr.span, E0639, span_err!(self.tcx.sess, expr.span, E0639,
"cannot create non-exhaustive {} using struct expression", "cannot create non-exhaustive {} using struct expression",
adt.variant_descr()); adt.variant_descr());

View file

@ -548,12 +548,13 @@ fn convert_enum_variant_types<'a, 'tcx>(
} }
} }
fn convert_struct_variant<'a, 'tcx>( fn convert_variant<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
did: DefId, did: DefId,
name: ast::Name, name: ast::Name,
discr: ty::VariantDiscr, discr: ty::VariantDiscr,
def: &hir::VariantData, def: &hir::VariantData,
adt_kind: ty::AdtKind
) -> ty::VariantDef { ) -> ty::VariantDef {
let mut seen_fields: FxHashMap<ast::Ident, Span> = FxHashMap(); let mut seen_fields: FxHashMap<ast::Ident, Span> = FxHashMap();
let node_id = tcx.hir.as_local_node_id(did).unwrap(); let node_id = tcx.hir.as_local_node_id(did).unwrap();
@ -584,13 +585,13 @@ fn convert_struct_variant<'a, 'tcx>(
} }
}) })
.collect(); .collect();
ty::VariantDef { ty::VariantDef::new(tcx,
did, did,
name, name,
discr, discr,
fields, fields,
ctor_kind: CtorKind::from_hir(def), adt_kind,
} CtorKind::from_hir(def))
} }
fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::AdtDef { fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::AdtDef {
@ -621,7 +622,7 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad
}; };
distance_from_explicit += 1; distance_from_explicit += 1;
convert_struct_variant(tcx, did, v.node.name, discr, &v.node.data) convert_variant(tcx, did, v.node.name, discr, &v.node.data, AdtKind::Enum)
}) })
.collect(), .collect(),
) )
@ -635,23 +636,25 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad
}; };
( (
AdtKind::Struct, AdtKind::Struct,
vec![convert_struct_variant( vec![convert_variant(
tcx, tcx,
ctor_id.unwrap_or(def_id), ctor_id.unwrap_or(def_id),
item.name, item.name,
ty::VariantDiscr::Relative(0), ty::VariantDiscr::Relative(0),
def, def,
AdtKind::Struct
)], )],
) )
} }
ItemKind::Union(ref def, _) => ( ItemKind::Union(ref def, _) => (
AdtKind::Union, AdtKind::Union,
vec![convert_struct_variant( vec![convert_variant(
tcx, tcx,
def_id, def_id,
item.name, item.name,
ty::VariantDiscr::Relative(0), ty::VariantDiscr::Relative(0),
def, def,
AdtKind::Union
)], )],
), ),
_ => bug!(), _ => bug!(),