From a3c2f5126fb9f2575584d12335b6e7e82deec45a Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 20 Jun 2020 00:36:02 +0200 Subject: Recursively compute impl sets --- crates/ra_hir_ty/src/method_resolution.rs | 39 ++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index be685e12f..ed638c195 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -65,26 +65,20 @@ impl CrateImplDefs { db: &dyn HirDatabase, krate: CrateId, ) -> Arc { - // FIXME: This should take visibility and orphan rules into account to keep the result - // smaller. let _p = profile("impls_from_deps_query"); let crate_graph = db.crate_graph(); let mut res = CrateImplDefs { inherent_impls: FxHashMap::default(), impls_by_trait: FxHashMap::default(), }; - let mut seen = FxHashSet::default(); - let mut worklist = - crate_graph[krate].dependencies.iter().map(|dep| dep.crate_id).collect::>(); - while let Some(krate) = worklist.pop() { - if !seen.insert(krate) { - continue; - } - - // No deduplication, since a) impls can't be reexported, b) we visit a crate only once - res.fill(db, krate); - worklist.extend(crate_graph[krate].dependencies.iter().map(|dep| dep.crate_id)); + // For each dependency, calculate `impls_from_deps` recursively, then add its own + // `impls_in_crate`. + // As we might visit crates multiple times, `merge` has to deduplicate impls to avoid + // wasting memory. + for dep in &crate_graph[krate].dependencies { + res.merge(&db.impls_from_deps(dep.crate_id)); + res.merge(&db.impls_in_crate(dep.crate_id)); } Arc::new(res) @@ -116,6 +110,25 @@ impl CrateImplDefs { } } + fn merge(&mut self, other: &Self) { + for (fp, impls) in &other.inherent_impls { + let vec = self.inherent_impls.entry(*fp).or_default(); + vec.extend(impls); + vec.sort(); + vec.dedup(); + } + + for (trait_, other_map) in &other.impls_by_trait { + let map = self.impls_by_trait.entry(*trait_).or_default(); + for (fp, impls) in other_map { + let vec = map.entry(*fp).or_default(); + vec.extend(impls); + vec.sort(); + vec.dedup(); + } + } + } + pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator + '_ { let fingerprint = TyFingerprint::for_impl(ty); fingerprint.and_then(|f| self.inherent_impls.get(&f)).into_iter().flatten().copied() -- cgit v1.2.3