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

Issue:
Closure types aren't always inferred correctly.
Using the VS Code-provided v0.2.565 of RA, the `sub` closure in the following code isn't being inferred.
[Screenshot of the incorrect inlay hint](https://i.imgur.com/E50fDmG.png)
```rust
fn foo(c: i32) -> Box<dyn Fn(i32, i32) -> i32> {
    let add = |a, b| a + b;
    let sub = |a, b| a - b;
    Box::new(if c > 42 { add } else { sub })
}

fn main() {
    println!("{}", foo(100)(10, 20));
}
```

Pull request description:
fix: closure unify without check ClosureId
Previously, the unification of closure types is blocked by `Ty.equals_ctor` which compares the ClosureId of the closures. Here is a workaround to allow closures to unify their substitutions.

Fixes #8604.

Patch:
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index a887e20b0b..d8e0b43206 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -332,6 +332,10 @@ impl InferenceTable {
                 | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1),
                 _ => true, /* we checked equals_ctor already */
             }
+        } else if let (TyKind::Closure(.., substs1), TyKind::Closure(.., substs2)) =
+            (ty1.kind(&Interner), ty2.kind(&Interner))
+        {
+            self.unify_substs(substs1, substs2, depth + 1)
         } else {
             self.unify_inner_trivial(&ty1, &ty2, depth)
         }


Test patch:
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 5948d0bc22..0eefd70f22 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1028,6 +1028,42 @@ fn infer_in_elseif() {
     )
 }
 
+#[test]
+fn infer_closure_unify() {
+    check_infer(
+        r#"
+        fn foo(f: bool) {
+            let a = |x| x;
+            let b = |x| x;
+            let id = if f { a } else { b };
+            id(123);
+        }
+        "#,
+        expect![[r#"
+            7..8 'f': bool
+            16..106 '{     ...23); }': ()
+            26..27 'a': |i32| -> i32
+            30..35 '|x| x': |i32| -> i32
+            31..32 'x': i32
+            34..35 'x': i32
+            45..46 'b': |i32| -> i32
+            49..54 '|x| x': |i32| -> i32
+            50..51 'x': i32
+            53..54 'x': i32
+            64..66 'id': |i32| -> i32
+            69..90 'if f {... { b }': |i32| -> i32
+            72..73 'f': bool
+            74..79 '{ a }': |i32| -> i32
+            76..77 'a': |i32| -> i32
+            85..90 '{ b }': |i32| -> i32
+            87..88 'b': |i32| -> i32
+            96..98 'id': |i32| -> i32
+            96..103 'id(123)': i32
+            99..102 '123': i32
+        "#]],
+    )
+}
+
 #[test]
 fn infer_if_match_with_return() {
     check_infer(