diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index 50fd2dd749..9821815ca3 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs @@ -6,6 +6,7 @@ use chalk_ir::Mutability; use hir_def::{ expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat}, path::Path, + type_ref::ConstScalar, }; use hir_expand::name::Name; @@ -14,7 +15,8 @@ use crate::{ Adjust, Adjustment, AutoBorrow, BindingMode, Expectation, InferenceContext, TypeMismatch, }, lower::lower_to_chalk_mutability, - static_lifetime, Interner, Substitution, Ty, TyBuilder, TyExt, TyKind, + static_lifetime, ConcreteConst, ConstValue, Interner, Substitution, Ty, TyBuilder, TyExt, + TyKind, }; impl<'a> InferenceContext<'a> { @@ -232,16 +234,28 @@ impl<'a> InferenceContext<'a> { self.infer_pat(pat_id, &elem_ty, default_bm); } - let pat_ty = match expected.kind(Interner) { + if let &Some(slice_pat_id) = slice { + let rest_pat_ty = match expected.kind(Interner) { + TyKind::Array(_, length) => { + let length = match length.data(Interner).value { + ConstValue::Concrete(ConcreteConst { + interned: ConstScalar::Usize(length), + }) => length.checked_sub((prefix.len() + suffix.len()) as u64), + _ => None, + }; + TyKind::Array(elem_ty.clone(), crate::consteval::usize_const(length)) + } + _ => TyKind::Slice(elem_ty.clone()), + } + .intern(Interner); + self.infer_pat(slice_pat_id, &rest_pat_ty, default_bm); + } + + match expected.kind(Interner) { TyKind::Array(_, const_) => TyKind::Array(elem_ty, const_.clone()), _ => TyKind::Slice(elem_ty), } - .intern(Interner); - if let &Some(slice_pat_id) = slice { - self.infer_pat(slice_pat_id, &pat_ty, default_bm); - } - - pat_ty + .intern(Interner) } Pat::Wild => expected.clone(), Pat::Range { start, end } => { diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index fb687cf20c..5b08d65c46 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs @@ -890,6 +890,32 @@ fn main() { ); } +#[test] +fn slice_pattern_correctly_handles_array_length() { + check_infer( + r#" +fn main() { + let [head, middle @ .., tail, tail2] = [1, 2, 3, 4, 5]; +} + "#, + expect![[r#" + 10..73 '{ ... 5]; }': () + 20..52 '[head,...tail2]': [i32; 5] + 21..25 'head': i32 + 27..38 'middle @ ..': [i32; 2] + 36..38 '..': [i32; 2] + 40..44 'tail': i32 + 46..51 'tail2': i32 + 55..70 '[1, 2, 3, 4, 5]': [i32; 5] + 56..57 '1': i32 + 59..60 '2': i32 + 62..63 '3': i32 + 65..66 '4': i32 + 68..69 '5': i32 + "#]], + ); +} + #[test] fn pattern_lookup_in_value_ns() { check_types(