diff options
Diffstat (limited to 'crates/ra_hir_ty/src/method_resolution.rs')
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 40 |
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. | ||
451 | pub 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 | |||
450 | fn is_valid_candidate( | 469 | fn 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 | |||
571 | fn 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 | } | ||