mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
try to infer array type from slice pattern
rust-analyzer equivalent of rust-lang/rust#2827aa97
This commit is contained in:
parent
bc10a44798
commit
d092918b55
@ -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 {
|
||||
|
@ -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![],
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user