diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index df5901835a..7b0ff81611 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::{ db::HirDatabase, primitive::{FloatBitness, Uncertain}, utils::all_super_traits, - Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, + ApplicationTy, Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, }; /// This is used as a key for indexing impls. @@ -214,7 +214,7 @@ pub fn iterate_method_candidates( // the methods by autoderef order of *receiver types*, not *self // types*. - let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect(); + let deref_chain = autoderef_method_receiver(db, krate, ty); for i in 0..deref_chain.len() { if let Some(result) = iterate_method_candidates_with_autoref( &deref_chain[i..], @@ -548,3 +548,20 @@ fn generic_implements_goal( let obligation = super::Obligation::Trait(trait_ref); Canonical { num_vars, value: InEnvironment::new(env, obligation) } } + +fn autoderef_method_receiver( + db: &impl HirDatabase, + krate: CrateId, + ty: InEnvironment>, +) -> Vec> { + let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect(); + // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) + if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) = + deref_chain.last().map(|ty| &ty.value) + { + let num_vars = deref_chain.last().unwrap().num_vars; + let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone()); + deref_chain.push(Canonical { value: unsized_ty, num_vars }) + } + deref_chain +} diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 644d59e17c..f9b394f059 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs @@ -838,6 +838,24 @@ fn test() { (&S).foo()<|>; } assert_eq!(t, "u128"); } +#[test] +fn method_resolution_unsize_array() { + let t = type_at( + r#" +//- /main.rs +#[lang = "slice"] +impl [T] { + fn len(&self) -> usize { loop {} } +} +fn test() { + let a = [1, 2, 3]; + a.len()<|>; +} +"#, + ); + assert_eq!(t, "usize"); +} + #[test] fn method_resolution_trait_from_prelude() { let (db, pos) = TestDB::with_position(