Repository: rust-analyzer/rust-analyzer
Pull request #9090 (2021-05-31 18:05:33)

hir_ty: use correct receiver_ty in method resolution
Fixes https://github.com/rust-analyzer/rust-analyzer/issues/8100.

flodiebold: bors d+
bors[bot]: :v: cynecx can now approve this pull request. To approve and merge a pull request, simply reply with `bors r+`. More detailed instructions are available [here](https://bors.tech/documentation/getting-started/#reviewing-pull-requests).

Patch:
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 41ef45326b..f73bf43b21 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -890,7 +890,7 @@ impl<'a> InferenceContext<'a> {
                 method_name,
             )
         });
-        let (derefed_receiver_ty, method_ty, substs) = match resolved {
+        let (receiver_ty, method_ty, substs) = match resolved {
             Some((ty, func)) => {
                 let ty = canonicalized_receiver.decanonicalize_ty(ty);
                 let generics = generics(self.db.upcast(), func.into());
@@ -916,16 +916,7 @@ impl<'a> InferenceContext<'a> {
             }
             None => (self.err_ty(), Vec::new(), self.err_ty()),
         };
-        // Apply autoref so the below unification works correctly
-        // FIXME: return correct autorefs from lookup_method
-        let actual_receiver_ty = match self.resolve_ty_shallow(&expected_receiver_ty).as_reference()
-        {
-            Some((_, lifetime, mutability)) => {
-                TyKind::Ref(mutability, lifetime, derefed_receiver_ty).intern(&Interner)
-            }
-            _ => derefed_receiver_ty,
-        };
-        self.unify(&expected_receiver_ty, &actual_receiver_ty);
+        self.unify(&expected_receiver_ty, &receiver_ty);
 
         self.check_call_arguments(args, &param_tys);
         self.normalize_associated_types_in(ret_ty)
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 08e385a42c..af6b6cda70 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -721,7 +721,8 @@ fn iterate_inherent_methods(
                     cov_mark::hit!(impl_self_type_match_without_receiver);
                     continue;
                 }
-                if callback(&self_ty.value, item) {
+                let receiver_ty = receiver_ty.map(|x| &x.value).unwrap_or(&self_ty.value);
+                if callback(receiver_ty, item) {
                     return true;
                 }
             }


Test patch:
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 5c70a1fc01..ac312981df 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -2634,3 +2634,81 @@ fn f() {
         "#]],
     )
 }
+
+#[test]
+fn infer_boxed_self_receiver() {
+    check_infer(
+        r#"
+#[lang = "deref"]
+pub trait Deref {
+    type Target;
+    fn deref(&self) -> &Self::Target;
+}
+
+struct Box<T>(T);
+
+impl<T> Deref for Box<T> {
+    type Target = T;
+    fn deref(&self) -> &Self::Target;
+}
+
+struct Foo<T>(T);
+
+impl<T> Foo<T> {
+    fn get_inner<'a>(self: &'a Box<Self>) -> &'a T {}
+
+    fn get_self<'a>(self: &'a Box<Self>) -> &'a Self {}
+
+    fn into_inner(self: Box<Self>) -> Self {}
+}
+
+fn main() {
+    let boxed = Box(Foo(0_i32));
+
+    let bad1 = boxed.get_inner();
+    let good1 = Foo::get_inner(&boxed);
+
+    let bad2 = boxed.get_self();
+    let good2 = Foo::get_self(&boxed);
+
+    let inner = boxed.into_inner();
+}
+        "#,
+        expect![[r#"
+            67..71 'self': &Self
+            175..179 'self': &Box<T>
+            259..263 'self': &Box<Foo<T>>
+            289..291 '{}': ()
+            313..317 'self': &Box<Foo<T>>
+            346..348 '{}': ()
+            368..372 'self': Box<Foo<T>>
+            393..395 '{}': ()
+            409..630 '{     ...r(); }': ()
+            419..424 'boxed': Box<Foo<i32>>
+            427..430 'Box': Box<Foo<i32>>(Foo<i32>) -> Box<Foo<i32>>
+            427..442 'Box(Foo(0_i32))': Box<Foo<i32>>
+            431..434 'Foo': Foo<i32>(i32) -> Foo<i32>
+            431..441 'Foo(0_i32)': Foo<i32>
+            435..440 '0_i32': i32
+            453..457 'bad1': &i32
+            460..465 'boxed': Box<Foo<i32>>
+            460..477 'boxed....nner()': &i32
+            487..492 'good1': &i32
+            495..509 'Foo::get_inner': fn get_inner<i32>(&Box<Foo<i32>>) -> &i32
+            495..517 'Foo::g...boxed)': &i32
+            510..516 '&boxed': &Box<Foo<i32>>
+            511..516 'boxed': Box<Foo<i32>>
+            528..532 'bad2': &Foo<i32>
+            535..540 'boxed': Box<Foo<i32>>
+            535..551 'boxed....self()': &Foo<i32>
+            561..566 'good2': &Foo<i32>
+            569..582 'Foo::get_self': fn get_self<i32>(&Box<Foo<i32>>) -> &Foo<i32>
+            569..590 'Foo::g...boxed)': &Foo<i32>
+            583..589 '&boxed': &Box<Foo<i32>>
+            584..589 'boxed': Box<Foo<i32>>
+            601..606 'inner': Foo<i32>
+            609..614 'boxed': Box<Foo<i32>>
+            609..627 'boxed....nner()': Foo<i32>
+        "#]],
+    );
+}