diff options
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/db.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 57 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 31 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk.rs | 28 |
4 files changed, 74 insertions, 57 deletions
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index bf71d38d6..7889b8d2c 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs | |||
@@ -3,15 +3,15 @@ | |||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::{ | 5 | use hir_def::{ |
6 | db::DefDatabase, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, TraitId, | 6 | db::DefDatabase, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, TypeParamId, |
7 | TypeParamId, VariantId, | 7 | VariantId, |
8 | }; | 8 | }; |
9 | use ra_arena::map::ArenaMap; | 9 | use ra_arena::map::ArenaMap; |
10 | use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; | 10 | use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; |
11 | use ra_prof::profile; | 11 | use ra_prof::profile; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | method_resolution::{CrateImplDefs, TyFingerprint}, | 14 | method_resolution::CrateImplDefs, |
15 | traits::{chalk, AssocTyValue, Impl}, | 15 | traits::{chalk, AssocTyValue, Impl}, |
16 | Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, | 16 | Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, |
17 | ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, | 17 | ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, |
@@ -70,13 +70,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
70 | #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)] | 70 | #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)] |
71 | fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; | 71 | fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; |
72 | 72 | ||
73 | #[salsa::invoke(crate::traits::impls_for_trait_query)] | 73 | #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_from_deps_query)] |
74 | fn impls_for_trait( | 74 | fn impls_from_deps(&self, krate: CrateId) -> Arc<CrateImplDefs>; |
75 | &self, | ||
76 | krate: CrateId, | ||
77 | trait_: TraitId, | ||
78 | self_ty_fp: Option<TyFingerprint>, | ||
79 | ) -> Arc<[ImplId]>; | ||
80 | 75 | ||
81 | // Interned IDs for Chalk integration | 76 | // Interned IDs for Chalk integration |
82 | #[salsa::interned] | 77 | #[salsa::interned] |
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index e83b39456..01b3362d7 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -38,18 +38,58 @@ impl TyFingerprint { | |||
38 | } | 38 | } |
39 | } | 39 | } |
40 | 40 | ||
41 | /// A queryable and mergeable collection of impls. | ||
41 | #[derive(Debug, PartialEq, Eq)] | 42 | #[derive(Debug, PartialEq, Eq)] |
42 | pub struct CrateImplDefs { | 43 | pub struct CrateImplDefs { |
43 | impls: FxHashMap<TyFingerprint, Vec<ImplId>>, | 44 | inherent_impls: FxHashMap<TyFingerprint, Vec<ImplId>>, |
44 | impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, | 45 | impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, |
45 | } | 46 | } |
46 | 47 | ||
47 | impl CrateImplDefs { | 48 | impl CrateImplDefs { |
48 | pub(crate) fn impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<CrateImplDefs> { | 49 | pub(crate) fn impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<CrateImplDefs> { |
49 | let _p = profile("impls_in_crate_query"); | 50 | let _p = profile("impls_in_crate_query"); |
50 | let mut res = | 51 | let mut res = CrateImplDefs { |
51 | CrateImplDefs { impls: FxHashMap::default(), impls_by_trait: FxHashMap::default() }; | 52 | inherent_impls: FxHashMap::default(), |
53 | impls_by_trait: FxHashMap::default(), | ||
54 | }; | ||
55 | res.fill(db, krate); | ||
56 | |||
57 | Arc::new(res) | ||
58 | } | ||
59 | |||
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 | // FIXME: This should take visibility and orphan rules into account to keep the result | ||
69 | // smaller. | ||
70 | let _p = profile("impls_from_deps_query"); | ||
71 | let crate_graph = db.crate_graph(); | ||
72 | let mut res = CrateImplDefs { | ||
73 | inherent_impls: FxHashMap::default(), | ||
74 | impls_by_trait: FxHashMap::default(), | ||
75 | }; | ||
76 | let mut seen = FxHashSet::default(); | ||
77 | let mut worklist = vec![krate]; | ||
78 | while let Some(krate) = worklist.pop() { | ||
79 | if !seen.insert(krate) { | ||
80 | continue; | ||
81 | } | ||
52 | 82 | ||
83 | // No deduplication, since a) impls can't be reexported, b) we visit a crate only once | ||
84 | res.fill(db, krate); | ||
85 | |||
86 | worklist.extend(crate_graph[krate].dependencies.iter().map(|dep| dep.crate_id)); | ||
87 | } | ||
88 | |||
89 | Arc::new(res) | ||
90 | } | ||
91 | |||
92 | fn fill(&mut self, db: &dyn HirDatabase, krate: CrateId) { | ||
53 | let crate_def_map = db.crate_def_map(krate); | 93 | let crate_def_map = db.crate_def_map(krate); |
54 | for (_module_id, module_data) in crate_def_map.modules.iter() { | 94 | for (_module_id, module_data) in crate_def_map.modules.iter() { |
55 | for impl_id in module_data.scope.impls() { | 95 | for impl_id in module_data.scope.impls() { |
@@ -57,7 +97,7 @@ impl CrateImplDefs { | |||
57 | Some(tr) => { | 97 | Some(tr) => { |
58 | let self_ty = db.impl_self_ty(impl_id); | 98 | let self_ty = db.impl_self_ty(impl_id); |
59 | let self_ty_fp = TyFingerprint::for_impl(&self_ty.value); | 99 | let self_ty_fp = TyFingerprint::for_impl(&self_ty.value); |
60 | res.impls_by_trait | 100 | self.impls_by_trait |
61 | .entry(tr.value.trait_) | 101 | .entry(tr.value.trait_) |
62 | .or_default() | 102 | .or_default() |
63 | .entry(self_ty_fp) | 103 | .entry(self_ty_fp) |
@@ -67,18 +107,17 @@ impl CrateImplDefs { | |||
67 | None => { | 107 | None => { |
68 | let self_ty = db.impl_self_ty(impl_id); | 108 | let self_ty = db.impl_self_ty(impl_id); |
69 | if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) { | 109 | if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) { |
70 | res.impls.entry(self_ty_fp).or_default().push(impl_id); | 110 | self.inherent_impls.entry(self_ty_fp).or_default().push(impl_id); |
71 | } | 111 | } |
72 | } | 112 | } |
73 | } | 113 | } |
74 | } | 114 | } |
75 | } | 115 | } |
76 | |||
77 | Arc::new(res) | ||
78 | } | 116 | } |
117 | |||
79 | pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator<Item = ImplId> + '_ { | 118 | pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator<Item = ImplId> + '_ { |
80 | let fingerprint = TyFingerprint::for_impl(ty); | 119 | let fingerprint = TyFingerprint::for_impl(ty); |
81 | fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flatten().copied() | 120 | fingerprint.and_then(|f| self.inherent_impls.get(&f)).into_iter().flatten().copied() |
82 | } | 121 | } |
83 | 122 | ||
84 | pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ { | 123 | pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ { |
@@ -110,7 +149,7 @@ impl CrateImplDefs { | |||
110 | } | 149 | } |
111 | 150 | ||
112 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { | 151 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { |
113 | self.impls | 152 | self.inherent_impls |
114 | .values() | 153 | .values() |
115 | .chain(self.impls_by_trait.values().flat_map(|m| m.values())) | 154 | .chain(self.impls_by_trait.values().flat_map(|m| m.values())) |
116 | .flatten() | 155 | .flatten() |
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 6bc6d474c..99d7a9616 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs | |||
@@ -5,9 +5,8 @@ use chalk_ir::cast::Cast; | |||
5 | use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; | 5 | use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; |
6 | use ra_db::{impl_intern_key, salsa, CrateId}; | 6 | use ra_db::{impl_intern_key, salsa, CrateId}; |
7 | use ra_prof::profile; | 7 | use ra_prof::profile; |
8 | use rustc_hash::FxHashSet; | ||
9 | 8 | ||
10 | use crate::{db::HirDatabase, method_resolution::TyFingerprint, DebruijnIndex}; | 9 | use crate::{db::HirDatabase, DebruijnIndex}; |
11 | 10 | ||
12 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; | 11 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; |
13 | 12 | ||
@@ -36,34 +35,6 @@ fn create_chalk_solver() -> chalk_solve::Solver<Interner> { | |||
36 | solver_choice.into_solver() | 35 | solver_choice.into_solver() |
37 | } | 36 | } |
38 | 37 | ||
39 | /// Collects impls for the given trait in the whole dependency tree of `krate`. | ||
40 | pub(crate) fn impls_for_trait_query( | ||
41 | db: &dyn HirDatabase, | ||
42 | krate: CrateId, | ||
43 | trait_: TraitId, | ||
44 | self_ty_fp: Option<TyFingerprint>, | ||
45 | ) -> Arc<[ImplId]> { | ||
46 | // FIXME: We could be a lot smarter here - because of the orphan rules and | ||
47 | // the fact that the trait and the self type need to be in the dependency | ||
48 | // tree of a crate somewhere for an impl to exist, we could skip looking in | ||
49 | // a lot of crates completely | ||
50 | let mut impls = FxHashSet::default(); | ||
51 | // We call the query recursively here. On the one hand, this means we can | ||
52 | // reuse results from queries for different crates; on the other hand, this | ||
53 | // will only ever get called for a few crates near the root of the tree (the | ||
54 | // ones the user is editing), so this may actually be a waste of memory. I'm | ||
55 | // doing it like this mainly for simplicity for now. | ||
56 | for dep in &db.crate_graph()[krate].dependencies { | ||
57 | impls.extend(db.impls_for_trait(dep.crate_id, trait_, self_ty_fp).iter()); | ||
58 | } | ||
59 | let crate_impl_defs = db.impls_in_crate(krate); | ||
60 | match self_ty_fp { | ||
61 | Some(fp) => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp)), | ||
62 | None => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait(trait_)), | ||
63 | } | ||
64 | impls.into_iter().collect() | ||
65 | } | ||
66 | |||
67 | /// A set of clauses that we assume to be true. E.g. if we are inside this function: | 38 | /// A set of clauses that we assume to be true. E.g. if we are inside this function: |
68 | /// ```rust | 39 | /// ```rust |
69 | /// fn foo<T: Default>(t: T) {} | 40 | /// fn foo<T: Default>(t: T) {} |
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index a72a82f5a..2f35d6d49 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs | |||
@@ -74,14 +74,26 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
74 | // Note: Since we're using impls_for_trait, only impls where the trait | 74 | // Note: Since we're using impls_for_trait, only impls where the trait |
75 | // can be resolved should ever reach Chalk. `impl_datum` relies on that | 75 | // can be resolved should ever reach Chalk. `impl_datum` relies on that |
76 | // and will panic if the trait can't be resolved. | 76 | // and will panic if the trait can't be resolved. |
77 | let mut result: Vec<_> = self | 77 | let in_deps = self.db.impls_from_deps(self.krate); |
78 | .db | 78 | let in_self = self.db.impls_in_crate(self.krate); |
79 | .impls_for_trait(self.krate, trait_, self_ty_fp) | 79 | let impl_maps = [in_deps, in_self]; |
80 | .iter() | 80 | |
81 | .copied() | 81 | let id_to_chalk = |id: hir_def::ImplId| Impl::ImplDef(id).to_chalk(self.db); |
82 | .map(Impl::ImplDef) | 82 | |
83 | .map(|impl_| impl_.to_chalk(self.db)) | 83 | let mut result: Vec<_> = match self_ty_fp { |
84 | .collect(); | 84 | Some(fp) => impl_maps |
85 | .iter() | ||
86 | .flat_map(|crate_impl_defs| { | ||
87 | crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp).map(id_to_chalk) | ||
88 | }) | ||
89 | .collect(), | ||
90 | None => impl_maps | ||
91 | .iter() | ||
92 | .flat_map(|crate_impl_defs| { | ||
93 | crate_impl_defs.lookup_impl_defs_for_trait(trait_).map(id_to_chalk) | ||
94 | }) | ||
95 | .collect(), | ||
96 | }; | ||
85 | 97 | ||
86 | let arg: Option<Ty> = | 98 | let arg: Option<Ty> = |
87 | parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone())); | 99 | parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone())); |