Repository: rust-lang/rust-analyzer (rust)

Issue:
Go to definition doesn't work for trait implementations for structs inside function bodies
```Rust
trait T {
    type Ty;
    fn foo() -> Self::Ty;
}

fn f() {
    struct X {}
    impl T for X {
        type Ty = i32;
        fn foo() -> i32 {
            5
        }
    }
    let t = X::foo();
}
```

In this example r-a sees method, and can infer that the type of `t` is `i32`, but go to definition on `foo` will go to the trait function, not the impl one.

Pull request description:
Consider block impls in `lookup_impl_assoc_item_for_trait_ref`
fix #14782 

Patch:
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index bf1e875858..7208bebb3b 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -729,8 +729,16 @@ fn lookup_impl_assoc_item_for_trait_ref(
     let self_ty = trait_ref.self_type_parameter(Interner);
     let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty)?;
     let impls = db.trait_impls_in_deps(env.krate);
-    let impls =
-        impls.iter().flat_map(|impls| impls.for_trait_and_self_ty(hir_trait_id, self_ty_fp));
+    let self_impls = match self_ty.kind(Interner) {
+        TyKind::Adt(id, _) => {
+            id.0.module(db.upcast()).containing_block().map(|x| db.trait_impls_in_block(x))
+        }
+        _ => None,
+    };
+    let impls = impls
+        .iter()
+        .chain(self_impls.as_ref())
+        .flat_map(|impls| impls.for_trait_and_self_ty(hir_trait_id, self_ty_fp));
 
     let table = InferenceTable::new(db, env);
 
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 1518b49515..ef3f14d79d 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1492,6 +1492,29 @@ impl Twait for Stwuct {
 fn f() {
     let s = Stwuct;
     s.a$0();
+}
+        "#,
+            );
+        }
+        #[test]
+        fn method_call_inside_block() {
+            check(
+                r#"
+trait Twait {
+    fn a(&self);
+}
+
+fn outer() {
+    struct Stwuct;
+
+    impl Twait for Stwuct {
+        fn a(&self){}
+         //^
+    }
+    fn f() {
+        let s = Stwuct;
+        s.a$0();
+    }
 }
         "#,
             );


Test patch:
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index b4b5fdd891..b336fa5f0f 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -503,6 +503,35 @@ fn trait_method() {
     );
 }
 
+#[test]
+fn trait_method_inside_block() {
+    check_number(
+        r#"
+trait Twait {
+    fn a(&self) -> i32;
+}
+
+fn outer() -> impl Twait {
+    struct Stwuct;
+
+    impl Twait for Stwuct {
+        fn a(&self) -> i32 {
+            5
+        }
+    }
+    fn f() -> impl Twait {
+        let s = Stwuct;
+        s
+    }
+    f()
+}
+
+const GOAL: i32 = outer().a();
+        "#,
+        5,
+    );
+}
+
 #[test]
 fn generic_fn() {
     check_number(