Auto merge of #14119 - Veykril:miniopt, r=Veykril

internal: Remove a few allocations in hir-ty::utils
This commit is contained in:
bors 2023-02-10 15:18:46 +00:00
commit a28f53646d
3 changed files with 96 additions and 93 deletions

View File

@ -927,7 +927,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
} }
} }
fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> { fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> + '_ {
let krate = trait_.lookup(db).container.krate(); let krate = trait_.lookup(db).container.krate();
utils::fn_traits(db, krate) utils::fn_traits(db, krate)
} }

View File

@ -1235,7 +1235,7 @@ fn named_associated_type_shorthand_candidates<R>(
mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>, mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
) -> Option<R> { ) -> Option<R> {
let mut search = |t| { let mut search = |t| {
for t in all_super_trait_refs(db, t) { all_super_trait_refs(db, t, |t| {
let data = db.trait_data(t.hir_trait_id()); let data = db.trait_data(t.hir_trait_id());
for (name, assoc_id) in &data.items { for (name, assoc_id) in &data.items {
@ -1245,8 +1245,8 @@ fn named_associated_type_shorthand_candidates<R>(
} }
} }
} }
} None
None })
}; };
match res { match res {

View File

@ -27,23 +27,84 @@
db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, WhereClause, db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, WhereClause,
}; };
pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> { pub(crate) fn fn_traits(
[ db: &dyn DefDatabase,
db.lang_item(krate, LangItem::Fn), krate: CrateId,
db.lang_item(krate, LangItem::FnMut), ) -> impl Iterator<Item = TraitId> + '_ {
db.lang_item(krate, LangItem::FnOnce), [LangItem::Fn, LangItem::FnMut, LangItem::FnOnce]
] .into_iter()
.into_iter() .filter_map(move |lang| db.lang_item(krate, lang))
.flatten() .flat_map(|it| it.as_trait())
.flat_map(|it| it.as_trait())
} }
fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> { /// Returns an iterator over the whole super trait hierarchy (including the
/// trait itself).
pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
// we need to take care a bit here to avoid infinite loops in case of cycles
// (i.e. if we have `trait A: B; trait B: A;`)
let mut result = smallvec![trait_];
let mut i = 0;
while let Some(&t) = result.get(i) {
// yeah this is quadratic, but trait hierarchies should be flat
// enough that this doesn't matter
direct_super_traits(db, t, |tt| {
if !result.contains(&tt) {
result.push(tt);
}
});
i += 1;
}
result
}
/// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
/// super traits. The original trait ref will be included. So the difference to
/// `all_super_traits` is that we keep track of type parameters; for example if
/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
/// `Self: OtherTrait<i32>`.
pub(super) fn all_super_trait_refs<T>(
db: &dyn HirDatabase,
trait_ref: TraitRef,
cb: impl FnMut(TraitRef) -> Option<T>,
) -> Option<T> {
let seen = iter::once(trait_ref.trait_id).collect();
let mut stack = Vec::new();
stack.push(trait_ref);
SuperTraits { db, seen, stack }.find_map(cb)
}
struct SuperTraits<'a> {
db: &'a dyn HirDatabase,
stack: Vec<TraitRef>,
seen: FxHashSet<ChalkTraitId>,
}
impl<'a> SuperTraits<'a> {
fn elaborate(&mut self, trait_ref: &TraitRef) {
direct_super_trait_refs(self.db, trait_ref, |trait_ref| {
if !self.seen.contains(&trait_ref.trait_id) {
self.stack.push(trait_ref);
}
});
}
}
impl<'a> Iterator for SuperTraits<'a> {
type Item = TraitRef;
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.stack.pop() {
self.elaborate(&next);
Some(next)
} else {
None
}
}
}
fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
let resolver = trait_.resolver(db); let resolver = trait_.resolver(db);
// returning the iterator directly doesn't easily work because of
// lifetime problems, but since there usually shouldn't be more than a
// few direct traits this should be fine (we could even use some kind of
// SmallVec if performance is a concern)
let generic_params = db.generic_params(trait_.into()); let generic_params = db.generic_params(trait_.into());
let trait_self = generic_params.find_trait_self_param(); let trait_self = generic_params.find_trait_self_param();
generic_params generic_params
@ -73,18 +134,14 @@ pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<I
Some(TypeNs::TraitId(t)) => Some(t), Some(TypeNs::TraitId(t)) => Some(t),
_ => None, _ => None,
}) })
.collect() .for_each(cb);
} }
fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<TraitRef> { fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) {
// returning the iterator directly doesn't easily work because of
// lifetime problems, but since there usually shouldn't be more than a
// few direct traits this should be fine (we could even use some kind of
// SmallVec if performance is a concern)
let generic_params = db.generic_params(trait_ref.hir_trait_id().into()); let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
let trait_self = match generic_params.find_trait_self_param() { let trait_self = match generic_params.find_trait_self_param() {
Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p }, Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
None => return Vec::new(), None => return,
}; };
db.generic_predicates_for_param(trait_self.parent, trait_self, None) db.generic_predicates_for_param(trait_self.parent, trait_self, None)
.iter() .iter()
@ -100,64 +157,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
}) })
}) })
.map(|pred| pred.substitute(Interner, &trait_ref.substitution)) .map(|pred| pred.substitute(Interner, &trait_ref.substitution))
.collect() .for_each(cb);
}
/// Returns an iterator over the whole super trait hierarchy (including the
/// trait itself).
pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
// we need to take care a bit here to avoid infinite loops in case of cycles
// (i.e. if we have `trait A: B; trait B: A;`)
let mut result = smallvec![trait_];
let mut i = 0;
while let Some(&t) = result.get(i) {
// yeah this is quadratic, but trait hierarchies should be flat
// enough that this doesn't matter
for tt in direct_super_traits(db, t) {
if !result.contains(&tt) {
result.push(tt);
}
}
i += 1;
}
result
}
/// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
/// super traits. The original trait ref will be included. So the difference to
/// `all_super_traits` is that we keep track of type parameters; for example if
/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
/// `Self: OtherTrait<i32>`.
pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> SuperTraits<'_> {
SuperTraits { db, seen: iter::once(trait_ref.trait_id).collect(), stack: vec![trait_ref] }
}
pub(super) struct SuperTraits<'a> {
db: &'a dyn HirDatabase,
stack: Vec<TraitRef>,
seen: FxHashSet<ChalkTraitId>,
}
impl<'a> SuperTraits<'a> {
fn elaborate(&mut self, trait_ref: &TraitRef) {
let mut trait_refs = direct_super_trait_refs(self.db, trait_ref);
trait_refs.retain(|tr| !self.seen.contains(&tr.trait_id));
self.stack.extend(trait_refs);
}
}
impl<'a> Iterator for SuperTraits<'a> {
type Item = TraitRef;
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.stack.pop() {
self.elaborate(&next);
Some(next)
} else {
None
}
}
} }
pub(super) fn associated_type_by_name_including_super_traits( pub(super) fn associated_type_by_name_including_super_traits(
@ -165,7 +165,7 @@ pub(super) fn associated_type_by_name_including_super_traits(
trait_ref: TraitRef, trait_ref: TraitRef,
name: &Name, name: &Name,
) -> Option<(TraitRef, TypeAliasId)> { ) -> Option<(TraitRef, TypeAliasId)> {
all_super_trait_refs(db, trait_ref).find_map(|t| { all_super_trait_refs(db, trait_ref, |t| {
let assoc_type = db.trait_data(t.hir_trait_id()).associated_type_by_name(name)?; let assoc_type = db.trait_data(t.hir_trait_id()).associated_type_by_name(name)?;
Some((t, assoc_type)) Some((t, assoc_type))
}) })
@ -238,15 +238,18 @@ pub(crate) fn len_self(&self) -> usize {
/// (parent total, self param, type param list, const param list, impl trait) /// (parent total, self param, type param list, const param list, impl trait)
pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) { pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
let ty_iter = || self.params.iter().filter_map(|x| x.1.type_param()); let mut self_params = 0;
let mut type_params = 0;
let self_params = let mut impl_trait_params = 0;
ty_iter().filter(|p| p.provenance == TypeParamProvenance::TraitSelf).count(); let mut const_params = 0;
let type_params = self.params.iter().for_each(|(_, data)| match data {
ty_iter().filter(|p| p.provenance == TypeParamProvenance::TypeParamList).count(); TypeOrConstParamData::TypeParamData(p) => match p.provenance {
let impl_trait_params = TypeParamProvenance::TypeParamList => type_params += 1,
ty_iter().filter(|p| p.provenance == TypeParamProvenance::ArgumentImplTrait).count(); TypeParamProvenance::TraitSelf => self_params += 1,
let const_params = self.params.iter().filter_map(|x| x.1.const_param()).count(); TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1,
},
TypeOrConstParamData::ConstParamData(_) => const_params += 1,
});
let parent_len = self.parent_generics().map_or(0, Generics::len); let parent_len = self.parent_generics().map_or(0, Generics::len);
(parent_len, self_params, type_params, const_params, impl_trait_params) (parent_len, self_params, type_params, const_params, impl_trait_params)