try to infer array type from slice pattern

rust-analyzer equivalent of rust-lang/rust#2827aa97
This commit is contained in:
Ali Bektas 2025-01-28 21:38:56 +01:00
parent bc10a44798
commit d092918b55
2 changed files with 62 additions and 1 deletions

View File

@ -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 {

View File

@ -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![],
);
}