aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/method_resolution.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty/method_resolution.rs')
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs60
1 files changed, 46 insertions, 14 deletions
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index b1684acf9..708a435b4 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -11,7 +11,7 @@ use crate::{
11 ids::TraitId, 11 ids::TraitId,
12 impl_block::{ImplId, ImplBlock, ImplItem}, 12 impl_block::{ImplId, ImplBlock, ImplItem},
13 ty::{Ty, TypeCtor}, 13 ty::{Ty, TypeCtor},
14 nameres::CrateModuleId, 14 nameres::CrateModuleId, resolve::Resolver, traits::TraitItem
15 15
16}; 16};
17 17
@@ -73,18 +73,18 @@ impl CrateImplBlocks {
73 73
74 let target_ty = impl_block.target_ty(db); 74 let target_ty = impl_block.target_ty(db);
75 75
76 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
77 self.impls
78 .entry(target_ty_fp)
79 .or_insert_with(Vec::new)
80 .push((module.module_id, impl_id));
81 }
82
83 if let Some(tr) = impl_block.target_trait(db) { 76 if let Some(tr) = impl_block.target_trait(db) {
84 self.impls_by_trait 77 self.impls_by_trait
85 .entry(tr.id) 78 .entry(tr.id)
86 .or_insert_with(Vec::new) 79 .or_insert_with(Vec::new)
87 .push((module.module_id, impl_id)); 80 .push((module.module_id, impl_id));
81 } else {
82 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
83 self.impls
84 .entry(target_ty_fp)
85 .or_insert_with(Vec::new)
86 .push((module.module_id, impl_id));
87 }
88 } 88 }
89 } 89 }
90 90
@@ -120,20 +120,52 @@ fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> {
120} 120}
121 121
122impl Ty { 122impl Ty {
123 // FIXME: cache this as a query?
124 // - if so, what signature? (TyFingerprint, Name)?
125 // - or maybe cache all names and def_ids of methods per fingerprint?
126 /// Look up the method with the given name, returning the actual autoderefed 123 /// Look up the method with the given name, returning the actual autoderefed
127 /// receiver type (but without autoref applied yet). 124 /// receiver type (but without autoref applied yet).
128 pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<(Ty, Function)> { 125 pub fn lookup_method(
129 self.iterate_methods(db, |ty, f| { 126 self,
127 db: &impl HirDatabase,
128 name: &Name,
129 resolver: &Resolver,
130 ) -> Option<(Ty, Function)> {
131 // FIXME: what has priority, an inherent method that needs autoderefs or a trait method?
132 let inherent_method = self.clone().iterate_methods(db, |ty, f| {
130 let sig = f.signature(db); 133 let sig = f.signature(db);
131 if sig.name() == name && sig.has_self_param() { 134 if sig.name() == name && sig.has_self_param() {
132 Some((ty.clone(), f)) 135 Some((ty.clone(), f))
133 } else { 136 } else {
134 None 137 None
135 } 138 }
136 }) 139 });
140 inherent_method.or_else(|| self.lookup_trait_method(db, name, resolver))
141 }
142
143 fn lookup_trait_method(
144 self,
145 db: &impl HirDatabase,
146 name: &Name,
147 resolver: &Resolver,
148 ) -> Option<(Ty, Function)> {
149 let mut candidates = Vec::new();
150 for t in resolver.traits_in_scope() {
151 let data = t.trait_data(db);
152 for item in data.items() {
153 match item {
154 &TraitItem::Function(m) => {
155 let sig = m.signature(db);
156 if sig.name() == name && sig.has_self_param() {
157 candidates.push((t, m));
158 }
159 }
160 _ => {}
161 }
162 }
163 }
164 // FIXME the implements check may result in other obligations or unifying variables?
165 candidates.retain(|(_t, _m)| /* self implements t */ true);
166 // FIXME what happens if there are still multiple potential candidates?
167 let (_chosen_trait, chosen_method) = candidates.first()?;
168 Some((self.clone(), *chosen_method))
137 } 169 }
138 170
139 // This would be nicer if it just returned an iterator, but that runs into 171 // This would be nicer if it just returned an iterator, but that runs into