Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/lib.rs')
-rw-r--r--crates/hir/src/lib.rs102
1 files changed, 100 insertions, 2 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 24323284e9..9b8c7b900a 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1187,6 +1187,10 @@ impl Struct {
fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
db.struct_data(self.id).variant_data.clone()
}
+
+ pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+ db.attrs(self.id.into()).is_unstable()
+ }
}
impl HasVisibility for Struct {
@@ -1229,6 +1233,10 @@ impl Union {
fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
db.union_data(self.id).variant_data.clone()
}
+
+ pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+ db.attrs(self.id.into()).is_unstable()
+ }
}
impl HasVisibility for Union {
@@ -1318,6 +1326,10 @@ impl Enum {
pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
Adt::from(self).layout(db)
}
+
+ pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+ db.attrs(self.id.into()).is_unstable()
+ }
}
impl HasVisibility for Enum {
@@ -1393,6 +1405,10 @@ impl Variant {
_ => parent_layout,
})
}
+
+ pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+ db.attrs(self.id.into()).is_unstable()
+ }
}
/// Variants inherit visibility from the parent enum.
@@ -2912,7 +2928,7 @@ impl GenericDef {
.collect()
}
- pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
+ pub fn type_or_const_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
let generics = db.generic_params(self.into());
generics
.type_or_consts
@@ -2922,6 +2938,40 @@ impl GenericDef {
})
.collect()
}
+
+ pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> {
+ let generics = db.generic_params(self.into());
+ generics
+ .type_or_consts
+ .iter()
+ .filter_map(|(local_id, data)| match data {
+ hir_def::generics::TypeOrConstParamData::TypeParamData(_) => Some(TypeParam {
+ id: TypeParamId::from_unchecked(TypeOrConstParamId {
+ parent: self.into(),
+ local_id,
+ }),
+ }),
+ hir_def::generics::TypeOrConstParamData::ConstParamData(_) => None,
+ })
+ .collect()
+ }
+
+ pub fn const_params(self, db: &dyn HirDatabase) -> Vec<ConstParam> {
+ let generics = db.generic_params(self.into());
+ generics
+ .type_or_consts
+ .iter()
+ .filter_map(|(local_id, data)| match data {
+ hir_def::generics::TypeOrConstParamData::TypeParamData(_) => None,
+ hir_def::generics::TypeOrConstParamData::ConstParamData(_) => Some(ConstParam {
+ id: ConstParamId::from_unchecked(TypeOrConstParamId {
+ parent: self.into(),
+ local_id,
+ }),
+ }),
+ })
+ .collect()
+ }
}
/// A single local definition.
@@ -3284,12 +3334,16 @@ impl TypeParam {
let ty = generic_arg_from_param(db, self.id.into())?;
let resolver = self.id.parent().resolver(db.upcast());
match ty.data(Interner) {
- GenericArgData::Ty(it) => {
+ GenericArgData::Ty(it) if *it.kind(Interner) != TyKind::Error => {
Some(Type::new_with_resolver_inner(db, &resolver, it.clone()))
}
_ => None,
}
}
+
+ pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
+ db.attrs(GenericParamId::from(self.id).into()).is_unstable()
+ }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -3773,6 +3827,50 @@ impl Type {
matches!(self.ty.kind(Interner), TyKind::Ref(..))
}
+ pub fn contains_reference(&self, db: &dyn HirDatabase) -> bool {
+ return go(db, self.env.krate, &self.ty);
+
+ fn go(db: &dyn HirDatabase, krate: CrateId, ty: &Ty) -> bool {
+ match ty.kind(Interner) {
+ // Reference itself
+ TyKind::Ref(_, _, _) => true,
+
+ // For non-phantom_data adts we check variants/fields as well as generic parameters
+ TyKind::Adt(adt_id, substitution)
+ if !db.struct_datum(krate, *adt_id).flags.phantom_data =>
+ {
+ let adt_datum = &db.struct_datum(krate, *adt_id);
+ let adt_datum_bound =
+ adt_datum.binders.clone().substitute(Interner, substitution);
+ adt_datum_bound
+ .variants
+ .into_iter()
+ .flat_map(|variant| variant.fields.into_iter())
+ .any(|ty| go(db, krate, &ty))
+ || substitution
+ .iter(Interner)
+ .filter_map(|x| x.ty(Interner))
+ .any(|ty| go(db, krate, ty))
+ }
+ // And for `PhantomData<T>`, we check `T`.
+ TyKind::Adt(_, substitution)
+ | TyKind::Tuple(_, substitution)
+ | TyKind::OpaqueType(_, substitution)
+ | TyKind::AssociatedType(_, substitution)
+ | TyKind::FnDef(_, substitution) => substitution
+ .iter(Interner)
+ .filter_map(|x| x.ty(Interner))
+ .any(|ty| go(db, krate, ty)),
+
+ // For `[T]` or `*T` we check `T`
+ TyKind::Array(ty, _) | TyKind::Slice(ty) | TyKind::Raw(_, ty) => go(db, krate, ty),
+
+ // Consider everything else as not reference
+ _ => false,
+ }
+ }
+ }
+
pub fn as_reference(&self) -> Option<(Type, Mutability)> {
let (ty, _lt, m) = self.ty.as_reference()?;
let m = Mutability::from_mutable(matches!(m, hir_ty::Mutability::Mut));