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.rs40
1 files changed, 38 insertions, 2 deletions
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index df5901835..74b908c2e 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -20,7 +20,7 @@ use crate::{
20 db::HirDatabase, 20 db::HirDatabase,
21 primitive::{FloatBitness, Uncertain}, 21 primitive::{FloatBitness, Uncertain},
22 utils::all_super_traits, 22 utils::all_super_traits,
23 Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, 23 ApplicationTy, Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
24}; 24};
25 25
26/// This is used as a key for indexing impls. 26/// This is used as a key for indexing impls.
@@ -214,7 +214,7 @@ pub fn iterate_method_candidates<T>(
214 // the methods by autoderef order of *receiver types*, not *self 214 // the methods by autoderef order of *receiver types*, not *self
215 // types*. 215 // types*.
216 216
217 let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect(); 217 let deref_chain = autoderef_method_receiver(db, krate, ty);
218 for i in 0..deref_chain.len() { 218 for i in 0..deref_chain.len() {
219 if let Some(result) = iterate_method_candidates_with_autoref( 219 if let Some(result) = iterate_method_candidates_with_autoref(
220 &deref_chain[i..], 220 &deref_chain[i..],
@@ -447,6 +447,25 @@ fn iterate_inherent_methods<T>(
447 None 447 None
448} 448}
449 449
450/// Returns the self type for the index trait call.
451pub fn resolve_indexing_op(
452 db: &impl HirDatabase,
453 ty: &Canonical<Ty>,
454 env: Arc<TraitEnvironment>,
455 krate: CrateId,
456 index_trait: TraitId,
457) -> Option<Canonical<Ty>> {
458 let ty = InEnvironment { value: ty.clone(), environment: env.clone() };
459 let deref_chain = autoderef_method_receiver(db, krate, ty);
460 for ty in deref_chain {
461 let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone());
462 if db.trait_solve(krate, goal).is_some() {
463 return Some(ty);
464 }
465 }
466 None
467}
468
450fn is_valid_candidate( 469fn is_valid_candidate(
451 db: &impl HirDatabase, 470 db: &impl HirDatabase,
452 name: Option<&Name>, 471 name: Option<&Name>,
@@ -548,3 +567,20 @@ fn generic_implements_goal(
548 let obligation = super::Obligation::Trait(trait_ref); 567 let obligation = super::Obligation::Trait(trait_ref);
549 Canonical { num_vars, value: InEnvironment::new(env, obligation) } 568 Canonical { num_vars, value: InEnvironment::new(env, obligation) }
550} 569}
570
571fn autoderef_method_receiver(
572 db: &impl HirDatabase,
573 krate: CrateId,
574 ty: InEnvironment<Canonical<Ty>>,
575) -> Vec<Canonical<Ty>> {
576 let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect();
577 // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
578 if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) =
579 deref_chain.last().map(|ty| &ty.value)
580 {
581 let num_vars = deref_chain.last().unwrap().num_vars;
582 let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone());
583 deref_chain.push(Canonical { value: unsized_ty, num_vars })
584 }
585 deref_chain
586}