Merge pull request #21060 from ChayimFriedman2/adjust-last

fix: Fix some inference of patterns
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 37060bd..02b8ab8 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -759,7 +759,6 @@
     re_erased: Region<'db>,
 
     empty_args: GenericArgs<'db>,
-    empty_tys: Tys<'db>,
 }
 
 impl<'db> InternedStandardTypes<'db> {
@@ -795,7 +794,6 @@
             re_erased: Region::new_erased(interner),
 
             empty_args: GenericArgs::new_from_iter(interner, []),
-            empty_tys: Tys::new_from_iter(interner, []),
         }
     }
 }
@@ -1475,15 +1473,30 @@
         self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
     }
 
-    fn demand_eqtype(&mut self, expected: Ty<'db>, actual: Ty<'db>) {
+    fn demand_eqtype(
+        &mut self,
+        id: ExprOrPatId,
+        expected: Ty<'db>,
+        actual: Ty<'db>,
+    ) -> Result<(), ()> {
+        let result = self.demand_eqtype_fixme_no_diag(expected, actual);
+        if result.is_err() {
+            self.result.type_mismatches.insert(id, TypeMismatch { expected, actual });
+        }
+        result
+    }
+
+    fn demand_eqtype_fixme_no_diag(
+        &mut self,
+        expected: Ty<'db>,
+        actual: Ty<'db>,
+    ) -> Result<(), ()> {
         let result = self
             .table
             .at(&ObligationCause::new())
             .eq(expected, actual)
             .map(|infer_ok| self.table.register_infer_ok(infer_ok));
-        if let Err(_err) = result {
-            // FIXME: Emit diagnostic.
-        }
+        result.map_err(drop)
     }
 
     fn demand_suptype(&mut self, expected: Ty<'db>, actual: Ty<'db>) {
diff --git a/crates/hir-ty/src/infer/fallback.rs b/crates/hir-ty/src/infer/fallback.rs
index b1c9146..d0ce8cb 100644
--- a/crates/hir-ty/src/infer/fallback.rs
+++ b/crates/hir-ty/src/infer/fallback.rs
@@ -160,7 +160,7 @@
         };
         debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
 
-        self.demand_eqtype(ty, fallback);
+        _ = self.demand_eqtype_fixme_no_diag(ty, fallback);
         true
     }
 
diff --git a/crates/hir-ty/src/infer/op.rs b/crates/hir-ty/src/infer/op.rs
index 57d4900..88319a8 100644
--- a/crates/hir-ty/src/infer/op.rs
+++ b/crates/hir-ty/src/infer/op.rs
@@ -108,7 +108,7 @@
                 {
                     let builtin_return_ty =
                         self.enforce_builtin_binop_types(lhs_ty, rhs_ty, category);
-                    self.demand_eqtype(builtin_return_ty, return_ty);
+                    _ = self.demand_eqtype(expr.into(), builtin_return_ty, return_ty);
                     builtin_return_ty
                 } else {
                     return_ty
diff --git a/crates/hir-ty/src/infer/opaques.rs b/crates/hir-ty/src/infer/opaques.rs
index f7719f5..ba4b53a 100644
--- a/crates/hir-ty/src/infer/opaques.rs
+++ b/crates/hir-ty/src/infer/opaques.rs
@@ -109,7 +109,7 @@
 
                     let expected =
                         EarlyBinder::bind(ty.ty).instantiate(interner, opaque_type_key.args);
-                    self.demand_eqtype(expected, hidden_type.ty);
+                    _ = self.demand_eqtype_fixme_no_diag(expected, hidden_type.ty);
                 }
 
                 self.result.type_of_opaque.insert(def_id, ty.ty);
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index 257224b..b3cf94a 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -1,6 +1,6 @@
 //! Type inference for patterns.
 
-use std::iter::repeat_with;
+use std::{cmp, iter};
 
 use hir_def::{
     HasModule,
@@ -19,7 +19,7 @@
         AllowTwoPhase, BindingMode, Expectation, InferenceContext, TypeMismatch, expr::ExprIsRead,
     },
     lower::lower_mutability,
-    next_solver::{GenericArgs, Ty, TyKind},
+    next_solver::{GenericArgs, Ty, TyKind, Tys, infer::traits::ObligationCause},
 };
 
 impl<'db> InferenceContext<'_, 'db> {
@@ -183,42 +183,61 @@
     /// Ellipses found in the original pattern or expression must be filtered out.
     pub(super) fn infer_tuple_pat_like(
         &mut self,
+        pat: PatId,
         expected: Ty<'db>,
         default_bm: BindingMode,
         ellipsis: Option<u32>,
-        subs: &[PatId],
+        elements: &[PatId],
         decl: Option<DeclContext>,
     ) -> Ty<'db> {
-        let expected = self.table.structurally_resolve_type(expected);
-        let expectations = match expected.kind() {
-            TyKind::Tuple(parameters) => parameters,
-            _ => self.types.empty_tys,
-        };
-
-        let ((pre, post), n_uncovered_patterns) = match ellipsis {
-            Some(idx) => {
-                (subs.split_at(idx as usize), expectations.len().saturating_sub(subs.len()))
+        let mut expected_len = elements.len();
+        if ellipsis.is_some() {
+            // Require known type only when `..` is present.
+            if let TyKind::Tuple(tys) = self.table.structurally_resolve_type(expected).kind() {
+                expected_len = tys.len();
             }
-            None => ((subs, &[][..]), 0),
+        }
+        let max_len = cmp::max(expected_len, elements.len());
+
+        let element_tys_iter = (0..max_len).map(|_| self.table.next_ty_var());
+        let element_tys = Tys::new_from_iter(self.interner(), element_tys_iter);
+        let pat_ty = Ty::new(self.interner(), TyKind::Tuple(element_tys));
+        if self.demand_eqtype(pat.into(), expected, pat_ty).is_err()
+            && let TyKind::Tuple(expected) = expected.kind()
+        {
+            // Equate expected type with the infer vars, for better diagnostics.
+            for (expected, elem_ty) in iter::zip(expected, element_tys) {
+                _ = self
+                    .table
+                    .at(&ObligationCause::dummy())
+                    .eq(expected, elem_ty)
+                    .map(|infer_ok| self.table.register_infer_ok(infer_ok));
+            }
+        }
+        let (before_ellipsis, after_ellipsis) = match ellipsis {
+            Some(ellipsis) => {
+                let element_tys = element_tys.as_slice();
+                // Don't check patterns twice.
+                let from_end_start = cmp::max(
+                    element_tys.len().saturating_sub(elements.len() - ellipsis as usize),
+                    ellipsis as usize,
+                );
+                (
+                    element_tys.get(..ellipsis as usize).unwrap_or(element_tys),
+                    element_tys.get(from_end_start..).unwrap_or_default(),
+                )
+            }
+            None => (element_tys.as_slice(), &[][..]),
         };
-        let mut expectations_iter =
-            expectations.iter().chain(repeat_with(|| self.table.next_ty_var()));
-
-        let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + subs.len());
-
-        inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns + subs.len()));
-
-        // Process pre
-        for (ty, pat) in inner_tys.iter_mut().zip(pre) {
-            *ty = self.infer_pat(*pat, *ty, default_bm, decl);
+        for (&elem, &elem_ty) in iter::zip(elements, before_ellipsis.iter().chain(after_ellipsis)) {
+            self.infer_pat(elem, elem_ty, default_bm, decl);
         }
-
-        // Process post
-        for (ty, pat) in inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post) {
-            *ty = self.infer_pat(*pat, *ty, default_bm, decl);
+        if let Some(uncovered) = elements.get(element_tys.len()..) {
+            for &elem in uncovered {
+                self.infer_pat(elem, self.types.error, default_bm, decl);
+            }
         }
-
-        Ty::new_tup_from_iter(self.interner(), inner_tys.into_iter())
+        pat_ty
     }
 
     /// The resolver needs to be updated to the surrounding expression when inside assignment
@@ -272,7 +291,7 @@
 
         let ty = match &self.body[pat] {
             Pat::Tuple { args, ellipsis } => {
-                self.infer_tuple_pat_like(expected, default_bm, *ellipsis, args, decl)
+                self.infer_tuple_pat_like(pat, expected, default_bm, *ellipsis, args, decl)
             }
             Pat::Or(pats) => {
                 for pat in pats.iter() {
@@ -356,7 +375,7 @@
                         GenericArgs::fill_with_defaults(
                             self.interner(),
                             box_adt.into(),
-                            std::iter::once(inner_ty.into()).chain(alloc_ty.map(Into::into)),
+                            iter::once(inner_ty.into()).chain(alloc_ty.map(Into::into)),
                             |_, id, _| self.table.next_var_for_param(id),
                         ),
                     )
@@ -416,7 +435,7 @@
             .result
             .pat_adjustments
             .get(&pat)
-            .and_then(|it| it.first())
+            .and_then(|it| it.last())
             .unwrap_or(&self.result.type_of_pat[pat])
     }
 
@@ -469,9 +488,9 @@
         let bound_ty = match mode {
             BindingMode::Ref(mutability) => {
                 let inner_lt = self.table.next_region_var();
-                Ty::new_ref(self.interner(), inner_lt, inner_ty, mutability)
+                Ty::new_ref(self.interner(), inner_lt, expected, mutability)
             }
-            BindingMode::Move => inner_ty,
+            BindingMode::Move => expected,
         };
         self.write_pat_ty(pat, inner_ty);
         self.write_binding_ty(binding, bound_ty);
diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs
index 75800a0..50aca16 100644
--- a/crates/hir-ty/src/tests/coercion.rs
+++ b/crates/hir-ty/src/tests/coercion.rs
@@ -833,11 +833,11 @@
 fn main() {
     let a: V<&dyn Tr>;
     (a,) = V { t: &S };
-  //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + 'static)>,)
+  //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,)
 
     let mut a: V<&dyn Tr> = V { t: &S };
     (a,) = V { t: &S };
-  //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + 'static)>,)
+  //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,)
 }
         "#,
     );
diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs
index aa1fff7..5d81d52 100644
--- a/crates/hir-ty/src/tests/patterns.rs
+++ b/crates/hir-ty/src/tests/patterns.rs
@@ -1259,3 +1259,22 @@
             "#,
     );
 }
+
+#[test]
+fn destructuring_assign_ref() {
+    check_no_mismatches(
+        r#"
+struct Foo;
+
+fn foo() -> (&'static Foo, u32) {
+    (&Foo, 0)
+}
+
+fn bar() {
+    let ext: &Foo;
+    let v;
+    (ext, v) = foo();
+}
+    "#,
+    );
+}