Improve indexing of impls

Store impls for e.g. &Foo with the ones for Foo instead of the big
"other" bucket. This can improve performance and simplifies the HIR impl
search a bit.
This commit is contained in:
Florian Diebold 2021-04-07 19:35:24 +02:00
parent 354151df35
commit fdd721e9ef
3 changed files with 85 additions and 28 deletions

View File

@ -1580,11 +1580,24 @@ pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<I
ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty)) ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty))
}; };
let fp = TyFingerprint::for_inherent_impl(&ty);
let fp = if let Some(fp) = fp {
fp
} else {
return Vec::new();
};
let mut all = Vec::new(); let mut all = Vec::new();
def_crates.iter().for_each(|&id| { def_crates.iter().for_each(|&id| {
all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter)) all.extend(
db.inherent_impls_in_crate(id)
.for_self_ty(&ty)
.into_iter()
.cloned()
.map(Self::from)
.filter(filter),
)
}); });
let fp = TyFingerprint::for_impl(&ty);
for id in def_crates for id in def_crates
.iter() .iter()
.flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db)) .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db))
@ -1592,13 +1605,12 @@ pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<I
.chain(def_crates.iter().copied()) .chain(def_crates.iter().copied())
.unique() .unique()
{ {
match fp { all.extend(
Some(fp) => all.extend( db.trait_impls_in_crate(id)
db.trait_impls_in_crate(id).for_self_ty(fp).map(Self::from).filter(filter), .for_self_ty_without_blanket_impls(fp)
), .map(Self::from)
None => all .filter(filter),
.extend(db.trait_impls_in_crate(id).all_impls().map(Self::from).filter(filter)), );
}
} }
all all
} }

View File

@ -13,6 +13,7 @@
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use stdx::always;
use crate::{ use crate::{
autoderef, autoderef,
@ -21,32 +22,36 @@
primitive::{self, FloatTy, IntTy, UintTy}, primitive::{self, FloatTy, IntTy, UintTy},
static_lifetime, static_lifetime,
utils::all_super_traits, utils::all_super_traits,
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId, AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
TyExt, TyKind,
}; };
/// This is used as a key for indexing impls. /// This is used as a key for indexing impls.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TyFingerprint { pub enum TyFingerprint {
// These are lang item impls:
Str, Str,
Slice, Slice,
Array, Array,
Never, Never,
RawPtr(Mutability), RawPtr(Mutability),
Scalar(Scalar), Scalar(Scalar),
// These can have user-defined impls:
Adt(hir_def::AdtId), Adt(hir_def::AdtId),
Dyn(TraitId), Dyn(TraitId),
Tuple(usize),
ForeignType(ForeignDefId), ForeignType(ForeignDefId),
FnPtr(usize, FnSig), // These only exist for trait impls
Unit,
Unnameable,
Function(u32),
} }
impl TyFingerprint { impl TyFingerprint {
/// Creates a TyFingerprint for looking up an impl. Only certain types can /// Creates a TyFingerprint for looking up an inherent impl. Only certain
/// have impls: if we have some `struct S`, we can have an `impl S`, but not /// types can have inherent impls: if we have some `struct S`, we can have
/// `impl &S`. Hence, this will return `None` for reference types and such. /// an `impl S`, but not `impl &S`. Hence, this will return `None` for
pub fn for_impl(ty: &Ty) -> Option<TyFingerprint> { /// reference types and such.
pub fn for_inherent_impl(ty: &Ty) -> Option<TyFingerprint> {
let fp = match ty.kind(&Interner) { let fp = match ty.kind(&Interner) {
TyKind::Str => TyFingerprint::Str, TyKind::Str => TyFingerprint::Str,
TyKind::Never => TyFingerprint::Never, TyKind::Never => TyFingerprint::Never,
@ -54,17 +59,52 @@ pub fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
TyKind::Array(..) => TyFingerprint::Array, TyKind::Array(..) => TyFingerprint::Array,
TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar), TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt), TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
TyKind::Tuple(cardinality, _) => TyFingerprint::Tuple(*cardinality),
TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability), TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id), TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
TyKind::Function(FnPointer { sig, substitution: substs, .. }) => {
TyFingerprint::FnPtr(substs.0.len(&Interner) - 1, *sig)
}
TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?, TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?,
_ => return None, _ => return None,
}; };
Some(fp) Some(fp)
} }
/// Creates a TyFingerprint for looking up a trait impl.
pub fn for_trait_impl(ty: &Ty) -> Option<TyFingerprint> {
let fp = match ty.kind(&Interner) {
TyKind::Str => TyFingerprint::Str,
TyKind::Never => TyFingerprint::Never,
TyKind::Slice(..) => TyFingerprint::Slice,
TyKind::Array(..) => TyFingerprint::Array,
TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?,
TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty),
TyKind::Tuple(_, subst) => {
let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(&Interner));
if let Some(ty) = first_ty {
return TyFingerprint::for_trait_impl(ty);
} else {
TyFingerprint::Unit
}
}
TyKind::AssociatedType(_, _)
| TyKind::OpaqueType(_, _)
| TyKind::FnDef(_, _)
| TyKind::Closure(_, _)
| TyKind::Generator(..)
| TyKind::GeneratorWitness(..) => TyFingerprint::Unnameable,
TyKind::Function(fn_ptr) => {
TyFingerprint::Function(fn_ptr.substitution.0.len(&Interner) as u32)
}
TyKind::Alias(_)
| TyKind::Placeholder(_)
| TyKind::BoundVar(_)
| TyKind::InferenceVar(_, _)
| TyKind::Error => return None,
};
Some(fp)
}
} }
pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
@ -112,7 +152,7 @@ fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut TraitImpl
None => continue, None => continue,
}; };
let self_ty = db.impl_self_ty(impl_id); let self_ty = db.impl_self_ty(impl_id);
let self_ty_fp = TyFingerprint::for_impl(self_ty.skip_binders()); let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
impls impls
.map .map
.entry(target_trait) .entry(target_trait)
@ -157,10 +197,13 @@ fn merge(&mut self, other: &Self) {
} }
/// Queries all trait impls for the given type. /// Queries all trait impls for the given type.
pub fn for_self_ty(&self, fp: TyFingerprint) -> impl Iterator<Item = ImplId> + '_ { pub fn for_self_ty_without_blanket_impls(
&self,
fp: TyFingerprint,
) -> impl Iterator<Item = ImplId> + '_ {
self.map self.map
.values() .values()
.flat_map(move |impls| impls.get(&None).into_iter().chain(impls.get(&Some(fp)))) .flat_map(move |impls| impls.get(&Some(fp)).into_iter())
.flat_map(|it| it.iter().copied()) .flat_map(|it| it.iter().copied())
} }
@ -215,7 +258,9 @@ pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId
} }
let self_ty = db.impl_self_ty(impl_id); let self_ty = db.impl_self_ty(impl_id);
if let Some(fp) = TyFingerprint::for_impl(self_ty.skip_binders()) { let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
always!(fp.is_some());
if let Some(fp) = fp {
map.entry(fp).or_default().push(impl_id); map.entry(fp).or_default().push(impl_id);
} }
} }
@ -228,7 +273,7 @@ pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId
} }
pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
match TyFingerprint::for_impl(self_ty) { match TyFingerprint::for_inherent_impl(self_ty) {
Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]), Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
None => &[], None => &[],
} }

View File

@ -101,7 +101,7 @@ fn binder_kind(
None None
} }
let self_ty_fp = TyFingerprint::for_impl(&ty); let self_ty_fp = TyFingerprint::for_trait_impl(&ty);
let fps: &[TyFingerprint] = match binder_kind(&ty, binders) { let fps: &[TyFingerprint] = match binder_kind(&ty, binders) {
Some(chalk_ir::TyVariableKind::Integer) => &ALL_INT_FPS, Some(chalk_ir::TyVariableKind::Integer) => &ALL_INT_FPS,
Some(chalk_ir::TyVariableKind::Float) => &ALL_FLOAT_FPS, Some(chalk_ir::TyVariableKind::Float) => &ALL_FLOAT_FPS,