Skip to content

Commit ad1a0e6

Browse files
bors[bot]Jonas Schievink
andauthored
Merge #5175
5175: More memory-efficient impl collection r=matklad a=jonas-schievink This saves roughly 90 MB in `ImplsFromDepsQuery`, which used to copy the list of all impls from libcore into *every* crate in the graph. It also stops collecting inherent impls from dependencies entirely, as those can only be located within the crate defining the self type. Co-authored-by: Jonas Schievink <[email protected]>
2 parents 8943c2c + 6bde542 commit ad1a0e6

File tree

8 files changed

+148
-128
lines changed

8 files changed

+148
-128
lines changed

crates/ra_db/src/input.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,23 @@ impl CrateGraph {
197197
self.arena.keys().copied()
198198
}
199199

200+
/// Returns an iterator over all transitive dependencies of the given crate.
201+
pub fn transitive_deps(&self, of: CrateId) -> impl Iterator<Item = CrateId> + '_ {
202+
let mut worklist = vec![of];
203+
let mut deps = FxHashSet::default();
204+
205+
while let Some(krate) = worklist.pop() {
206+
if !deps.insert(krate) {
207+
continue;
208+
}
209+
210+
worklist.extend(self[krate].dependencies.iter().map(|dep| dep.crate_id));
211+
}
212+
213+
deps.remove(&of);
214+
deps.into_iter()
215+
}
216+
200217
// FIXME: this only finds one crate with the given root; we could have multiple
201218
pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
202219
let (&crate_id, _) =

crates/ra_hir/src/code_model.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,12 +1053,14 @@ pub struct ImplDef {
10531053

10541054
impl ImplDef {
10551055
pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<ImplDef> {
1056-
let impls = db.impls_in_crate(krate.id);
1057-
impls.all_impls().map(Self::from).collect()
1056+
let inherent = db.inherent_impls_in_crate(krate.id);
1057+
let trait_ = db.trait_impls_in_crate(krate.id);
1058+
1059+
inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
10581060
}
10591061
pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<ImplDef> {
1060-
let impls = db.impls_in_crate(krate.id);
1061-
impls.lookup_impl_defs_for_trait(trait_.id).map(Self::from).collect()
1062+
let impls = db.trait_impls_in_crate(krate.id);
1063+
impls.for_trait(trait_.id).map(Self::from).collect()
10621064
}
10631065

10641066
pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> {
@@ -1303,10 +1305,10 @@ impl Type {
13031305
mut callback: impl FnMut(AssocItem) -> Option<T>,
13041306
) -> Option<T> {
13051307
for krate in self.ty.value.def_crates(db, krate.id)? {
1306-
let impls = db.impls_in_crate(krate);
1308+
let impls = db.inherent_impls_in_crate(krate);
13071309

1308-
for impl_def in impls.lookup_impl_defs(&self.ty.value) {
1309-
for &item in db.impl_data(impl_def).items.iter() {
1310+
for impl_def in impls.for_self_ty(&self.ty.value) {
1311+
for &item in db.impl_data(*impl_def).items.iter() {
13101312
if let Some(result) = callback(item.into()) {
13111313
return Some(result);
13121314
}

crates/ra_hir/src/db.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ pub use hir_expand::db::{
1616
pub use hir_ty::db::{
1717
AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery,
1818
GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase,
19-
HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsFromDepsQuery,
20-
ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery,
21-
InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery,
22-
TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery,
19+
HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, InferQueryQuery,
20+
InherentImplsInCrateQuery, InternAssocTyValueQuery, InternChalkImplQuery, InternTypeCtorQuery,
21+
InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery, TraitDatumQuery,
22+
TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery, ValueTyQuery,
2323
};
2424

2525
#[test]

crates/ra_hir_ty/src/db.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use ra_db::{impl_intern_key, salsa, CrateId, Upcast};
1111
use ra_prof::profile;
1212

1313
use crate::{
14-
method_resolution::CrateImplDefs,
14+
method_resolution::{InherentImpls, TraitImpls},
1515
traits::{chalk, AssocTyValue, Impl},
1616
Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig,
1717
ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId,
@@ -67,11 +67,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
6767
#[salsa::invoke(crate::lower::generic_defaults_query)]
6868
fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
6969

70-
#[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)]
71-
fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>;
70+
#[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
71+
fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
7272

73-
#[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_from_deps_query)]
74-
fn impls_from_deps(&self, krate: CrateId) -> Arc<CrateImplDefs>;
73+
#[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
74+
fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
75+
76+
#[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
77+
fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
7578

7679
// Interned IDs for Chalk integration
7780
#[salsa::interned]

crates/ra_hir_ty/src/method_resolution.rs

Lines changed: 99 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -38,136 +38,131 @@ impl TyFingerprint {
3838
}
3939
}
4040

41-
/// A queryable and mergeable collection of impls.
42-
#[derive(Debug, PartialEq, Eq)]
43-
pub struct CrateImplDefs {
44-
inherent_impls: FxHashMap<TyFingerprint, Vec<ImplId>>,
45-
impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
41+
/// Trait impls defined or available in some crate.
42+
#[derive(Debug, Eq, PartialEq)]
43+
pub struct TraitImpls {
44+
// If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
45+
map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
4646
}
4747

48-
impl CrateImplDefs {
49-
pub(crate) fn impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<CrateImplDefs> {
50-
let _p = profile("impls_in_crate_query");
51-
let mut res = CrateImplDefs {
52-
inherent_impls: FxHashMap::default(),
53-
impls_by_trait: FxHashMap::default(),
54-
};
55-
res.fill(db, krate);
48+
impl TraitImpls {
49+
pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
50+
let _p = profile("trait_impls_in_crate_query");
51+
let mut impls = Self { map: FxHashMap::default() };
5652

57-
Arc::new(res)
53+
let crate_def_map = db.crate_def_map(krate);
54+
for (_module_id, module_data) in crate_def_map.modules.iter() {
55+
for impl_id in module_data.scope.impls() {
56+
let target_trait = match db.impl_trait(impl_id) {
57+
Some(tr) => tr.value.trait_,
58+
None => continue,
59+
};
60+
let self_ty = db.impl_self_ty(impl_id);
61+
let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
62+
impls
63+
.map
64+
.entry(target_trait)
65+
.or_default()
66+
.entry(self_ty_fp)
67+
.or_default()
68+
.push(impl_id);
69+
}
70+
}
71+
72+
Arc::new(impls)
5873
}
5974

60-
/// Collects all impls from transitive dependencies of `krate` that may be used by `krate`.
61-
///
62-
/// The full set of impls that can be used by `krate` is the returned map plus all the impls
63-
/// from `krate` itself.
64-
pub(crate) fn impls_from_deps_query(
65-
db: &dyn HirDatabase,
66-
krate: CrateId,
67-
) -> Arc<CrateImplDefs> {
68-
let _p = profile("impls_from_deps_query");
75+
pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
76+
let _p = profile("trait_impls_in_deps_query");
6977
let crate_graph = db.crate_graph();
70-
let mut res = CrateImplDefs {
71-
inherent_impls: FxHashMap::default(),
72-
impls_by_trait: FxHashMap::default(),
73-
};
78+
let mut res = Self { map: FxHashMap::default() };
7479

75-
// For each dependency, calculate `impls_from_deps` recursively, then add its own
76-
// `impls_in_crate`.
77-
// As we might visit crates multiple times, `merge` has to deduplicate impls to avoid
78-
// wasting memory.
79-
for dep in &crate_graph[krate].dependencies {
80-
res.merge(&db.impls_from_deps(dep.crate_id));
81-
res.merge(&db.impls_in_crate(dep.crate_id));
80+
for krate in crate_graph.transitive_deps(krate) {
81+
res.merge(&db.trait_impls_in_crate(krate));
8282
}
8383

8484
Arc::new(res)
8585
}
8686

87-
fn fill(&mut self, db: &dyn HirDatabase, krate: CrateId) {
88-
let crate_def_map = db.crate_def_map(krate);
89-
for (_module_id, module_data) in crate_def_map.modules.iter() {
90-
for impl_id in module_data.scope.impls() {
91-
match db.impl_trait(impl_id) {
92-
Some(tr) => {
93-
let self_ty = db.impl_self_ty(impl_id);
94-
let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
95-
self.impls_by_trait
96-
.entry(tr.value.trait_)
97-
.or_default()
98-
.entry(self_ty_fp)
99-
.or_default()
100-
.push(impl_id);
101-
}
102-
None => {
103-
let self_ty = db.impl_self_ty(impl_id);
104-
if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) {
105-
self.inherent_impls.entry(self_ty_fp).or_default().push(impl_id);
106-
}
107-
}
108-
}
109-
}
110-
}
111-
}
112-
11387
fn merge(&mut self, other: &Self) {
114-
for (fp, impls) in &other.inherent_impls {
115-
let vec = self.inherent_impls.entry(*fp).or_default();
116-
vec.extend(impls);
117-
vec.sort();
118-
vec.dedup();
119-
}
120-
121-
for (trait_, other_map) in &other.impls_by_trait {
122-
let map = self.impls_by_trait.entry(*trait_).or_default();
88+
for (trait_, other_map) in &other.map {
89+
let map = self.map.entry(*trait_).or_default();
12390
for (fp, impls) in other_map {
12491
let vec = map.entry(*fp).or_default();
12592
vec.extend(impls);
126-
vec.sort();
127-
vec.dedup();
12893
}
12994
}
13095
}
13196

132-
pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator<Item = ImplId> + '_ {
133-
let fingerprint = TyFingerprint::for_impl(ty);
134-
fingerprint.and_then(|f| self.inherent_impls.get(&f)).into_iter().flatten().copied()
135-
}
136-
137-
pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ {
138-
self.impls_by_trait
139-
.get(&tr)
97+
/// Queries all impls of the given trait.
98+
pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ {
99+
self.map
100+
.get(&trait_)
140101
.into_iter()
141-
.flat_map(|m| m.values().flat_map(|v| v.iter().copied()))
102+
.flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
142103
}
143104

144-
pub fn lookup_impl_defs_for_trait_and_ty(
105+
/// Queries all impls of `trait_` that may apply to `self_ty`.
106+
pub fn for_trait_and_self_ty(
145107
&self,
146-
tr: TraitId,
147-
fp: TyFingerprint,
108+
trait_: TraitId,
109+
self_ty: TyFingerprint,
148110
) -> impl Iterator<Item = ImplId> + '_ {
149-
self.impls_by_trait
150-
.get(&tr)
151-
.and_then(|m| m.get(&Some(fp)))
111+
self.map
112+
.get(&trait_)
152113
.into_iter()
153-
.flatten()
154-
.copied()
155-
.chain(
156-
self.impls_by_trait
157-
.get(&tr)
158-
.and_then(|m| m.get(&None))
159-
.into_iter()
160-
.flatten()
161-
.copied(),
162-
)
114+
.flat_map(move |map| map.get(&None).into_iter().chain(map.get(&Some(self_ty))))
115+
.flat_map(|v| v.iter().copied())
116+
}
117+
118+
pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
119+
self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
120+
}
121+
}
122+
123+
/// Inherent impls defined in some crate.
124+
///
125+
/// Inherent impls can only be defined in the crate that also defines the self type of the impl
126+
/// (note that some primitives are considered to be defined by both libcore and liballoc).
127+
///
128+
/// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a
129+
/// single crate.
130+
#[derive(Debug, Eq, PartialEq)]
131+
pub struct InherentImpls {
132+
map: FxHashMap<TyFingerprint, Vec<ImplId>>,
133+
}
134+
135+
impl InherentImpls {
136+
pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
137+
let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default();
138+
139+
let crate_def_map = db.crate_def_map(krate);
140+
for (_module_id, module_data) in crate_def_map.modules.iter() {
141+
for impl_id in module_data.scope.impls() {
142+
let data = db.impl_data(impl_id);
143+
if data.target_trait.is_some() {
144+
continue;
145+
}
146+
147+
let self_ty = db.impl_self_ty(impl_id);
148+
if let Some(fp) = TyFingerprint::for_impl(&self_ty.value) {
149+
map.entry(fp).or_default().push(impl_id);
150+
}
151+
}
152+
}
153+
154+
Arc::new(Self { map })
155+
}
156+
157+
pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
158+
match TyFingerprint::for_impl(self_ty) {
159+
Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
160+
None => &[],
161+
}
163162
}
164163

165-
pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a {
166-
self.inherent_impls
167-
.values()
168-
.chain(self.impls_by_trait.values().flat_map(|m| m.values()))
169-
.flatten()
170-
.copied()
164+
pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
165+
self.map.values().flat_map(|v| v.iter().copied())
171166
}
172167
}
173168

@@ -524,9 +519,9 @@ fn iterate_inherent_methods(
524519
None => return false,
525520
};
526521
for krate in def_crates {
527-
let impls = db.impls_in_crate(krate);
522+
let impls = db.inherent_impls_in_crate(krate);
528523

529-
for impl_def in impls.lookup_impl_defs(&self_ty.value) {
524+
for &impl_def in impls.for_self_ty(&self_ty.value) {
530525
for &item in db.impl_data(impl_def).items.iter() {
531526
if !is_valid_candidate(db, name, receiver_ty, item, self_ty) {
532527
continue;

crates/ra_hir_ty/src/traits/chalk.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
7777
// Note: Since we're using impls_for_trait, only impls where the trait
7878
// can be resolved should ever reach Chalk. `impl_datum` relies on that
7979
// and will panic if the trait can't be resolved.
80-
let in_deps = self.db.impls_from_deps(self.krate);
81-
let in_self = self.db.impls_in_crate(self.krate);
80+
let in_deps = self.db.trait_impls_in_deps(self.krate);
81+
let in_self = self.db.trait_impls_in_crate(self.krate);
8282
let impl_maps = [in_deps, in_self];
8383

8484
let id_to_chalk = |id: hir_def::ImplId| Impl::ImplDef(id).to_chalk(self.db);
@@ -87,14 +87,12 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
8787
Some(fp) => impl_maps
8888
.iter()
8989
.flat_map(|crate_impl_defs| {
90-
crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp).map(id_to_chalk)
90+
crate_impl_defs.for_trait_and_self_ty(trait_, fp).map(id_to_chalk)
9191
})
9292
.collect(),
9393
None => impl_maps
9494
.iter()
95-
.flat_map(|crate_impl_defs| {
96-
crate_impl_defs.lookup_impl_defs_for_trait(trait_).map(id_to_chalk)
97-
})
95+
.flat_map(|crate_impl_defs| crate_impl_defs.for_trait(trait_).map(id_to_chalk))
9896
.collect(),
9997
};
10098

crates/ra_ide/src/goto_implementation.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ impl T for &Foo {}
219219
#[derive(Copy)]
220220
//^^^^^^^^^^^^^^^
221221
struct Foo<|>;
222+
223+
mod marker {
224+
trait Copy {}
225+
}
222226
"#,
223227
);
224228
}

crates/ra_ide_db/src/change.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,9 @@ impl RootDatabase {
243243
hir::db::GenericPredicatesForParamQuery
244244
hir::db::GenericPredicatesQuery
245245
hir::db::GenericDefaultsQuery
246-
hir::db::ImplsInCrateQuery
247-
hir::db::ImplsFromDepsQuery
246+
hir::db::InherentImplsInCrateQuery
247+
hir::db::TraitImplsInCrateQuery
248+
hir::db::TraitImplsInDepsQuery
248249
hir::db::InternTypeCtorQuery
249250
hir::db::InternTypeParamIdQuery
250251
hir::db::InternChalkImplQuery

0 commit comments

Comments
 (0)