//! HIR for references to types. Paths in these are not yet resolved. They can //! be directly created from an ast::TypeRef, without further queries. use hir_expand::name::Name; use intern::Symbol; use la_arena::Idx; use thin_vec::ThinVec; use crate::{ LifetimeParamId, TypeParamId, expr_store::{ ExpressionStore, path::{GenericArg, Path}, }, hir::ExprId, }; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum Mutability { Shared, Mut, } impl Mutability { pub fn from_mutable(mutable: bool) -> Mutability { if mutable { Mutability::Mut } else { Mutability::Shared } } pub fn as_keyword_for_ref(self) -> &'static str { match self { Mutability::Shared => "", Mutability::Mut => "mut ", } } pub fn as_keyword_for_ptr(self) -> &'static str { match self { Mutability::Shared => "const ", Mutability::Mut => "mut ", } } /// Returns `true` if the mutability is [`Mut`]. /// /// [`Mut`]: Mutability::Mut #[must_use] pub fn is_mut(&self) -> bool { matches!(self, Self::Mut) } /// Returns `true` if the mutability is [`Shared`]. /// /// [`Shared`]: Mutability::Shared #[must_use] pub fn is_shared(&self) -> bool { matches!(self, Self::Shared) } } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum Rawness { RawPtr, Ref, } impl Rawness { pub fn from_raw(is_raw: bool) -> Rawness { if is_raw { Rawness::RawPtr } else { Rawness::Ref } } pub fn is_raw(&self) -> bool { matches!(self, Self::RawPtr) } } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] /// A `TypeRefId` that is guaranteed to always be `TypeRef::Path`. We use this for things like /// impl's trait, that are always paths but need to be traced back to source code. pub struct PathId(TypeRefId); impl PathId { #[inline] pub fn from_type_ref_unchecked(type_ref: TypeRefId) -> Self { Self(type_ref) } #[inline] pub fn type_ref(self) -> TypeRefId { self.0 } } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct TraitRef { pub path: PathId, } #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct FnType { pub params: Box<[(Option, TypeRefId)]>, pub is_varargs: bool, pub is_unsafe: bool, pub abi: Option, } impl FnType { #[inline] pub fn split_params_and_ret(&self) -> (&[(Option, TypeRefId)], TypeRefId) { let (ret, params) = self.params.split_last().expect("should have at least return type"); (params, ret.1) } } #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct ArrayType { pub ty: TypeRefId, pub len: ConstRef, } #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct RefType { pub ty: TypeRefId, pub lifetime: Option, pub mutability: Mutability, } /// Compare ty::Ty #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum TypeRef { Never, Placeholder, Tuple(ThinVec), Path(Path), RawPtr(TypeRefId, Mutability), // FIXME: Unbox this once `Idx` has a niche, // as `RefType` should shrink by 4 bytes then Reference(Box), Array(ArrayType), Slice(TypeRefId), /// A fn pointer. Last element of the vector is the return type. Fn(Box), ImplTrait(ThinVec), DynTrait(ThinVec), TypeParam(TypeParamId), Error, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] const _: () = assert!(size_of::() == 24); pub type TypeRefId = Idx; pub type LifetimeRefId = Idx; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum LifetimeRef { Named(Name), Static, Placeholder, Param(LifetimeParamId), Error, } #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum TypeBound { Path(PathId, TraitBoundModifier), ForLifetime(ThinVec, PathId), Lifetime(LifetimeRefId), Use(ThinVec), Error, } #[cfg(target_pointer_width = "64")] const _: [(); 16] = [(); size_of::()]; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum UseArgRef { Name(Name), Lifetime(LifetimeRefId), } /// A modifier on a bound, currently this is only used for `?Sized`, where the /// modifier is `Maybe`. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum TraitBoundModifier { None, Maybe, } impl TypeRef { pub(crate) fn unit() -> TypeRef { TypeRef::Tuple(ThinVec::new()) } pub fn walk(this: TypeRefId, map: &ExpressionStore, f: &mut impl FnMut(TypeRefId, &TypeRef)) { go(this, f, map); fn go( type_ref_id: TypeRefId, f: &mut impl FnMut(TypeRefId, &TypeRef), map: &ExpressionStore, ) { let type_ref = &map[type_ref_id]; f(type_ref_id, type_ref); match type_ref { TypeRef::Fn(fn_) => { fn_.params.iter().for_each(|&(_, param_type)| go(param_type, f, map)) } TypeRef::Tuple(types) => types.iter().for_each(|&t| go(t, f, map)), TypeRef::RawPtr(type_ref, _) | TypeRef::Slice(type_ref) => go(*type_ref, f, map), TypeRef::Reference(it) => go(it.ty, f, map), TypeRef::Array(it) => go(it.ty, f, map), TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { for bound in bounds { match bound { &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => { go_path(&map[path], f, map) } TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (), } } } TypeRef::Path(path) => go_path(path, f, map), TypeRef::Never | TypeRef::Placeholder | TypeRef::Error | TypeRef::TypeParam(_) => {} }; } fn go_path(path: &Path, f: &mut impl FnMut(TypeRefId, &TypeRef), map: &ExpressionStore) { if let Some(type_ref) = path.type_anchor() { go(type_ref, f, map); } for segment in path.segments().iter() { if let Some(args_and_bindings) = segment.args_and_bindings { for arg in args_and_bindings.args.iter() { match arg { GenericArg::Type(type_ref) => { go(*type_ref, f, map); } GenericArg::Const(_) | GenericArg::Lifetime(_) => {} } } for binding in args_and_bindings.bindings.iter() { if let Some(type_ref) = binding.type_ref { go(type_ref, f, map); } for bound in binding.bounds.iter() { match bound { &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => { go_path(&map[path], f, map) } TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (), } } } } } } } } impl TypeBound { pub fn as_path<'a>(&self, map: &'a ExpressionStore) -> Option<(&'a Path, TraitBoundModifier)> { match self { &TypeBound::Path(p, m) => Some((&map[p], m)), &TypeBound::ForLifetime(_, p) => Some((&map[p], TraitBoundModifier::None)), TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None, } } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct ConstRef { pub expr: ExprId, }