Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/generics.rs')
| -rw-r--r-- | crates/hir-ty/src/generics.rs | 368 |
1 files changed, 206 insertions, 162 deletions
diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs index b041281844..32482ca94b 100644 --- a/crates/hir-ty/src/generics.rs +++ b/crates/hir-ty/src/generics.rs @@ -7,51 +7,56 @@ //! - Type or Const parameters //! //! where parent follows the same scheme. -use std::ops; +use arrayvec::ArrayVec; use hir_def::{ ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, Lookup, TypeOrConstParamId, TypeParamId, db::DefDatabase, expr_store::ExpressionStore, hir::generics::{ - GenericParamDataRef, GenericParams, LifetimeParamData, LocalLifetimeParamId, - LocalTypeOrConstParamId, TypeOrConstParamData, TypeParamProvenance, WherePredicate, + GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData, + TypeParamProvenance, WherePredicate, }, }; -use itertools::chain; -pub fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics<'_> { - let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); +pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics<'_> { + let mut chain = ArrayVec::new(); + let mut parent_params_len = 0; + if let Some(parent_def) = parent_generic_def(db, def) { + let (parent_params, parent_store) = GenericParams::with_store(db, parent_def); + chain.push(SingleGenerics { + def: parent_def, + params: parent_params, + store: parent_store, + preceding_params_len: 0, + }); + parent_params_len = parent_params.len() as u32; + } let (params, store) = GenericParams::with_store(db, def); - let has_trait_self_param = params.trait_self_param().is_some(); - Generics { def, params, parent_generics, has_trait_self_param, store } + chain.push(SingleGenerics { def, params, store, preceding_params_len: parent_params_len }); + Generics { chain } +} + +#[derive(Debug)] +pub(crate) struct Generics<'db> { + chain: ArrayVec<SingleGenerics<'db>, 2>, } -#[derive(Clone, Debug)] -pub struct Generics<'db> { + +#[derive(Debug)] +pub(crate) struct SingleGenerics<'db> { def: GenericDefId, + preceding_params_len: u32, params: &'db GenericParams, store: &'db ExpressionStore, - parent_generics: Option<Box<Generics<'db>>>, - has_trait_self_param: bool, } -impl<T> ops::Index<T> for Generics<'_> -where - GenericParams: ops::Index<T>, -{ - type Output = <GenericParams as ops::Index<T>>::Output; - fn index(&self, index: T) -> &Self::Output { - &self.params[index] - } -} - -impl<'db> Generics<'db> { +impl<'db> SingleGenerics<'db> { pub(crate) fn def(&self) -> GenericDefId { self.def } - pub(crate) fn store(&self) -> &ExpressionStore { + pub(crate) fn store(&self) -> &'db ExpressionStore { self.store } @@ -59,166 +64,237 @@ impl<'db> Generics<'db> { self.params.where_predicates().iter() } - pub(crate) fn is_empty(&self) -> bool { - self.params.is_empty() && self.parent_generics.as_ref().is_none_or(|g| g.params.is_empty()) + pub(crate) fn has_no_params(&self) -> bool { + self.params.is_empty() } - pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ { - self.iter_parent_id().chain(self.iter_self_id()) + pub(crate) fn len_lifetimes(&self) -> usize { + self.params.len_lifetimes() } - pub(crate) fn iter_self_id(&self) -> impl Iterator<Item = GenericParamId> + '_ { - self.iter_self().map(|(id, _)| id) + pub(crate) fn len(&self) -> usize { + self.params.len() } - pub(crate) fn iter_parent_id(&self) -> impl Iterator<Item = GenericParamId> + '_ { - self.iter_parent().map(|(id, _)| id) + fn iter_lifetimes(&self) -> impl Iterator<Item = (LifetimeParamId, &'db LifetimeParamData)> { + let parent = self.def; + self.params + .iter_lt() + .map(move |(local_id, data)| (LifetimeParamId { parent, local_id }, data)) } - pub(crate) fn iter_self_type_or_consts( + pub(crate) fn iter_type_or_consts( &self, - ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> + '_ - { - let mut toc = self.params.iter_type_or_consts(); - let trait_self_param = self.has_trait_self_param.then(|| toc.next()).flatten(); - chain!(trait_self_param, toc) + ) -> impl Iterator<Item = (TypeOrConstParamId, &'db TypeOrConstParamData)> { + let parent = self.def; + self.params + .iter_type_or_consts() + .map(move |(local_id, data)| (TypeOrConstParamId { parent, local_id }, data)) } - /// Iterate over the parent params followed by self params. - pub(crate) fn iter( + fn iter_type_or_consts_as_generic( + &self, + ) -> impl Iterator<Item = (GenericParamId, GenericParamDataRef<'db>)> { + self.iter_type_or_consts().map(|(id, data)| match data { + TypeOrConstParamData::TypeParamData(data) => ( + GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), + GenericParamDataRef::TypeParamData(data), + ), + TypeOrConstParamData::ConstParamData(data) => ( + GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), + GenericParamDataRef::ConstParamData(data), + ), + }) + } + + fn trait_self_and_others( &self, - ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ { - self.iter_parent().chain(self.iter_self()) + ) -> ( + Option<(GenericParamId, GenericParamDataRef<'db>)>, + impl Iterator<Item = (GenericParamId, GenericParamDataRef<'db>)>, + ) { + let mut iter = self.iter_type_or_consts_as_generic(); + let trait_self = if let GenericDefId::TraitId(_) = self.def { iter.next() } else { None }; + (trait_self, iter) } - pub(crate) fn iter_parents_with_store( + pub(crate) fn iter(&self) -> impl Iterator<Item = (GenericParamId, GenericParamDataRef<'db>)> { + let lifetimes = self.iter_lifetimes().map(|(id, data)| { + (GenericParamId::LifetimeParamId(id), GenericParamDataRef::LifetimeParamData(data)) + }); + let (trait_self, type_and_consts) = self.trait_self_and_others(); + trait_self.into_iter().chain(lifetimes).chain(type_and_consts) + } + + pub(crate) fn iter_with_idx( &self, - ) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &ExpressionStore)> + '_ - { - self.iter_parent() - .zip(self.parent_generics().into_iter().flat_map(|it| std::iter::repeat(it.store))) + ) -> impl Iterator<Item = (u32, GenericParamId, GenericParamDataRef<'db>)> { + std::iter::zip(self.preceding_params_len.., self.iter()) + .map(|(index, (id, data))| (index, id, data)) + } + + pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> { + self.iter().map(|(id, _)| id) + } +} + +impl<'db> Generics<'db> { + pub(crate) fn iter_owners(&self) -> impl DoubleEndedIterator<Item = &SingleGenerics<'db>> { + self.chain.iter() + } + + fn owner(&self) -> &SingleGenerics<'db> { + self.chain.last().expect("must have an owner params") + } + + pub(crate) fn parent(&self) -> Option<&SingleGenerics<'db>> { + match &*self.chain { + [parent, _owner] => Some(parent), + _ => None, + } + } + + pub(crate) fn has_no_params(&self) -> bool { + self.iter_owners().all(|owner| owner.has_no_params()) + } + + pub(crate) fn def(&self) -> GenericDefId { + self.owner().def + } + + pub(crate) fn store(&self) -> &'db ExpressionStore { + self.owner().store } - /// Iterate over the params without parent params. pub(crate) fn iter_self( &self, - ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ { - let mut toc = self.params.iter_type_or_consts().map(from_toc_id(self)); - let trait_self_param = self.has_trait_self_param.then(|| toc.next()).flatten(); - chain!(trait_self_param, self.params.iter_lt().map(from_lt_id(self)), toc) + ) -> impl Iterator<Item = (GenericParamId, GenericParamDataRef<'db>)> { + self.owner().iter() } - /// Iterator over types and const params of parent. - pub(crate) fn iter_parent( + pub(crate) fn iter_self_with_idx( &self, - ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ { - self.parent_generics().into_iter().flat_map(|it| { - let mut toc = it.params.iter_type_or_consts().map(from_toc_id(it)); - let trait_self_param = it.has_trait_self_param.then(|| toc.next()).flatten(); - chain!(trait_self_param, it.params.iter_lt().map(from_lt_id(it)), toc) - }) + ) -> impl Iterator<Item = (u32, GenericParamId, GenericParamDataRef<'db>)> { + self.owner().iter_with_idx() + } + + pub(crate) fn iter_parent_id(&self) -> impl Iterator<Item = GenericParamId> { + self.parent().into_iter().flat_map(|parent| parent.iter_id()) + } + + pub(crate) fn iter_self_type_or_consts( + &self, + ) -> impl Iterator<Item = (TypeOrConstParamId, &'db TypeOrConstParamData)> { + self.owner().iter_type_or_consts() + } + + /// Iterate over the parent params followed by self params. + #[cfg(test)] + pub(crate) fn iter(&self) -> impl Iterator<Item = (GenericParamId, GenericParamDataRef<'_>)> { + self.iter_owners().flat_map(|owner| owner.iter()) + } + + pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> { + self.iter_owners().flat_map(|owner| owner.iter_id()) } /// Returns total number of generic parameters in scope, including those from parent. pub(crate) fn len(&self) -> usize { - let parent = self.len_parent(); - let child = self.params.len(); - parent + child + match &*self.chain { + [parent, owner] => parent.len() + owner.len(), + [owner] => owner.len(), + _ => unreachable!(), + } } #[inline] pub(crate) fn len_parent(&self) -> usize { - self.parent_generics().map_or(0, Generics::len) + self.parent().map_or(0, SingleGenerics::len) } pub(crate) fn len_lifetimes_self(&self) -> usize { - self.params.len_lifetimes() + self.owner().len_lifetimes() } - /// (parent total, self param, type params, const params, impl trait list, lifetimes) - pub(crate) fn provenance_split(&self) -> (usize, bool, usize, usize, usize, usize) { - let mut self_param = false; - let mut type_params = 0; - let mut impl_trait_params = 0; + pub(crate) fn provenance_split(&self) -> ProvenanceSplit { + let parent_total = self.len_parent(); + + let owner = self.owner(); + let lifetimes = owner.params.len_lifetimes(); + + let mut has_self_param = false; + let mut non_impl_trait_type_params = 0; + let mut impl_trait_type_params = 0; let mut const_params = 0; - self.params.iter_type_or_consts().for_each(|(_, data)| match data { + owner.params.iter_type_or_consts().for_each(|(_, data)| match data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { - TypeParamProvenance::TypeParamList => type_params += 1, - TypeParamProvenance::TraitSelf => self_param |= true, - TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1, + TypeParamProvenance::TypeParamList => non_impl_trait_type_params += 1, + TypeParamProvenance::TraitSelf => has_self_param |= true, + TypeParamProvenance::ArgumentImplTrait => impl_trait_type_params += 1, }, TypeOrConstParamData::ConstParamData(_) => const_params += 1, }); - let lifetime_params = self.params.len_lifetimes(); - - let parent_len = self.parent_generics().map_or(0, Generics::len); - (parent_len, self_param, type_params, const_params, impl_trait_params, lifetime_params) - } - - pub(crate) fn type_or_const_param( - &self, - param: TypeOrConstParamId, - ) -> Option<(usize, TypeOrConstParamData)> { - let idx = self.find_type_or_const_param(param)?; - self.iter().nth(idx).and_then(|p| { - let data = match p.1 { - GenericParamDataRef::TypeParamData(p) => p.clone().into(), - GenericParamDataRef::ConstParamData(p) => p.clone().into(), - _ => return None, - }; - Some((idx, data)) - }) - } - - pub fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option<usize> { - self.find_type_or_const_param(param) + ProvenanceSplit { + parent_total, + has_self_param, + non_impl_trait_type_params, + const_params, + impl_trait_type_params, + lifetimes, + } } - fn find_type_or_const_param(&self, param: TypeOrConstParamId) -> Option<usize> { - if param.parent == self.def { - let idx = param.local_id.into_raw().into_u32() as usize; - debug_assert!( - idx < self.params.len_type_or_consts(), - "idx: {} len: {}", - idx, - self.params.len_type_or_consts() - ); - if self.params.trait_self_param() == Some(param.local_id) { - return Some(idx); + fn find_owner(&self, def: GenericDefId) -> &SingleGenerics<'db> { + match &*self.chain { + [parent, owner] => { + if parent.def == def { + parent + } else { + debug_assert_eq!(def, owner.def); + owner + } } - Some(self.parent_generics().map_or(0, |g| g.len()) + self.params.len_lifetimes() + idx) - } else { - debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(param.parent)); - self.parent_generics().and_then(|g| g.find_type_or_const_param(param)) + [owner] => { + debug_assert_eq!(def, owner.def); + owner + } + _ => unreachable!(), } } - pub fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option<usize> { - self.find_lifetime(lifetime) - } - - fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<usize> { - if lifetime.parent == self.def { - let idx = lifetime.local_id.into_raw().into_u32() as usize; - debug_assert!(idx <= self.params.len_lifetimes()); - Some( - self.parent_generics().map_or(0, |g| g.len()) - + self.params.trait_self_param().is_some() as usize - + idx, - ) + pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> u32 { + let owner = self.find_owner(param.parent); + let has_trait_self = matches!(owner.def, GenericDefId::TraitId(_)); + if has_trait_self && param.local_id == GenericParams::SELF_PARAM_ID_IN_SELF { + owner.preceding_params_len } else { - debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(lifetime.parent)); - self.parent_generics().and_then(|g| g.find_lifetime(lifetime)) + owner.preceding_params_len + + owner.len_lifetimes() as u32 + + param.local_id.into_raw().into_u32() } } - pub(crate) fn parent_generics(&self) -> Option<&Generics<'db>> { - self.parent_generics.as_deref() + pub(crate) fn lifetime_param_idx(&self, param: LifetimeParamId) -> u32 { + let owner = self.find_owner(param.parent); + let has_trait_self = matches!(owner.def, GenericDefId::TraitId(_)); + owner.preceding_params_len + + u32::from(has_trait_self) + + param.local_id.into_raw().into_u32() } } -pub(crate) fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> { +pub(crate) struct ProvenanceSplit { + pub(crate) parent_total: usize, + // The rest are about self. + pub(crate) has_self_param: bool, + pub(crate) non_impl_trait_type_params: usize, + pub(crate) const_params: usize, + pub(crate) impl_trait_type_params: usize, + pub(crate) lifetimes: usize, +} + +fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> { let container = match def { GenericDefId::FunctionId(it) => it.lookup(db).container, GenericDefId::TypeAliasId(it) => it.lookup(db).container, @@ -235,35 +311,3 @@ pub(crate) fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Opt ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, } } - -fn from_toc_id<'a>( - it: &'a Generics<'a>, -) -> impl Fn( - (LocalTypeOrConstParamId, &'a TypeOrConstParamData), -) -> (GenericParamId, GenericParamDataRef<'a>) { - move |(local_id, p): (_, _)| { - let id = TypeOrConstParamId { parent: it.def, local_id }; - match p { - TypeOrConstParamData::TypeParamData(p) => ( - GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), - GenericParamDataRef::TypeParamData(p), - ), - TypeOrConstParamData::ConstParamData(p) => ( - GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), - GenericParamDataRef::ConstParamData(p), - ), - } - } -} - -fn from_lt_id<'a>( - it: &'a Generics<'a>, -) -> impl Fn((LocalLifetimeParamId, &'a LifetimeParamData)) -> (GenericParamId, GenericParamDataRef<'a>) -{ - move |(local_id, p): (_, _)| { - ( - GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), - GenericParamDataRef::LifetimeParamData(p), - ) - } -} |