aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/method_resolution.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/method_resolution.rs')
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs98
1 files changed, 56 insertions, 42 deletions
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 97281cf15..21efb196a 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -191,13 +191,13 @@ pub fn iterate_method_candidates<T>(
191 let ty = InEnvironment { value: ty.clone(), environment }; 191 let ty = InEnvironment { value: ty.clone(), environment };
192 let krate = resolver.krate()?; 192 let krate = resolver.krate()?;
193 193
194 // We have to be careful about the order of operations here. 194 // We have to be careful about the order we're looking at candidates
195 // Consider the case where we're resolving `x.clone()` where `x: 195 // in here. Consider the case where we're resolving `x.clone()`
196 // &Vec<_>`. This resolves to the clone method with self type 196 // where `x: &Vec<_>`. This resolves to the clone method with self
197 // `Vec<_>`, *not* `&_`. I.e. we need to consider methods where the 197 // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where
198 // receiver type exactly matches before cases where we have to do 198 // the receiver type exactly matches before cases where we have to
199 // autoref. But in the autoderef steps, the `&_` self type comes up 199 // do autoref. But in the autoderef steps, the `&_` self type comes
200 // *before* the `Vec<_>` self type. 200 // up *before* the `Vec<_>` self type.
201 // 201 //
202 // On the other hand, we don't want to just pick any by-value method 202 // On the other hand, we don't want to just pick any by-value method
203 // before any by-autoref method; it's just that we need to consider 203 // before any by-autoref method; it's just that we need to consider
@@ -206,7 +206,7 @@ pub fn iterate_method_candidates<T>(
206 206
207 let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty.clone()).collect(); 207 let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty.clone()).collect();
208 for i in 0..deref_chain.len() { 208 for i in 0..deref_chain.len() {
209 if let Some(result) = iterate_method_candidates_autoref( 209 if let Some(result) = iterate_method_candidates_with_autoref(
210 &deref_chain[i..], 210 &deref_chain[i..],
211 db, 211 db,
212 resolver, 212 resolver,
@@ -220,12 +220,12 @@ pub fn iterate_method_candidates<T>(
220 } 220 }
221 LookupMode::Path => { 221 LookupMode::Path => {
222 // No autoderef for path lookups 222 // No autoderef for path lookups
223 iterate_method_candidates_inner(&ty, db, resolver, name, None, &mut callback) 223 iterate_method_candidates_for_self_ty(&ty, db, resolver, name, &mut callback)
224 } 224 }
225 } 225 }
226} 226}
227 227
228fn iterate_method_candidates_autoref<T>( 228fn iterate_method_candidates_with_autoref<T>(
229 deref_chain: &[Canonical<Ty>], 229 deref_chain: &[Canonical<Ty>],
230 db: &impl HirDatabase, 230 db: &impl HirDatabase,
231 resolver: &Resolver, 231 resolver: &Resolver,
@@ -275,18 +275,25 @@ fn iterate_method_candidates_autoref<T>(
275 275
276fn iterate_method_candidates_by_receiver<T>( 276fn iterate_method_candidates_by_receiver<T>(
277 receiver_ty: &Canonical<Ty>, 277 receiver_ty: &Canonical<Ty>,
278 deref_chain: &[Canonical<Ty>], 278 rest_of_deref_chain: &[Canonical<Ty>],
279 db: &impl HirDatabase, 279 db: &impl HirDatabase,
280 resolver: &Resolver, 280 resolver: &Resolver,
281 name: Option<&Name>, 281 name: Option<&Name>,
282 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 282 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
283) -> Option<T> { 283) -> Option<T> {
284 // TODO: do we need to do the whole loop for inherents before traits?
285 // We're looking for methods with *receiver* type receiver_ty. These could 284 // We're looking for methods with *receiver* type receiver_ty. These could
286 // be found in any of the derefs of receiver_ty, so we have to go through 285 // be found in any of the derefs of receiver_ty, so we have to go through
287 // that. 286 // that.
288 for self_ty in std::iter::once(receiver_ty).chain(deref_chain) { 287 let krate = resolver.krate()?;
289 if let Some(result) = iterate_method_candidates_inner( 288 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
289 if let Some(result) =
290 iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback)
291 {
292 return Some(result);
293 }
294 }
295 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
296 if let Some(result) = iterate_trait_method_candidates(
290 self_ty, 297 self_ty,
291 db, 298 db,
292 resolver, 299 resolver,
@@ -300,22 +307,19 @@ fn iterate_method_candidates_by_receiver<T>(
300 None 307 None
301} 308}
302 309
303fn iterate_method_candidates_inner<T>( 310fn iterate_method_candidates_for_self_ty<T>(
304 self_ty: &Canonical<Ty>, 311 self_ty: &Canonical<Ty>,
305 db: &impl HirDatabase, 312 db: &impl HirDatabase,
306 resolver: &Resolver, 313 resolver: &Resolver,
307 name: Option<&Name>, 314 name: Option<&Name>,
308 receiver_ty: Option<&Canonical<Ty>>,
309 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 315 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
310) -> Option<T> { 316) -> Option<T> {
311 let krate = resolver.krate()?; 317 let krate = resolver.krate()?;
312 if let Some(result) = 318 if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) {
313 iterate_inherent_methods(self_ty, db, name, receiver_ty, krate, &mut callback)
314 {
315 return Some(result); 319 return Some(result);
316 } 320 }
317 if let Some(result) = 321 if let Some(result) =
318 iterate_trait_method_candidates(self_ty, db, resolver, name, receiver_ty, &mut callback) 322 iterate_trait_method_candidates(self_ty, db, resolver, name, None, &mut callback)
319 { 323 {
320 return Some(result); 324 return Some(result);
321 } 325 }
@@ -412,29 +416,11 @@ fn is_valid_candidate(
412 if !data.has_self_param { 416 if !data.has_self_param {
413 return false; 417 return false;
414 } 418 }
415 let substs = match m.lookup(db).container { 419 let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) {
416 hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, item) 420 Some(ty) => ty,
417 .push(self_ty.value.clone()) 421 None => return false,
418 .fill_with_unknown()
419 .build(),
420 hir_def::ContainerId::ImplId(impl_id) => {
421 let vars =
422 Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build();
423 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
424 let self_ty_with_vars =
425 Canonical { num_vars: vars.len(), value: &self_ty_with_vars };
426 if let Some(substs) = super::infer::unify(self_ty_with_vars, &self_ty.value)
427 {
428 substs
429 } else {
430 return false;
431 }
432 }
433 hir_def::ContainerId::ModuleId(_) => unreachable!(),
434 }; 422 };
435 let sig = db.callable_item_signature(m.into()); 423 if transformed_receiver_ty != receiver_ty.value {
436 let receiver = sig.params()[0].clone().subst(&substs);
437 if receiver != receiver_ty.value {
438 return false; 424 return false;
439 } 425 }
440 } 426 }
@@ -448,6 +434,34 @@ fn is_valid_candidate(
448 } 434 }
449} 435}
450 436
437pub(crate) fn inherent_impl_substs(
438 db: &impl HirDatabase,
439 impl_id: ImplId,
440 self_ty: &Ty,
441) -> Option<Substs> {
442 let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build();
443 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
444 let self_ty_with_vars = Canonical { num_vars: vars.len(), value: &self_ty_with_vars };
445 super::infer::unify(self_ty_with_vars, self_ty)
446}
447
448fn transform_receiver_ty(
449 db: &impl HirDatabase,
450 function_id: FunctionId,
451 self_ty: &Canonical<Ty>,
452) -> Option<Ty> {
453 let substs = match function_id.lookup(db).container {
454 hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, function_id)
455 .push(self_ty.value.clone())
456 .fill_with_unknown()
457 .build(),
458 hir_def::ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty.value)?,
459 hir_def::ContainerId::ModuleId(_) => unreachable!(),
460 };
461 let sig = db.callable_item_signature(function_id.into());
462 Some(sig.params()[0].clone().subst(&substs))
463}
464
451pub fn implements_trait( 465pub fn implements_trait(
452 ty: &Canonical<Ty>, 466 ty: &Canonical<Ty>,
453 db: &impl HirDatabase, 467 db: &impl HirDatabase,