Skip to content

Commit

Permalink
try to infer array type from slice pattern
Browse files Browse the repository at this point in the history
rust-analyzer equivalent of rust-lang/rust#2827aa97
  • Loading branch information
alibektas committed Jan 28, 2025
1 parent 2386e95 commit db07adf
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 1 deletion.
35 changes: 34 additions & 1 deletion src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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 {
Expand Down
28 changes: 28 additions & 0 deletions src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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![],
);
}

0 comments on commit db07adf

Please sign in to comment.