diff options
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/method_resolution.rs | 18 |
2 files changed, 37 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..7b0ff8161 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..], |
@@ -548,3 +548,20 @@ fn generic_implements_goal( | |||
548 | let obligation = super::Obligation::Trait(trait_ref); | 548 | let obligation = super::Obligation::Trait(trait_ref); |
549 | Canonical { num_vars, value: InEnvironment::new(env, obligation) } | 549 | Canonical { num_vars, value: InEnvironment::new(env, obligation) } |
550 | } | 550 | } |
551 | |||
552 | fn autoderef_method_receiver( | ||
553 | db: &impl HirDatabase, | ||
554 | krate: CrateId, | ||
555 | ty: InEnvironment<Canonical<Ty>>, | ||
556 | ) -> Vec<Canonical<Ty>> { | ||
557 | let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect(); | ||
558 | // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) | ||
559 | if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) = | ||
560 | deref_chain.last().map(|ty| &ty.value) | ||
561 | { | ||
562 | let num_vars = deref_chain.last().unwrap().num_vars; | ||
563 | let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone()); | ||
564 | deref_chain.push(Canonical { value: unsized_ty, num_vars }) | ||
565 | } | ||
566 | deref_chain | ||
567 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 644d59e17..f9b394f05 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs | |||
@@ -839,6 +839,24 @@ fn test() { (&S).foo()<|>; } | |||
839 | } | 839 | } |
840 | 840 | ||
841 | #[test] | 841 | #[test] |
842 | fn method_resolution_unsize_array() { | ||
843 | let t = type_at( | ||
844 | r#" | ||
845 | //- /main.rs | ||
846 | #[lang = "slice"] | ||
847 | impl<T> [T] { | ||
848 | fn len(&self) -> usize { loop {} } | ||
849 | } | ||
850 | fn test() { | ||
851 | let a = [1, 2, 3]; | ||
852 | a.len()<|>; | ||
853 | } | ||
854 | "#, | ||
855 | ); | ||
856 | assert_eq!(t, "usize"); | ||
857 | } | ||
858 | |||
859 | #[test] | ||
842 | fn method_resolution_trait_from_prelude() { | 860 | fn method_resolution_trait_from_prelude() { |
843 | let (db, pos) = TestDB::with_position( | 861 | let (db, pos) = TestDB::with_position( |
844 | r#" | 862 | r#" |