diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index ca8d5bae5e50..83b134604745 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -6,12 +6,13 @@ use hir_def::{ expr_store::Body, hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId}, path::Path, + HasModule, }; use hir_expand::name::Name; use stdx::TupleExt; use crate::{ - consteval::{try_const_usize, usize_const}, + consteval::{self, try_const_usize, usize_const}, infer::{ coerce::CoerceNever, expr::ExprIsRead, BindingMode, Expectation, InferenceContext, TypeMismatch, @@ -479,6 +480,19 @@ impl InferenceContext<'_> { suffix: &[PatId], default_bm: BindingMode, ) -> Ty { + let expected = self.resolve_ty_shallow(expected); + + // If `expected` is an infer ty, we try to equate it to an array if the given pattern + // allows it. See issue #16609 + if expected.is_ty_var() { + if let Some(resolved_array_ty) = + self.try_resolve_slice_ty_to_array_ty(prefix, suffix, slice) + { + self.unify(&expected, &resolved_array_ty); + } + } + + let expected = self.resolve_ty_shallow(&expected); let elem_ty = match expected.kind(Interner) { TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(), _ => self.err_ty(), @@ -553,6 +567,25 @@ impl InferenceContext<'_> { | Pat::Expr(_) => false, } } + + fn try_resolve_slice_ty_to_array_ty( + &mut self, + before: &[PatId], + suffix: &[PatId], + slice: &Option, + ) -> Option { + if !slice.is_none() { + return None; + } + + let len = before.len() + suffix.len(); + let size = + consteval::usize_const(self.db, Some(len as u128), self.owner.krate(self.db.upcast())); + + let elem_ty = self.table.new_type_var(); + let array_ty = TyKind::Array(elem_ty.clone(), size).intern(Interner); + Some(array_ty) + } } pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 156366045705..9e0920e41ba4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -3814,3 +3814,31 @@ async fn foo(a: (), b: i32) -> u32 { "#, ); } + +#[test] +fn irrefutable_slices() { + check_infer( + r#" +//- minicore: from +struct A; + +impl From for [u8; 2] { + fn from(a: A) -> Self { + [0; 2] + } +} +impl From for [u8; 3] { + fn from(a: A) -> Self { + [0; 3] + } +} + + +fn main() { + let a = A; + let [b, c] = a.into(); +} +"#, + expect![], + ); +}