diff options
Diffstat (limited to 'crates/ra_hir/src/ty/method_resolution.rs')
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 90 |
1 files changed, 67 insertions, 23 deletions
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index eb69344f6..ee0c7b00f 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -166,7 +166,19 @@ pub(crate) fn lookup_method( | |||
166 | name: &Name, | 166 | name: &Name, |
167 | resolver: &Resolver, | 167 | resolver: &Resolver, |
168 | ) -> Option<(Ty, Function)> { | 168 | ) -> Option<(Ty, Function)> { |
169 | iterate_method_candidates(ty, db, resolver, Some(name), |ty, f| Some((ty.clone(), f))) | 169 | iterate_method_candidates(ty, db, resolver, Some(name), LookupMode::MethodCall, |ty, f| { |
170 | if let AssocItem::Function(f) = f { | ||
171 | Some((ty.clone(), f)) | ||
172 | } else { | ||
173 | None | ||
174 | } | ||
175 | }) | ||
176 | } | ||
177 | |||
178 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
179 | pub(crate) enum LookupMode { | ||
180 | MethodCall, | ||
181 | Path, | ||
170 | } | 182 | } |
171 | 183 | ||
172 | // This would be nicer if it just returned an iterator, but that runs into | 184 | // This would be nicer if it just returned an iterator, but that runs into |
@@ -176,7 +188,8 @@ pub(crate) fn iterate_method_candidates<T>( | |||
176 | db: &impl HirDatabase, | 188 | db: &impl HirDatabase, |
177 | resolver: &Resolver, | 189 | resolver: &Resolver, |
178 | name: Option<&Name>, | 190 | name: Option<&Name>, |
179 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 191 | mode: LookupMode, |
192 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | ||
180 | ) -> Option<T> { | 193 | ) -> Option<T> { |
181 | // For method calls, rust first does any number of autoderef, and then one | 194 | // For method calls, rust first does any number of autoderef, and then one |
182 | // autoref (i.e. when the method takes &self or &mut self). We just ignore | 195 | // autoref (i.e. when the method takes &self or &mut self). We just ignore |
@@ -188,13 +201,15 @@ pub(crate) fn iterate_method_candidates<T>( | |||
188 | // rustc does an autoderef and then autoref again). | 201 | // rustc does an autoderef and then autoref again). |
189 | 202 | ||
190 | let krate = resolver.krate()?; | 203 | let krate = resolver.krate()?; |
204 | // TODO no autoderef in LookupMode::Path | ||
191 | for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) { | 205 | for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) { |
192 | if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback) | 206 | if let Some(result) = |
207 | iterate_inherent_methods(&derefed_ty, db, name, mode, krate, &mut callback) | ||
193 | { | 208 | { |
194 | return Some(result); | 209 | return Some(result); |
195 | } | 210 | } |
196 | if let Some(result) = | 211 | if let Some(result) = |
197 | iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback) | 212 | iterate_trait_method_candidates(&derefed_ty, db, resolver, name, mode, &mut callback) |
198 | { | 213 | { |
199 | return Some(result); | 214 | return Some(result); |
200 | } | 215 | } |
@@ -207,7 +222,8 @@ fn iterate_trait_method_candidates<T>( | |||
207 | db: &impl HirDatabase, | 222 | db: &impl HirDatabase, |
208 | resolver: &Resolver, | 223 | resolver: &Resolver, |
209 | name: Option<&Name>, | 224 | name: Option<&Name>, |
210 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 225 | mode: LookupMode, |
226 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | ||
211 | ) -> Option<T> { | 227 | ) -> Option<T> { |
212 | let krate = resolver.krate()?; | 228 | let krate = resolver.krate()?; |
213 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) | 229 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) |
@@ -231,21 +247,35 @@ fn iterate_trait_method_candidates<T>( | |||
231 | // trait, but if we find out it doesn't, we'll skip the rest of the | 247 | // trait, but if we find out it doesn't, we'll skip the rest of the |
232 | // iteration | 248 | // iteration |
233 | let mut known_implemented = inherently_implemented; | 249 | let mut known_implemented = inherently_implemented; |
234 | for item in data.items() { | 250 | for &item in data.items() { |
235 | if let AssocItem::Function(m) = *item { | 251 | // TODO unify with the impl case |
236 | let data = m.data(db); | 252 | match item { |
237 | if name.map_or(true, |name| data.name() == name) && data.has_self_param() { | 253 | AssocItem::Function(m) => { |
238 | if !known_implemented { | 254 | let data = m.data(db); |
239 | let goal = generic_implements_goal(db, env.clone(), t, ty.clone()); | 255 | if !name.map_or(true, |name| data.name() == name) |
240 | if db.trait_solve(krate, goal).is_none() { | 256 | || (!data.has_self_param() && mode != LookupMode::Path) |
241 | continue 'traits; | 257 | { |
242 | } | 258 | continue; |
243 | } | 259 | } |
244 | known_implemented = true; | 260 | } |
245 | if let Some(result) = callback(&ty.value, m) { | 261 | AssocItem::Const(c) => { |
246 | return Some(result); | 262 | if !name.map_or(true, |name| Some(name) == c.name(db).as_ref()) |
263 | || (mode != LookupMode::Path) | ||
264 | { | ||
265 | continue; | ||
247 | } | 266 | } |
248 | } | 267 | } |
268 | _ => {} | ||
269 | }; | ||
270 | if !known_implemented { | ||
271 | let goal = generic_implements_goal(db, env.clone(), t, ty.clone()); | ||
272 | if db.trait_solve(krate, goal).is_none() { | ||
273 | continue 'traits; | ||
274 | } | ||
275 | } | ||
276 | known_implemented = true; | ||
277 | if let Some(result) = callback(&ty.value, item) { | ||
278 | return Some(result); | ||
249 | } | 279 | } |
250 | } | 280 | } |
251 | } | 281 | } |
@@ -256,21 +286,35 @@ fn iterate_inherent_methods<T>( | |||
256 | ty: &Canonical<Ty>, | 286 | ty: &Canonical<Ty>, |
257 | db: &impl HirDatabase, | 287 | db: &impl HirDatabase, |
258 | name: Option<&Name>, | 288 | name: Option<&Name>, |
289 | mode: LookupMode, | ||
259 | krate: Crate, | 290 | krate: Crate, |
260 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 291 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, |
261 | ) -> Option<T> { | 292 | ) -> Option<T> { |
262 | for krate in def_crates(db, krate, &ty.value)? { | 293 | for krate in def_crates(db, krate, &ty.value)? { |
263 | let impls = db.impls_in_crate(krate); | 294 | let impls = db.impls_in_crate(krate); |
264 | 295 | ||
265 | for impl_block in impls.lookup_impl_blocks(&ty.value) { | 296 | for impl_block in impls.lookup_impl_blocks(&ty.value) { |
266 | for item in impl_block.items(db) { | 297 | for item in impl_block.items(db) { |
267 | if let AssocItem::Function(f) = item { | 298 | match item { |
268 | let data = f.data(db); | 299 | AssocItem::Function(f) => { |
269 | if name.map_or(true, |name| data.name() == name) && data.has_self_param() { | 300 | let data = f.data(db); |
270 | if let Some(result) = callback(&ty.value, f) { | 301 | if !name.map_or(true, |name| data.name() == name) |
271 | return Some(result); | 302 | || (!data.has_self_param() && mode != LookupMode::Path) |
303 | { | ||
304 | continue; | ||
272 | } | 305 | } |
273 | } | 306 | } |
307 | AssocItem::Const(c) => { | ||
308 | if !name.map_or(true, |name| Some(name) == c.name(db).as_ref()) | ||
309 | || (mode != LookupMode::Path) | ||
310 | { | ||
311 | continue; | ||
312 | } | ||
313 | } | ||
314 | _ => {} | ||
315 | } | ||
316 | if let Some(result) = callback(&ty.value, item) { | ||
317 | return Some(result); | ||
274 | } | 318 | } |
275 | } | 319 | } |
276 | } | 320 | } |