Skip to content

Commit db07adf

Browse files
committed
try to infer array type from slice pattern
rust-analyzer equivalent of rust-lang/rust#2827aa97
1 parent 2386e95 commit db07adf

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ use hir_def::{
66
expr_store::Body,
77
hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId},
88
path::Path,
9+
HasModule,
910
};
1011
use hir_expand::name::Name;
1112
use stdx::TupleExt;
1213

1314
use crate::{
14-
consteval::{try_const_usize, usize_const},
15+
consteval::{self, try_const_usize, usize_const},
1516
infer::{
1617
coerce::CoerceNever, expr::ExprIsRead, BindingMode, Expectation, InferenceContext,
1718
TypeMismatch,
@@ -479,6 +480,19 @@ impl InferenceContext<'_> {
479480
suffix: &[PatId],
480481
default_bm: BindingMode,
481482
) -> Ty {
483+
let expected = self.resolve_ty_shallow(expected);
484+
485+
// If `expected` is an infer ty, we try to equate it to an array if the given pattern
486+
// allows it. See issue #16609
487+
if expected.is_ty_var() {
488+
if let Some(resolved_array_ty) =
489+
self.try_resolve_slice_ty_to_array_ty(prefix, suffix, slice)
490+
{
491+
self.unify(&expected, &resolved_array_ty);
492+
}
493+
}
494+
495+
let expected = self.resolve_ty_shallow(&expected);
482496
let elem_ty = match expected.kind(Interner) {
483497
TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(),
484498
_ => self.err_ty(),
@@ -553,6 +567,25 @@ impl InferenceContext<'_> {
553567
| Pat::Expr(_) => false,
554568
}
555569
}
570+
571+
fn try_resolve_slice_ty_to_array_ty(
572+
&mut self,
573+
before: &[PatId],
574+
suffix: &[PatId],
575+
slice: &Option<PatId>,
576+
) -> Option<Ty> {
577+
if !slice.is_none() {
578+
return None;
579+
}
580+
581+
let len = before.len() + suffix.len();
582+
let size =
583+
consteval::usize_const(self.db, Some(len as u128), self.owner.krate(self.db.upcast()));
584+
585+
let elem_ty = self.table.new_type_var();
586+
let array_ty = TyKind::Array(elem_ty.clone(), size).intern(Interner);
587+
Some(array_ty)
588+
}
556589
}
557590

558591
pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool {

src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3814,3 +3814,31 @@ async fn foo(a: (), b: i32) -> u32 {
38143814
"#,
38153815
);
38163816
}
3817+
3818+
#[test]
3819+
fn irrefutable_slices() {
3820+
check_infer(
3821+
r#"
3822+
//- minicore: from
3823+
struct A;
3824+
3825+
impl From<A> for [u8; 2] {
3826+
fn from(a: A) -> Self {
3827+
[0; 2]
3828+
}
3829+
}
3830+
impl From<A> for [u8; 3] {
3831+
fn from(a: A) -> Self {
3832+
[0; 3]
3833+
}
3834+
}
3835+
3836+
3837+
fn main() {
3838+
let a = A;
3839+
let [b, c] = a.into();
3840+
}
3841+
"#,
3842+
expect![],
3843+
);
3844+
}

0 commit comments

Comments
 (0)