Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/data/adt.rs')
| -rw-r--r-- | crates/hir-def/src/data/adt.rs | 489 |
1 files changed, 0 insertions, 489 deletions
diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs deleted file mode 100644 index c94622016d..0000000000 --- a/crates/hir-def/src/data/adt.rs +++ /dev/null @@ -1,489 +0,0 @@ -//! Defines hir-level representation of structs, enums and unions - -use base_db::CrateId; -use bitflags::bitflags; -use cfg::CfgOptions; -use either::Either; - -use hir_expand::name::Name; -use intern::sym; -use la_arena::Arena; -use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions}; -use rustc_hashes::Hash64; -use triomphe::Arc; -use tt::iter::TtElement; - -use crate::{ - builtin_type::{BuiltinInt, BuiltinUint}, - db::DefDatabase, - hir::Expr, - item_tree::{ - AttrOwner, Field, FieldParent, FieldsShape, ItemTree, ModItem, RawVisibilityId, TreeId, - }, - lang_item::LangItem, - nameres::diagnostics::{DefDiagnostic, DefDiagnostics}, - tt::{Delimiter, DelimiterKind, Leaf, TopSubtree}, - type_ref::{TypeRefId, TypesMap}, - visibility::RawVisibility, - EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId, -}; - -/// Note that we use `StructData` for unions as well! -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StructData { - pub name: Name, - pub variant_data: Arc<VariantData>, - pub repr: Option<ReprOptions>, - pub visibility: RawVisibility, - pub flags: StructFlags, -} - -bitflags! { - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub struct StructFlags: u8 { - const NO_FLAGS = 0; - /// Indicates whether the struct is `PhantomData`. - const IS_PHANTOM_DATA = 1 << 2; - /// Indicates whether the struct has a `#[fundamental]` attribute. - const IS_FUNDAMENTAL = 1 << 3; - // FIXME: should this be a flag? - /// Indicates whether the struct has a `#[rustc_has_incoherent_inherent_impls]` attribute. - const IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL = 1 << 4; - /// Indicates whether this struct is `Box`. - const IS_BOX = 1 << 5; - /// Indicates whether this struct is `ManuallyDrop`. - const IS_MANUALLY_DROP = 1 << 6; - /// Indicates whether this struct is `UnsafeCell`. - const IS_UNSAFE_CELL = 1 << 7; - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnumData { - pub name: Name, - pub variants: Box<[(EnumVariantId, Name)]>, - pub repr: Option<ReprOptions>, - pub visibility: RawVisibility, - pub rustc_has_incoherent_inherent_impls: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnumVariantData { - pub name: Name, - pub variant_data: Arc<VariantData>, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum VariantData { - Record { fields: Arena<FieldData>, types_map: Arc<TypesMap> }, - Tuple { fields: Arena<FieldData>, types_map: Arc<TypesMap> }, - Unit, -} - -/// A single field of an enum variant or struct -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FieldData { - pub name: Name, - pub type_ref: TypeRefId, - pub visibility: RawVisibility, -} - -fn repr_from_value( - db: &dyn DefDatabase, - krate: CrateId, - item_tree: &ItemTree, - of: AttrOwner, -) -> Option<ReprOptions> { - item_tree.attrs(db, krate, of).by_key(&sym::repr).tt_values().find_map(parse_repr_tt) -} - -fn parse_repr_tt(tt: &TopSubtree) -> Option<ReprOptions> { - match tt.top_subtree().delimiter { - Delimiter { kind: DelimiterKind::Parenthesis, .. } => {} - _ => return None, - } - - let mut flags = ReprFlags::empty(); - let mut int = None; - let mut max_align: Option<Align> = None; - let mut min_pack: Option<Align> = None; - - let mut tts = tt.iter(); - while let Some(tt) = tts.next() { - if let TtElement::Leaf(Leaf::Ident(ident)) = tt { - flags.insert(match &ident.sym { - s if *s == sym::packed => { - let pack = if let Some(TtElement::Subtree(_, mut tt_iter)) = tts.peek() { - tts.next(); - if let Some(TtElement::Leaf(Leaf::Literal(lit))) = tt_iter.next() { - lit.symbol.as_str().parse().unwrap_or_default() - } else { - 0 - } - } else { - 0 - }; - let pack = Align::from_bytes(pack).unwrap_or(Align::ONE); - min_pack = - Some(if let Some(min_pack) = min_pack { min_pack.min(pack) } else { pack }); - ReprFlags::empty() - } - s if *s == sym::align => { - if let Some(TtElement::Subtree(_, mut tt_iter)) = tts.peek() { - tts.next(); - if let Some(TtElement::Leaf(Leaf::Literal(lit))) = tt_iter.next() { - if let Ok(align) = lit.symbol.as_str().parse() { - let align = Align::from_bytes(align).ok(); - max_align = max_align.max(align); - } - } - } - ReprFlags::empty() - } - s if *s == sym::C => ReprFlags::IS_C, - s if *s == sym::transparent => ReprFlags::IS_TRANSPARENT, - s if *s == sym::simd => ReprFlags::IS_SIMD, - repr => { - if let Some(builtin) = BuiltinInt::from_suffix_sym(repr) - .map(Either::Left) - .or_else(|| BuiltinUint::from_suffix_sym(repr).map(Either::Right)) - { - int = Some(match builtin { - Either::Left(bi) => match bi { - BuiltinInt::Isize => IntegerType::Pointer(true), - BuiltinInt::I8 => IntegerType::Fixed(Integer::I8, true), - BuiltinInt::I16 => IntegerType::Fixed(Integer::I16, true), - BuiltinInt::I32 => IntegerType::Fixed(Integer::I32, true), - BuiltinInt::I64 => IntegerType::Fixed(Integer::I64, true), - BuiltinInt::I128 => IntegerType::Fixed(Integer::I128, true), - }, - Either::Right(bu) => match bu { - BuiltinUint::Usize => IntegerType::Pointer(false), - BuiltinUint::U8 => IntegerType::Fixed(Integer::I8, false), - BuiltinUint::U16 => IntegerType::Fixed(Integer::I16, false), - BuiltinUint::U32 => IntegerType::Fixed(Integer::I32, false), - BuiltinUint::U64 => IntegerType::Fixed(Integer::I64, false), - BuiltinUint::U128 => IntegerType::Fixed(Integer::I128, false), - }, - }); - } - ReprFlags::empty() - } - }) - } - } - - Some(ReprOptions { - int, - align: max_align, - pack: min_pack, - flags, - field_shuffle_seed: Hash64::ZERO, - }) -} - -impl StructData { - #[inline] - pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { - db.struct_data_with_diagnostics(id).0 - } - - pub(crate) fn struct_data_with_diagnostics_query( - db: &dyn DefDatabase, - id: StructId, - ) -> (Arc<StructData>, DefDiagnostics) { - let loc = id.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); - let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); - - let mut flags = StructFlags::NO_FLAGS; - if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() { - flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL; - } - if attrs.by_key(&sym::fundamental).exists() { - flags |= StructFlags::IS_FUNDAMENTAL; - } - if let Some(lang) = attrs.lang_item() { - match lang { - LangItem::PhantomData => flags |= StructFlags::IS_PHANTOM_DATA, - LangItem::OwnedBox => flags |= StructFlags::IS_BOX, - LangItem::ManuallyDrop => flags |= StructFlags::IS_MANUALLY_DROP, - LangItem::UnsafeCell => flags |= StructFlags::IS_UNSAFE_CELL, - _ => (), - } - } - - let strukt = &item_tree[loc.id.value]; - let (fields, diagnostics) = lower_fields( - db, - krate, - loc.container.local_id, - loc.id.tree_id(), - &item_tree, - &db.crate_graph()[krate].cfg_options, - FieldParent::Struct(loc.id.value), - &strukt.fields, - None, - ); - let types_map = strukt.types_map.clone(); - ( - Arc::new(StructData { - name: strukt.name.clone(), - variant_data: Arc::new(match strukt.shape { - FieldsShape::Record => VariantData::Record { fields, types_map }, - FieldsShape::Tuple => VariantData::Tuple { fields, types_map }, - FieldsShape::Unit => VariantData::Unit, - }), - repr, - visibility: item_tree[strukt.visibility].clone(), - flags, - }), - DefDiagnostics::new(diagnostics), - ) - } - - #[inline] - pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { - db.union_data_with_diagnostics(id).0 - } - - pub(crate) fn union_data_with_diagnostics_query( - db: &dyn DefDatabase, - id: UnionId, - ) -> (Arc<StructData>, DefDiagnostics) { - let loc = id.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); - let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); - let mut flags = StructFlags::NO_FLAGS; - if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() { - flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL; - } - if attrs.by_key(&sym::fundamental).exists() { - flags |= StructFlags::IS_FUNDAMENTAL; - } - - let union = &item_tree[loc.id.value]; - let (fields, diagnostics) = lower_fields( - db, - krate, - loc.container.local_id, - loc.id.tree_id(), - &item_tree, - &db.crate_graph()[krate].cfg_options, - FieldParent::Union(loc.id.value), - &union.fields, - None, - ); - let types_map = union.types_map.clone(); - ( - Arc::new(StructData { - name: union.name.clone(), - variant_data: Arc::new(VariantData::Record { fields, types_map }), - repr, - visibility: item_tree[union.visibility].clone(), - flags, - }), - DefDiagnostics::new(diagnostics), - ) - } -} - -impl EnumData { - pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> { - let loc = e.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into()); - let rustc_has_incoherent_inherent_impls = item_tree - .attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()) - .by_key(&sym::rustc_has_incoherent_inherent_impls) - .exists(); - - let enum_ = &item_tree[loc.id.value]; - - Arc::new(EnumData { - name: enum_.name.clone(), - variants: loc.container.def_map(db).enum_definitions[&e] - .iter() - .map(|&id| (id, item_tree[id.lookup(db).id.value].name.clone())) - .collect(), - repr, - visibility: item_tree[enum_.visibility].clone(), - rustc_has_incoherent_inherent_impls, - }) - } - - pub fn variant(&self, name: &Name) -> Option<EnumVariantId> { - let &(id, _) = self.variants.iter().find(|(_id, n)| n == name)?; - Some(id) - } - - pub fn variant_body_type(&self) -> IntegerType { - match self.repr { - Some(ReprOptions { int: Some(builtin), .. }) => builtin, - _ => IntegerType::Pointer(true), - } - } - - // [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448) - pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool { - self.variants.iter().all(|(v, _)| { - // The condition check order is slightly modified from rustc - // to improve performance by early returning with relatively fast checks - let variant = &db.enum_variant_data(*v).variant_data; - if !variant.fields().is_empty() { - return false; - } - // The outer if condition is whether this variant has const ctor or not - if !matches!(variant.kind(), StructKind::Unit) { - let body = db.body((*v).into()); - // A variant with explicit discriminant - if body.exprs[body.body_expr] != Expr::Missing { - return false; - } - } - true - }) - } -} - -impl EnumVariantData { - #[inline] - pub(crate) fn enum_variant_data_query( - db: &dyn DefDatabase, - e: EnumVariantId, - ) -> Arc<EnumVariantData> { - db.enum_variant_data_with_diagnostics(e).0 - } - - pub(crate) fn enum_variant_data_with_diagnostics_query( - db: &dyn DefDatabase, - e: EnumVariantId, - ) -> (Arc<EnumVariantData>, DefDiagnostics) { - let loc = e.lookup(db); - let container = loc.parent.lookup(db).container; - let krate = container.krate; - let item_tree = loc.id.item_tree(db); - let variant = &item_tree[loc.id.value]; - - let (fields, diagnostics) = lower_fields( - db, - krate, - container.local_id, - loc.id.tree_id(), - &item_tree, - &db.crate_graph()[krate].cfg_options, - FieldParent::Variant(loc.id.value), - &variant.fields, - Some(item_tree[loc.parent.lookup(db).id.value].visibility), - ); - let types_map = variant.types_map.clone(); - - ( - Arc::new(EnumVariantData { - name: variant.name.clone(), - variant_data: Arc::new(match variant.shape { - FieldsShape::Record => VariantData::Record { fields, types_map }, - FieldsShape::Tuple => VariantData::Tuple { fields, types_map }, - FieldsShape::Unit => VariantData::Unit, - }), - }), - DefDiagnostics::new(diagnostics), - ) - } -} - -impl VariantData { - pub fn fields(&self) -> &Arena<FieldData> { - const EMPTY: &Arena<FieldData> = &Arena::new(); - match &self { - VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => fields, - _ => EMPTY, - } - } - - pub fn types_map(&self) -> &TypesMap { - match &self { - VariantData::Record { types_map, .. } | VariantData::Tuple { types_map, .. } => { - types_map - } - VariantData::Unit => TypesMap::EMPTY, - } - } - - // FIXME: Linear lookup - pub fn field(&self, name: &Name) -> Option<LocalFieldId> { - self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None }) - } - - pub fn kind(&self) -> StructKind { - match self { - VariantData::Record { .. } => StructKind::Record, - VariantData::Tuple { .. } => StructKind::Tuple, - VariantData::Unit => StructKind::Unit, - } - } - - #[allow(clippy::self_named_constructors)] - pub(crate) fn variant_data(db: &dyn DefDatabase, id: VariantId) -> Arc<VariantData> { - match id { - VariantId::StructId(it) => db.struct_data(it).variant_data.clone(), - VariantId::EnumVariantId(it) => db.enum_variant_data(it).variant_data.clone(), - VariantId::UnionId(it) => db.union_data(it).variant_data.clone(), - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum StructKind { - Tuple, - Record, - Unit, -} - -fn lower_fields( - db: &dyn DefDatabase, - krate: CrateId, - container: LocalModuleId, - tree_id: TreeId, - item_tree: &ItemTree, - cfg_options: &CfgOptions, - parent: FieldParent, - fields: &[Field], - override_visibility: Option<RawVisibilityId>, -) -> (Arena<FieldData>, Vec<DefDiagnostic>) { - let mut diagnostics = Vec::new(); - let mut arena = Arena::new(); - for (idx, field) in fields.iter().enumerate() { - let attr_owner = AttrOwner::make_field_indexed(parent, idx); - let attrs = item_tree.attrs(db, krate, attr_owner); - if attrs.is_cfg_enabled(cfg_options) { - arena.alloc(lower_field(item_tree, field, override_visibility)); - } else { - diagnostics.push(DefDiagnostic::unconfigured_code( - container, - tree_id, - attr_owner, - attrs.cfg().unwrap(), - cfg_options.clone(), - )) - } - } - (arena, diagnostics) -} - -fn lower_field( - item_tree: &ItemTree, - field: &Field, - override_visibility: Option<RawVisibilityId>, -) -> FieldData { - FieldData { - name: field.name.clone(), - type_ref: field.type_ref, - visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), - } -} |