Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/next_solver/interner.rs')
-rw-r--r--crates/hir-ty/src/next_solver/interner.rs359
1 files changed, 128 insertions, 231 deletions
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index b8b8d15347..fc83ebc625 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -4,25 +4,24 @@ use std::{fmt, ops::ControlFlow};
use intern::{Interned, InternedRef, InternedSliceRef, impl_internable};
use macros::GenericTypeVisitable;
+use rustc_abi::ReprOptions;
use rustc_ast_ir::{FloatTy, IntTy, UintTy};
pub use tls_cache::clear_tls_solver_cache;
pub use tls_db::{attach_db, attach_db_allow_change, with_attached_db};
use base_db::Crate;
use hir_def::{
- AdtId, CallableDefId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, HasModule,
+ AdtId, CallableDefId, DefWithBodyId, EnumId, ExpressionStoreOwnerId, HasModule,
ItemContainerId, StructId, UnionId, VariantId,
attrs::AttrFlags,
expr_store::{Body, ExpressionStore},
hir::{ClosureKind as HirClosureKind, CoroutineKind as HirCoroutineKind},
lang_item::LangItems,
signatures::{
- EnumSignature, FieldData, FnFlags, FunctionSignature, ImplFlags, ImplSignature,
+ EnumFlags, EnumSignature, FnFlags, FunctionSignature, ImplFlags, ImplSignature,
StructFlags, StructSignature, TraitFlags, TraitSignature, UnionSignature,
},
};
-use la_arena::Idx;
-use rustc_abi::{ReprFlags, ReprOptions};
use rustc_hash::FxHashSet;
use rustc_index::bit_set::DenseBitSet;
use rustc_type_ir::{
@@ -419,266 +418,167 @@ pub struct AllocId;
interned_slice!(VariancesOfStorage, VariancesOf, StoredVariancesOf, variances, Variance, Variance);
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct VariantIdx(usize);
-
-// FIXME: could/should store actual data?
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub enum VariantDef {
- Struct(StructId),
- Union(UnionId),
- Enum(EnumVariantId),
-}
-
-impl VariantDef {
- pub fn id(&self) -> VariantId {
- match self {
- VariantDef::Struct(struct_id) => VariantId::StructId(*struct_id),
- VariantDef::Union(union_id) => VariantId::UnionId(*union_id),
- VariantDef::Enum(enum_variant_id) => VariantId::EnumVariantId(*enum_variant_id),
- }
- }
-
- pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Idx<FieldData>, FieldData)> {
- let id: VariantId = match self {
- VariantDef::Struct(it) => (*it).into(),
- VariantDef::Union(it) => (*it).into(),
- VariantDef::Enum(it) => (*it).into(),
- };
- id.fields(db).fields().iter().map(|(id, data)| (id, data.clone())).collect()
+bitflags::bitflags! {
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+ struct AdtFlags: u8 {
+ const IS_FUNDAMENTAL = 1 << 0;
+ const IS_PACKED = 1 << 1;
+ const HAS_REPR = 1 << 2;
+ const IS_PHANTOM_DATA = 1 << 3;
+ const IS_MANUALLY_DROP = 1 << 4;
+ const IS_BOX = 1 << 5;
}
}
-/*
-/// Definition of a variant -- a struct's fields or an enum variant.
-#[derive(Debug, HashStable, TyEncodable, TyDecodable)]
-pub struct VariantDef {
- /// `DefId` that identifies the variant itself.
- /// If this variant belongs to a struct or union, then this is a copy of its `DefId`.
- pub def_id: DefId,
- /// `DefId` that identifies the variant's constructor.
- /// If this variant is a struct variant, then this is `None`.
- pub ctor: Option<(CtorKind, DefId)>,
- /// Variant or struct name, maybe empty for anonymous adt (struct or union).
- pub name: Symbol,
- /// Discriminant of this variant.
- pub discr: VariantDiscr,
- /// Fields of this variant.
- pub fields: IndexVec<FieldIdx, FieldDef>,
- /// The error guarantees from parser, if any.
- tainted: Option<ErrorGuaranteed>,
- /// Flags of the variant (e.g. is field list non-exhaustive)?
- flags: VariantFlags,
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+enum AdtDefInner {
+ Struct { id: StructId, flags: AdtFlags },
+ Union { id: UnionId, flags: AdtFlags },
+ Enum { id: EnumId, flags: AdtFlags },
}
-*/
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct AdtFlags {
- is_enum: bool,
- is_union: bool,
- is_struct: bool,
- is_phantom_data: bool,
- is_fundamental: bool,
- is_box: bool,
- is_manually_drop: bool,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct AdtDefInner {
- pub id: AdtId,
- variants: Vec<(VariantIdx, VariantDef)>,
- flags: AdtFlags,
- repr: ReprOptions,
-}
-
-// We're gonna cheat a little bit and implement `Hash` on only the `DefId` and
-// accept there might be collisions for def ids from different crates (or across
-// different tests, oh my).
-impl std::hash::Hash for AdtDefInner {
- #[inline]
- fn hash<H: std::hash::Hasher>(&self, s: &mut H) {
- self.id.hash(s)
- }
-}
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct AdtDef(AdtDefInner);
-#[salsa::interned(no_lifetime, constructor = new_)]
-pub struct AdtDef {
- #[returns(ref)]
- data_: AdtDefInner,
-}
+const _: () = assert!(size_of::<AdtDef>() == 12);
impl AdtDef {
pub fn new<'db>(def_id: AdtId, interner: DbInterner<'db>) -> Self {
let db = interner.db();
- let (flags, variants, repr) = match def_id {
- AdtId::StructId(struct_id) => {
- let data = StructSignature::of(db, struct_id);
-
- let flags = AdtFlags {
- is_enum: false,
- is_union: false,
- is_struct: true,
- is_phantom_data: data.flags.contains(StructFlags::IS_PHANTOM_DATA),
- is_fundamental: data.flags.contains(StructFlags::FUNDAMENTAL),
- is_box: data.flags.contains(StructFlags::IS_BOX),
- is_manually_drop: data.flags.contains(StructFlags::IS_MANUALLY_DROP),
- };
-
- let variants = vec![(VariantIdx(0), VariantDef::Struct(struct_id))];
-
- let data_repr = data.repr(db, struct_id);
- let mut repr_flags = ReprFlags::empty();
- if flags.is_box {
- repr_flags.insert(ReprFlags::IS_LINEAR);
+ let inner = match def_id {
+ AdtId::StructId(id) => {
+ let data = StructSignature::of(db, id);
+ let mut flags = AdtFlags::empty();
+ if data.flags.contains(StructFlags::FUNDAMENTAL) {
+ flags.insert(AdtFlags::IS_FUNDAMENTAL);
}
- if data_repr.is_some_and(|r| r.c()) {
- repr_flags.insert(ReprFlags::IS_C);
+ if data.flags.contains(StructFlags::IS_PHANTOM_DATA) {
+ flags.insert(AdtFlags::IS_PHANTOM_DATA);
}
- if data_repr.is_some_and(|r| r.simd()) {
- repr_flags.insert(ReprFlags::IS_SIMD);
+ if data.flags.contains(StructFlags::IS_MANUALLY_DROP) {
+ flags.insert(AdtFlags::IS_MANUALLY_DROP);
}
- let repr = ReprOptions {
- align: data_repr.and_then(|r| r.align),
- pack: data_repr.and_then(|r| r.pack),
- int: data_repr.and_then(|r| r.int),
- flags: repr_flags,
- ..ReprOptions::default()
- };
-
- (flags, variants, repr)
- }
- AdtId::UnionId(union_id) => {
- let flags = AdtFlags {
- is_enum: false,
- is_union: true,
- is_struct: false,
- is_phantom_data: false,
- is_fundamental: false,
- is_box: false,
- is_manually_drop: false,
- };
-
- let variants = vec![(VariantIdx(0), VariantDef::Union(union_id))];
-
- let data_repr = AttrFlags::repr(db, union_id.into());
- let mut repr_flags = ReprFlags::empty();
- if flags.is_box {
- repr_flags.insert(ReprFlags::IS_LINEAR);
+ if data.flags.contains(StructFlags::IS_BOX) {
+ flags.insert(AdtFlags::IS_BOX);
}
- if data_repr.is_some_and(|r| r.c()) {
- repr_flags.insert(ReprFlags::IS_C);
+ if data.flags.contains(StructFlags::HAS_REPR) {
+ flags.insert(AdtFlags::HAS_REPR);
+ if data.repr(db, id).is_some_and(|repr| repr.packed()) {
+ flags.insert(AdtFlags::IS_PACKED);
+ }
}
- if data_repr.is_some_and(|r| r.simd()) {
- repr_flags.insert(ReprFlags::IS_SIMD);
+ AdtDefInner::Struct { id, flags }
+ }
+ AdtId::UnionId(id) => {
+ let data = UnionSignature::of(db, id);
+ let mut flags = AdtFlags::empty();
+ if data.flags.contains(StructFlags::FUNDAMENTAL) {
+ flags.insert(AdtFlags::IS_FUNDAMENTAL);
}
- let repr = ReprOptions {
- align: data_repr.and_then(|r| r.align),
- pack: data_repr.and_then(|r| r.pack),
- int: data_repr.and_then(|r| r.int),
- flags: repr_flags,
- ..ReprOptions::default()
- };
-
- (flags, variants, repr)
- }
- AdtId::EnumId(enum_id) => {
- let flags = AdtFlags {
- is_enum: true,
- is_union: false,
- is_struct: false,
- is_phantom_data: false,
- is_fundamental: false,
- is_box: false,
- is_manually_drop: false,
- };
-
- let variants = enum_id
- .enum_variants(db)
- .variants
- .iter()
- .enumerate()
- .map(|(idx, v)| (VariantIdx(idx), v))
- .map(|(idx, v)| (idx, VariantDef::Enum(v.0)))
- .collect();
-
- let data_repr = AttrFlags::repr(db, enum_id.into());
-
- let mut repr_flags = ReprFlags::empty();
- if flags.is_box {
- repr_flags.insert(ReprFlags::IS_LINEAR);
+ if data.flags.contains(StructFlags::HAS_REPR) {
+ flags.insert(AdtFlags::HAS_REPR);
+ if data.repr(db, id).is_some_and(|repr| repr.packed()) {
+ flags.insert(AdtFlags::IS_PACKED);
+ }
}
- if data_repr.is_some_and(|r| r.c()) {
- repr_flags.insert(ReprFlags::IS_C);
+ AdtDefInner::Union { id, flags }
+ }
+ AdtId::EnumId(id) => {
+ let data = EnumSignature::of(db, id);
+ let mut flags = AdtFlags::empty();
+ if data.flags.contains(EnumFlags::FUNDAMENTAL) {
+ flags.insert(AdtFlags::IS_FUNDAMENTAL);
}
- if data_repr.is_some_and(|r| r.simd()) {
- repr_flags.insert(ReprFlags::IS_SIMD);
+ if data.flags.contains(EnumFlags::HAS_REPR) {
+ flags.insert(AdtFlags::HAS_REPR);
+ if data.repr(db, id).is_some_and(|repr| repr.packed()) {
+ flags.insert(AdtFlags::IS_PACKED);
+ }
}
-
- let repr = ReprOptions {
- align: data_repr.and_then(|r| r.align),
- pack: data_repr.and_then(|r| r.pack),
- int: data_repr.and_then(|r| r.int),
- flags: repr_flags,
- ..ReprOptions::default()
- };
-
- (flags, variants, repr)
+ AdtDefInner::Enum { id, flags }
}
};
+ AdtDef(inner)
+ }
- AdtDef::new_(db, AdtDefInner { id: def_id, variants, flags, repr })
+ #[inline]
+ pub fn def_id(self) -> AdtId {
+ match self.0 {
+ AdtDefInner::Struct { id, .. } => AdtId::StructId(id),
+ AdtDefInner::Union { id, .. } => AdtId::UnionId(id),
+ AdtDefInner::Enum { id, .. } => AdtId::EnumId(id),
+ }
}
- pub fn inner(&self) -> &AdtDefInner {
- crate::with_attached_db(|db| {
- let inner = self.data_(db);
- // SAFETY: ¯\_(ツ)_/¯
- unsafe { std::mem::transmute(inner) }
- })
+ #[inline]
+ fn flags(self) -> AdtFlags {
+ match self.0 {
+ AdtDefInner::Struct { flags, .. }
+ | AdtDefInner::Union { flags, .. }
+ | AdtDefInner::Enum { flags, .. } => flags,
+ }
}
- pub fn is_enum(&self) -> bool {
- self.inner().flags.is_enum
+ #[inline]
+ pub fn is_struct(self) -> bool {
+ matches!(self.0, AdtDefInner::Struct { .. })
+ }
+
+ #[inline]
+ pub fn is_union(self) -> bool {
+ matches!(self.0, AdtDefInner::Union { .. })
}
- pub fn is_box(&self) -> bool {
- self.inner().flags.is_box
+ #[inline]
+ pub fn is_enum(self) -> bool {
+ matches!(self.0, AdtDefInner::Enum { .. })
}
#[inline]
- pub fn repr(self) -> ReprOptions {
- self.inner().repr
+ pub fn is_box(self) -> bool {
+ matches!(self.0, AdtDefInner::Struct { flags, .. } if flags.contains(AdtFlags::IS_BOX))
}
- /// Asserts this is a struct or union and returns its unique variant.
- pub fn non_enum_variant(self) -> VariantDef {
- assert!(self.inner().flags.is_struct || self.inner().flags.is_union);
- self.inner().variants[0].1.clone()
+ #[inline]
+ pub fn repr(self, db: &dyn HirDatabase) -> ReprOptions {
+ if self.flags().contains(AdtFlags::HAS_REPR) {
+ AttrFlags::repr_assume_has(db, self.def_id()).unwrap_or_default()
+ } else {
+ ReprOptions::default()
+ }
}
}
impl<'db> inherent::AdtDef<DbInterner<'db>> for AdtDef {
fn def_id(self) -> AdtIdWrapper {
- self.inner().id.into()
+ self.def_id().into()
}
fn is_struct(self) -> bool {
- self.inner().flags.is_struct
+ self.is_struct()
}
fn is_phantom_data(self) -> bool {
- self.inner().flags.is_phantom_data
+ matches!(self.0, AdtDefInner::Struct { flags, .. } if flags.contains(AdtFlags::IS_PHANTOM_DATA))
+ }
+
+ fn is_manually_drop(self) -> bool {
+ matches!(self.0, AdtDefInner::Struct { flags, .. } if flags.contains(AdtFlags::IS_MANUALLY_DROP))
+ }
+
+ fn is_packed(self) -> bool {
+ self.flags().contains(AdtFlags::IS_PACKED)
}
fn is_fundamental(self) -> bool {
- self.inner().flags.is_fundamental
+ self.flags().contains(AdtFlags::IS_FUNDAMENTAL)
}
fn struct_tail_ty(
self,
interner: DbInterner<'db>,
) -> Option<EarlyBinder<DbInterner<'db>, Ty<'db>>> {
- let hir_def::AdtId::StructId(struct_id) = self.inner().id else {
+ let hir_def::AdtId::StructId(struct_id) = self.def_id() else {
return None;
};
let id: VariantId = struct_id.into();
@@ -697,7 +597,7 @@ impl<'db> inherent::AdtDef<DbInterner<'db>> for AdtDef {
db.field_types(id).iter().map(|(_, ty)| ty.get().skip_binder()).collect::<Vec<_>>()
};
let field_tys = |_id: VariantId| vec![];
- let tys: Vec<_> = match self.inner().id {
+ let tys: Vec<_> = match self.def_id() {
hir_def::AdtId::StructId(id) => field_tys(id.into()),
hir_def::AdtId::UnionId(id) => field_tys(id.into()),
hir_def::AdtId::EnumId(id) => id
@@ -723,15 +623,7 @@ impl<'db> inherent::AdtDef<DbInterner<'db>> for AdtDef {
}
fn destructor(self, interner: DbInterner<'db>) -> Option<AdtDestructorKind> {
- crate::drop::destructor(interner.db, self.def_id().0).map(|_| AdtDestructorKind::NotConst)
- }
-
- fn is_manually_drop(self) -> bool {
- self.inner().flags.is_manually_drop
- }
-
- fn is_packed(self) -> bool {
- self.repr().packed()
+ crate::drop::destructor(interner.db, self.def_id()).map(|_| AdtDestructorKind::NotConst)
}
fn field_representing_type_info(
@@ -746,17 +638,17 @@ impl<'db> inherent::AdtDef<DbInterner<'db>> for AdtDef {
impl fmt::Debug for AdtDef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- crate::with_attached_db(|db| match self.inner().id {
- AdtId::StructId(struct_id) => {
- let data = StructSignature::of(db, struct_id);
+ crate::with_attached_db(|db| match self.0 {
+ AdtDefInner::Struct { id, .. } => {
+ let data = StructSignature::of(db, id);
f.write_str(data.name.as_str())
}
- AdtId::UnionId(union_id) => {
- let data = UnionSignature::of(db, union_id);
+ AdtDefInner::Union { id, .. } => {
+ let data = UnionSignature::of(db, id);
f.write_str(data.name.as_str())
}
- AdtId::EnumId(enum_id) => {
- let data = EnumSignature::of(db, enum_id);
+ AdtDefInner::Enum { id, .. } => {
+ let data = EnumSignature::of(db, id);
f.write_str(data.name.as_str())
}
})
@@ -1985,13 +1877,18 @@ impl<'db> Interner for DbInterner<'db> {
};
// The last field of the structure has to exist and contain type/const parameters.
- let variant = def.non_enum_variant();
+ let variant = match def.def_id() {
+ AdtId::StructId(id) => VariantId::from(id),
+ AdtId::UnionId(id) => id.into(),
+ AdtId::EnumId(_) => panic!("expected a struct or a union"),
+ };
let fields = variant.fields(self.db());
- let Some((tail_field, prefix_fields)) = fields.split_last() else {
+ let mut prefix_fields = fields.fields().iter();
+ let Some(tail_field) = prefix_fields.next_back() else {
return UnsizingParams(DenseBitSet::new_empty(num_params));
};
- let field_types = self.db().field_types(variant.id());
+ let field_types = self.db().field_types(variant);
let mut unsizing_params = DenseBitSet::new_empty(num_params);
let ty = field_types[tail_field.0].get();
for arg in ty.instantiate_identity().walk() {