diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-04-14 20:55:18 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-04-14 20:55:18 +0100 |
commit | e1a2649aff0a9387fb14646a56cb652061bc42ec (patch) | |
tree | b8275843aa56b922b6325b50be2aae063234cc2a /crates/ra_hir/src/ty/method_resolution.rs | |
parent | 88be6f32172813f53dae60d73c9f5deb0c3fb29f (diff) | |
parent | 4f8a49f43cad086a656626c43062ff89b46f505a (diff) |
Merge #1144
1144: Refactor method candidate generation a bit r=flodiebold a=flodiebold
This fixes the order in which candidates are chosen a bit (not completely though, as the ignored test demonstrates), and makes autoderef work with trait methods.
As a side effect, this also makes completion of trait methods work :)
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty/method_resolution.rs')
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 126 |
1 files changed, 73 insertions, 53 deletions
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 6b7918187..667b66095 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -129,85 +129,105 @@ impl Ty { | |||
129 | name: &Name, | 129 | name: &Name, |
130 | resolver: &Resolver, | 130 | resolver: &Resolver, |
131 | ) -> Option<(Ty, Function)> { | 131 | ) -> Option<(Ty, Function)> { |
132 | // FIXME: trait methods should be used before autoderefs | 132 | self.iterate_method_candidates(db, resolver, Some(name), |ty, f| Some((ty.clone(), f))) |
133 | // (and we need to do autoderefs for trait method calls as well) | ||
134 | let inherent_method = self.clone().iterate_methods(db, |ty, f| { | ||
135 | let sig = f.signature(db); | ||
136 | if sig.name() == name && sig.has_self_param() { | ||
137 | Some((ty.clone(), f)) | ||
138 | } else { | ||
139 | None | ||
140 | } | ||
141 | }); | ||
142 | inherent_method.or_else(|| self.lookup_trait_method(db, name, resolver)) | ||
143 | } | 133 | } |
144 | 134 | ||
145 | fn lookup_trait_method( | 135 | // This would be nicer if it just returned an iterator, but that runs into |
136 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. | ||
137 | pub(crate) fn iterate_method_candidates<T>( | ||
146 | self, | 138 | self, |
147 | db: &impl HirDatabase, | 139 | db: &impl HirDatabase, |
148 | name: &Name, | ||
149 | resolver: &Resolver, | 140 | resolver: &Resolver, |
150 | ) -> Option<(Ty, Function)> { | 141 | name: Option<&Name>, |
151 | let mut candidates = Vec::new(); | 142 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
152 | for t in resolver.traits_in_scope() { | 143 | ) -> Option<T> { |
144 | // For method calls, rust first does any number of autoderef, and then one | ||
145 | // autoref (i.e. when the method takes &self or &mut self). We just ignore | ||
146 | // the autoref currently -- when we find a method matching the given name, | ||
147 | // we assume it fits. | ||
148 | |||
149 | // Also note that when we've got a receiver like &S, even if the method we | ||
150 | // find in the end takes &self, we still do the autoderef step (just as | ||
151 | // rustc does an autoderef and then autoref again). | ||
152 | |||
153 | for derefed_ty in self.autoderef(db) { | ||
154 | if let Some(result) = derefed_ty.iterate_inherent_methods(db, name, &mut callback) { | ||
155 | return Some(result); | ||
156 | } | ||
157 | if let Some(result) = | ||
158 | derefed_ty.iterate_trait_method_candidates(db, resolver, name, &mut callback) | ||
159 | { | ||
160 | return Some(result); | ||
161 | } | ||
162 | } | ||
163 | None | ||
164 | } | ||
165 | |||
166 | fn iterate_trait_method_candidates<T>( | ||
167 | &self, | ||
168 | db: &impl HirDatabase, | ||
169 | resolver: &Resolver, | ||
170 | name: Option<&Name>, | ||
171 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | ||
172 | ) -> Option<T> { | ||
173 | 'traits: for t in resolver.traits_in_scope() { | ||
153 | let data = t.trait_data(db); | 174 | let data = t.trait_data(db); |
175 | // we'll be lazy about checking whether the type implements the | ||
176 | // trait, but if we find out it doesn't, we'll skip the rest of the | ||
177 | // iteration | ||
178 | let mut known_implemented = false; | ||
154 | for item in data.items() { | 179 | for item in data.items() { |
155 | match item { | 180 | match item { |
156 | &TraitItem::Function(m) => { | 181 | &TraitItem::Function(m) => { |
157 | let sig = m.signature(db); | 182 | let sig = m.signature(db); |
158 | if sig.name() == name && sig.has_self_param() { | 183 | if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { |
159 | candidates.push((t, m)); | 184 | if !known_implemented { |
185 | let trait_ref = TraitRef { | ||
186 | trait_: t, | ||
187 | substs: fresh_substs_for_trait(db, t, self.clone()), | ||
188 | }; | ||
189 | let (trait_ref, _) = super::traits::canonicalize(trait_ref); | ||
190 | if db.implements(trait_ref).is_none() { | ||
191 | continue 'traits; | ||
192 | } | ||
193 | } | ||
194 | known_implemented = true; | ||
195 | if let Some(result) = callback(self, m) { | ||
196 | return Some(result); | ||
197 | } | ||
160 | } | 198 | } |
161 | } | 199 | } |
162 | _ => {} | 200 | _ => {} |
163 | } | 201 | } |
164 | } | 202 | } |
165 | } | 203 | } |
166 | candidates.retain(|(t, _m)| { | 204 | None |
167 | let trait_ref = | ||
168 | TraitRef { trait_: *t, substs: fresh_substs_for_trait(db, *t, self.clone()) }; | ||
169 | let (trait_ref, _) = super::traits::canonicalize(trait_ref); | ||
170 | db.implements(trait_ref).is_some() | ||
171 | }); | ||
172 | // FIXME if there's multiple candidates here, that's an ambiguity error | ||
173 | let (_chosen_trait, chosen_method) = candidates.first()?; | ||
174 | // FIXME return correct receiver type | ||
175 | Some((self.clone(), *chosen_method)) | ||
176 | } | 205 | } |
177 | 206 | ||
178 | // This would be nicer if it just returned an iterator, but that runs into | 207 | fn iterate_inherent_methods<T>( |
179 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. | 208 | &self, |
180 | pub fn iterate_methods<T>( | ||
181 | self, | ||
182 | db: &impl HirDatabase, | 209 | db: &impl HirDatabase, |
210 | name: Option<&Name>, | ||
183 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 211 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
184 | ) -> Option<T> { | 212 | ) -> Option<T> { |
185 | // For method calls, rust first does any number of autoderef, and then one | 213 | let krate = match def_crate(db, self) { |
186 | // autoref (i.e. when the method takes &self or &mut self). We just ignore | 214 | Some(krate) => krate, |
187 | // the autoref currently -- when we find a method matching the given name, | 215 | None => return None, |
188 | // we assume it fits. | 216 | }; |
189 | 217 | let impls = db.impls_in_crate(krate); | |
190 | // Also note that when we've got a receiver like &S, even if the method we | ||
191 | // find in the end takes &self, we still do the autoderef step (just as | ||
192 | // rustc does an autoderef and then autoref again). | ||
193 | 218 | ||
194 | for derefed_ty in self.autoderef(db) { | 219 | for impl_block in impls.lookup_impl_blocks(self) { |
195 | let krate = match def_crate(db, &derefed_ty) { | 220 | for item in impl_block.items(db) { |
196 | Some(krate) => krate, | 221 | match item { |
197 | None => continue, | 222 | ImplItem::Method(f) => { |
198 | }; | 223 | let sig = f.signature(db); |
199 | let impls = db.impls_in_crate(krate); | 224 | if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { |
200 | 225 | if let Some(result) = callback(self, f) { | |
201 | for impl_block in impls.lookup_impl_blocks(&derefed_ty) { | ||
202 | for item in impl_block.items(db) { | ||
203 | match item { | ||
204 | ImplItem::Method(f) => { | ||
205 | if let Some(result) = callback(&derefed_ty, f) { | ||
206 | return Some(result); | 226 | return Some(result); |
207 | } | 227 | } |
208 | } | 228 | } |
209 | _ => {} | ||
210 | } | 229 | } |
230 | _ => {} | ||
211 | } | 231 | } |
212 | } | 232 | } |
213 | } | 233 | } |