Repository: mun-lang/mun (language: rust)

Issue:
Type inference problem: expected `{integer}`, found `i64`
The following piece of code doesn't compile because of a type inference error:

```rs
fn value() -> i64 { 6 }

pub fn main() {
    let t = 2;
    t = loop { break value(); };
}
```

The error message:

```
error: expected `{integer}`, found `i64`
 --> mod.mun:5:9
  |
5 |     t = loop { break value(); };
  |         ^^^^^^^^^^^^^^^^^^^^^^^ expected `{integer}`, found `i64`
  |
```

**Expected behavior**: the code compiles without error. `i64` is an integer type so the compiler should be able to infer that `t` is of type `i64`.

*Edit: I'm using mun v0.3.0 (the pre-built binaries)*


Discussion / hints:

Fix patch:
diff --git a/crates/mun_hir/src/ty.rs b/crates/mun_hir/src/ty.rs
index 5a57aff52..8d38d8a80 100644
--- a/crates/mun_hir/src/ty.rs
+++ b/crates/mun_hir/src/ty.rs
@@ -156,6 +156,20 @@ impl Ty {
         matches!(self.interned(), TyKind::Never)
     }
 
+    /// Returns true if these types represent the same type based on their outer type.
+    pub fn equals_ctor(&self, other: &Ty) -> bool {
+        match (self.interned(), other.interned()) {
+            (TyKind::Struct(a), TyKind::Struct(b)) => a == b,
+            (TyKind::Float(a), TyKind::Float(b)) => a == b,
+            (TyKind::Int(a), TyKind::Int(b)) => a == b,
+            (TyKind::Bool, TyKind::Bool) | (TyKind::Never, TyKind::Never) => true,
+            (TyKind::Tuple(_, a), TyKind::Tuple(_, b)) => a == b,
+            (TyKind::TypeAlias(a), TyKind::TypeAlias(b)) => a == b,
+            (TyKind::FnDef(a, _), TyKind::FnDef(b, _)) => a == b,
+            _ => false,
+        }
+    }
+
     /// Returns the callable definition for the given expression or `None` if the type does not
     /// represent a callable.
     pub fn as_callable_def(&self) -> Option<CallableDef> {
diff --git a/crates/mun_hir/src/ty/infer/type_variable.rs b/crates/mun_hir/src/ty/infer/type_variable.rs
index 075983e19..205a374b3 100644
--- a/crates/mun_hir/src/ty/infer/type_variable.rs
+++ b/crates/mun_hir/src/ty/infer/type_variable.rs
@@ -1,7 +1,7 @@
 use crate::{
     ty::infer::InferTy,
     ty::{TyKind, TypeWalk},
-    Ty,
+    Substitution, Ty,
 };
 use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
 use std::{borrow::Cow, fmt};
@@ -134,8 +134,22 @@ impl TypeVariableTable {
         // First resolve both types as much as possible
         let a = self.replace_if_possible(a);
         let b = self.replace_if_possible(b);
+        if a.equals_ctor(&b) {
+            match (a.interned(), b.interned()) {
+                (TyKind::Tuple(_, a), TyKind::Tuple(_, b)) => self.unify_substitutions(a, b),
+                _ => true,
+            }
+        } else {
+            self.unify_inner_trivial(&a, &b)
+        }
+    }
 
-        self.unify_inner_trivial(&a, &b)
+    fn unify_substitutions(&mut self, substs1: &Substitution, substs2: &Substitution) -> bool {
+        substs1
+            .0
+            .iter()
+            .zip(substs2.0.iter())
+            .all(|(t1, t2)| self.unify_inner(t1, t2))
     }
 
     /// Handles unificiation of trivial cases.


Test patch:
diff --git a/crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__issue_354.snap b/crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__issue_354.snap
new file mode 100644
index 000000000..135d1b94f
--- /dev/null
+++ b/crates/mun_hir/src/ty/snapshots/mun_hir__ty__tests__issue_354.snap
@@ -0,0 +1,17 @@
+---
+source: crates/mun_hir/src/ty/tests.rs
+expression: "fn value() -> i64 { 6 }\n\npub fn main() {\n    let t = 2;\n    t = loop { break value(); };\n}"
+
+---
+18..23 '{ 6 }': i64
+20..21 '6': i64
+39..90 '{     ...; }; }': ()
+49..50 't': i64
+53..54 '2': i64
+60..61 't': i64
+60..87 't = lo...e(); }': ()
+64..87 'loop {...e(); }': i64
+69..87 '{ brea...e(); }': never
+71..84 'break value()': never
+77..82 'value': function value() -> i64
+77..84 'value()': i64
diff --git a/crates/mun_hir/src/ty/tests.rs b/crates/mun_hir/src/ty/tests.rs
index 2e2cfc6d4..94cd26818 100644
--- a/crates/mun_hir/src/ty/tests.rs
+++ b/crates/mun_hir/src/ty/tests.rs
@@ -4,6 +4,19 @@ use crate::{
 };
 use std::{fmt::Write, sync::Arc};
 
+#[test]
+fn issue_354() {
+    infer_snapshot(
+        r#"
+    fn value() -> i64 { 6 }
+
+    pub fn main() {
+        let t = 2;
+        t = loop { break value(); };
+    }"#,
+    )
+}
+
 #[test]
 fn private_access() {
     infer_snapshot(