Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/infer/pat.rs35
-rw-r--r--crates/hir-ty/src/tests/simple.rs28
2 files changed, 62 insertions, 1 deletions
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index ca8d5bae5e..83b1346047 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/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<PatId>,
+ ) -> Option<Ty> {
+ 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/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 1563660457..9e0920e41b 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/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<A> for [u8; 2] {
+ fn from(a: A) -> Self {
+ [0; 2]
+ }
+}
+impl From<A> for [u8; 3] {
+ fn from(a: A) -> Self {
+ [0; 3]
+ }
+}
+
+
+fn main() {
+ let a = A;
+ let [b, c] = a.into();
+}
+"#,
+ expect![],
+ );
+}