4947: Replace `impls_in_trait` query with smarter use of `CrateImplDefs` r=matklad a=jonas-schievink

`impls_in_trait` was allocating a whopping ~400 MB of RAM when running analysis-stats on r-a itself.

Remove it, instead adding a query that computes a summary `CrateImplDefs` map for all transitive dependencies. This can probably still be made more efficient, but this already reduces the peak memory usage by 25% without much performance impact on analysis-stats.

**Before**:

```
Total: 34.962107188s, 2083mb allocated 2141mb resident
   422mb ImplsForTraitQuery (deps)
   250mb CrateDefMapQueryQuery
   147mb MacroArgQuery
   140mb TraitSolveQuery (deps)
    68mb InferQueryQuery (deps)
    62mb ImplDatumQuery (deps)
```

**After**:

```
Total: 35.261100358s, 1520mb allocated 1569mb resident
   250mb CrateDefMapQueryQuery
   147mb MacroArgQuery
   144mb TraitSolveQuery (deps)
    68mb InferQueryQuery (deps)
    61mb ImplDatumQuery (deps)
    45mb BodyQuery
    45mb ImplDatumQuery
```

Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
bors[bot]
2020-06-20 22:14:21 +00:00
committed by GitHub
7 changed files with 91 additions and 60 deletions

View File

@@ -7,9 +7,8 @@ use hir_def::{
};
use ra_db::{impl_intern_key, salsa, CrateId};
use ra_prof::profile;
use rustc_hash::FxHashSet;
use crate::{db::HirDatabase, method_resolution::TyFingerprint, DebruijnIndex};
use crate::{db::HirDatabase, DebruijnIndex};
use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
@@ -38,34 +37,6 @@ fn create_chalk_solver() -> chalk_solve::Solver<Interner> {
solver_choice.into_solver()
}
/// Collects impls for the given trait in the whole dependency tree of `krate`.
pub(crate) fn impls_for_trait_query(
db: &dyn HirDatabase,
krate: CrateId,
trait_: TraitId,
self_ty_fp: Option<TyFingerprint>,
) -> Arc<[ImplId]> {
// FIXME: We could be a lot smarter here - because of the orphan rules and
// the fact that the trait and the self type need to be in the dependency
// tree of a crate somewhere for an impl to exist, we could skip looking in
// a lot of crates completely
let mut impls = FxHashSet::default();
// We call the query recursively here. On the one hand, this means we can
// reuse results from queries for different crates; on the other hand, this
// will only ever get called for a few crates near the root of the tree (the
// ones the user is editing), so this may actually be a waste of memory. I'm
// doing it like this mainly for simplicity for now.
for dep in &db.crate_graph()[krate].dependencies {
impls.extend(db.impls_for_trait(dep.crate_id, trait_, self_ty_fp).iter());
}
let crate_impl_defs = db.impls_in_crate(krate);
match self_ty_fp {
Some(fp) => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp)),
None => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait(trait_)),
}
impls.into_iter().collect()
}
/// A set of clauses that we assume to be true. E.g. if we are inside this function:
/// ```rust
/// fn foo<T: Default>(t: T) {}