Skip to content

Commit fdd721e

Browse files
committed
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.
1 parent 354151d commit fdd721e

File tree

3 files changed

+85
-28
lines changed

3 files changed

+85
-28
lines changed

crates/hir/src/lib.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,25 +1580,37 @@ impl Impl {
15801580
ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty))
15811581
};
15821582

1583+
let fp = TyFingerprint::for_inherent_impl(&ty);
1584+
let fp = if let Some(fp) = fp {
1585+
fp
1586+
} else {
1587+
return Vec::new();
1588+
};
1589+
15831590
let mut all = Vec::new();
15841591
def_crates.iter().for_each(|&id| {
1585-
all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter))
1592+
all.extend(
1593+
db.inherent_impls_in_crate(id)
1594+
.for_self_ty(&ty)
1595+
.into_iter()
1596+
.cloned()
1597+
.map(Self::from)
1598+
.filter(filter),
1599+
)
15861600
});
1587-
let fp = TyFingerprint::for_impl(&ty);
15881601
for id in def_crates
15891602
.iter()
15901603
.flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db))
15911604
.map(|Crate { id }| id)
15921605
.chain(def_crates.iter().copied())
15931606
.unique()
15941607
{
1595-
match fp {
1596-
Some(fp) => all.extend(
1597-
db.trait_impls_in_crate(id).for_self_ty(fp).map(Self::from).filter(filter),
1598-
),
1599-
None => all
1600-
.extend(db.trait_impls_in_crate(id).all_impls().map(Self::from).filter(filter)),
1601-
}
1608+
all.extend(
1609+
db.trait_impls_in_crate(id)
1610+
.for_self_ty_without_blanket_impls(fp)
1611+
.map(Self::from)
1612+
.filter(filter),
1613+
);
16021614
}
16031615
all
16041616
}

crates/hir_ty/src/method_resolution.rs

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use hir_def::{
1313
};
1414
use hir_expand::name::Name;
1515
use rustc_hash::{FxHashMap, FxHashSet};
16+
use stdx::always;
1617

1718
use crate::{
1819
autoderef,
@@ -21,50 +22,89 @@ use crate::{
2122
primitive::{self, FloatTy, IntTy, UintTy},
2223
static_lifetime,
2324
utils::all_super_traits,
24-
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId,
25-
InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder,
26-
TyExt, TyKind,
25+
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
26+
Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
2727
};
2828

2929
/// This is used as a key for indexing impls.
3030
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
3131
pub enum TyFingerprint {
32+
// These are lang item impls:
3233
Str,
3334
Slice,
3435
Array,
3536
Never,
3637
RawPtr(Mutability),
3738
Scalar(Scalar),
39+
// These can have user-defined impls:
3840
Adt(hir_def::AdtId),
3941
Dyn(TraitId),
40-
Tuple(usize),
4142
ForeignType(ForeignDefId),
42-
FnPtr(usize, FnSig),
43+
// These only exist for trait impls
44+
Unit,
45+
Unnameable,
46+
Function(u32),
4347
}
4448

4549
impl TyFingerprint {
46-
/// Creates a TyFingerprint for looking up an impl. Only certain types can
47-
/// have impls: if we have some `struct S`, we can have an `impl S`, but not
48-
/// `impl &S`. Hence, this will return `None` for reference types and such.
49-
pub fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
50+
/// Creates a TyFingerprint for looking up an inherent impl. Only certain
51+
/// types can have inherent impls: if we have some `struct S`, we can have
52+
/// an `impl S`, but not `impl &S`. Hence, this will return `None` for
53+
/// reference types and such.
54+
pub fn for_inherent_impl(ty: &Ty) -> Option<TyFingerprint> {
5055
let fp = match ty.kind(&Interner) {
5156
TyKind::Str => TyFingerprint::Str,
5257
TyKind::Never => TyFingerprint::Never,
5358
TyKind::Slice(..) => TyFingerprint::Slice,
5459
TyKind::Array(..) => TyFingerprint::Array,
5560
TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
5661
TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
57-
TyKind::Tuple(cardinality, _) => TyFingerprint::Tuple(*cardinality),
5862
TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
5963
TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
60-
TyKind::Function(FnPointer { sig, substitution: substs, .. }) => {
61-
TyFingerprint::FnPtr(substs.0.len(&Interner) - 1, *sig)
62-
}
6364
TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?,
6465
_ => return None,
6566
};
6667
Some(fp)
6768
}
69+
70+
/// Creates a TyFingerprint for looking up a trait impl.
71+
pub fn for_trait_impl(ty: &Ty) -> Option<TyFingerprint> {
72+
let fp = match ty.kind(&Interner) {
73+
TyKind::Str => TyFingerprint::Str,
74+
TyKind::Never => TyFingerprint::Never,
75+
TyKind::Slice(..) => TyFingerprint::Slice,
76+
TyKind::Array(..) => TyFingerprint::Array,
77+
TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
78+
TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
79+
TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
80+
TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
81+
TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?,
82+
TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty),
83+
TyKind::Tuple(_, subst) => {
84+
let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(&Interner));
85+
if let Some(ty) = first_ty {
86+
return TyFingerprint::for_trait_impl(ty);
87+
} else {
88+
TyFingerprint::Unit
89+
}
90+
}
91+
TyKind::AssociatedType(_, _)
92+
| TyKind::OpaqueType(_, _)
93+
| TyKind::FnDef(_, _)
94+
| TyKind::Closure(_, _)
95+
| TyKind::Generator(..)
96+
| TyKind::GeneratorWitness(..) => TyFingerprint::Unnameable,
97+
TyKind::Function(fn_ptr) => {
98+
TyFingerprint::Function(fn_ptr.substitution.0.len(&Interner) as u32)
99+
}
100+
TyKind::Alias(_)
101+
| TyKind::Placeholder(_)
102+
| TyKind::BoundVar(_)
103+
| TyKind::InferenceVar(_, _)
104+
| TyKind::Error => return None,
105+
};
106+
Some(fp)
107+
}
68108
}
69109

70110
pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
@@ -112,7 +152,7 @@ impl TraitImpls {
112152
None => continue,
113153
};
114154
let self_ty = db.impl_self_ty(impl_id);
115-
let self_ty_fp = TyFingerprint::for_impl(self_ty.skip_binders());
155+
let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
116156
impls
117157
.map
118158
.entry(target_trait)
@@ -157,10 +197,13 @@ impl TraitImpls {
157197
}
158198

159199
/// Queries all trait impls for the given type.
160-
pub fn for_self_ty(&self, fp: TyFingerprint) -> impl Iterator<Item = ImplId> + '_ {
200+
pub fn for_self_ty_without_blanket_impls(
201+
&self,
202+
fp: TyFingerprint,
203+
) -> impl Iterator<Item = ImplId> + '_ {
161204
self.map
162205
.values()
163-
.flat_map(move |impls| impls.get(&None).into_iter().chain(impls.get(&Some(fp))))
206+
.flat_map(move |impls| impls.get(&Some(fp)).into_iter())
164207
.flat_map(|it| it.iter().copied())
165208
}
166209

@@ -215,7 +258,9 @@ impl InherentImpls {
215258
}
216259

217260
let self_ty = db.impl_self_ty(impl_id);
218-
if let Some(fp) = TyFingerprint::for_impl(self_ty.skip_binders()) {
261+
let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
262+
always!(fp.is_some());
263+
if let Some(fp) = fp {
219264
map.entry(fp).or_default().push(impl_id);
220265
}
221266
}
@@ -228,7 +273,7 @@ impl InherentImpls {
228273
}
229274

230275
pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
231-
match TyFingerprint::for_impl(self_ty) {
276+
match TyFingerprint::for_inherent_impl(self_ty) {
232277
Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
233278
None => &[],
234279
}

crates/hir_ty/src/traits/chalk.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
101101
None
102102
}
103103

104-
let self_ty_fp = TyFingerprint::for_impl(&ty);
104+
let self_ty_fp = TyFingerprint::for_trait_impl(&ty);
105105
let fps: &[TyFingerprint] = match binder_kind(&ty, binders) {
106106
Some(chalk_ir::TyVariableKind::Integer) => &ALL_INT_FPS,
107107
Some(chalk_ir::TyVariableKind::Float) => &ALL_FLOAT_FPS,

0 commit comments

Comments
 (0)