fix: infer byte string pattern as &[u8]
when matched against slices
This commit is contained in:
parent
e1e93c4438
commit
ffc6b42901
@ -14,8 +14,9 @@ use crate::{
|
|||||||
consteval::intern_const_scalar,
|
consteval::intern_const_scalar,
|
||||||
infer::{BindingMode, Expectation, InferenceContext, TypeMismatch},
|
infer::{BindingMode, Expectation, InferenceContext, TypeMismatch},
|
||||||
lower::lower_to_chalk_mutability,
|
lower::lower_to_chalk_mutability,
|
||||||
static_lifetime, ConcreteConst, ConstValue, Interner, Substitution, Ty, TyBuilder, TyExt,
|
primitive::UintTy,
|
||||||
TyKind,
|
static_lifetime, ConcreteConst, ConstValue, Interner, Scalar, Substitution, Ty, TyBuilder,
|
||||||
|
TyExt, TyKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::PatLike;
|
use super::PatLike;
|
||||||
@ -294,7 +295,29 @@ impl<'a> InferenceContext<'a> {
|
|||||||
let start_ty = self.infer_expr(*start, &Expectation::has_type(expected.clone()));
|
let start_ty = self.infer_expr(*start, &Expectation::has_type(expected.clone()));
|
||||||
self.infer_expr(*end, &Expectation::has_type(start_ty))
|
self.infer_expr(*end, &Expectation::has_type(start_ty))
|
||||||
}
|
}
|
||||||
Pat::Lit(expr) => self.infer_expr(*expr, &Expectation::has_type(expected.clone())),
|
&Pat::Lit(expr) => {
|
||||||
|
// FIXME: using `Option` here is a workaround until we can use if-let chains in stable.
|
||||||
|
let mut pat_ty = None;
|
||||||
|
|
||||||
|
// Like slice patterns, byte string patterns can denote both `&[u8; N]` and `&[u8]`.
|
||||||
|
if let Expr::Literal(Literal::ByteString(_)) = self.body[expr] {
|
||||||
|
if let Some((inner, ..)) = expected.as_reference() {
|
||||||
|
let inner = self.resolve_ty_shallow(inner);
|
||||||
|
if matches!(inner.kind(Interner), TyKind::Slice(_)) {
|
||||||
|
let elem_ty = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner);
|
||||||
|
let slice_ty = TyKind::Slice(elem_ty).intern(Interner);
|
||||||
|
let ty = TyKind::Ref(Mutability::Not, static_lifetime(), slice_ty)
|
||||||
|
.intern(Interner);
|
||||||
|
self.write_expr_ty(expr, ty.clone());
|
||||||
|
pat_ty = Some(ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pat_ty.unwrap_or_else(|| {
|
||||||
|
self.infer_expr(expr, &Expectation::has_type(expected.clone()))
|
||||||
|
})
|
||||||
|
}
|
||||||
Pat::Box { inner } => match self.resolve_boxed_box() {
|
Pat::Box { inner } => match self.resolve_boxed_box() {
|
||||||
Some(box_adt) => {
|
Some(box_adt) => {
|
||||||
let (inner_ty, alloc_ty) = match expected.as_adt() {
|
let (inner_ty, alloc_ty) = match expected.as_adt() {
|
||||||
@ -343,7 +366,9 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
|
|||||||
// FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented.
|
// FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented.
|
||||||
Pat::Path(..) => true,
|
Pat::Path(..) => true,
|
||||||
Pat::ConstBlock(..) => true,
|
Pat::ConstBlock(..) => true,
|
||||||
Pat::Lit(expr) => !matches!(body[*expr], Expr::Literal(Literal::String(..))),
|
Pat::Lit(expr) => {
|
||||||
|
!matches!(body[*expr], Expr::Literal(Literal::String(..) | Literal::ByteString(..)))
|
||||||
|
}
|
||||||
Pat::Bind {
|
Pat::Bind {
|
||||||
mode: BindingAnnotation::Mutable | BindingAnnotation::Unannotated,
|
mode: BindingAnnotation::Mutable | BindingAnnotation::Unannotated,
|
||||||
subpat: Some(subpat),
|
subpat: Some(subpat),
|
||||||
|
@ -315,6 +315,51 @@ fn infer_pattern_match_string_literal() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_pattern_match_byte_string_literal() {
|
||||||
|
check_infer_with_mismatches(
|
||||||
|
r#"
|
||||||
|
//- minicore: index
|
||||||
|
struct S;
|
||||||
|
impl<T, const N: usize> core::ops::Index<S> for [T; N] {
|
||||||
|
type Output = [u8];
|
||||||
|
fn index(&self, index: core::ops::RangeFull) -> &Self::Output {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn test(v: [u8; 3]) {
|
||||||
|
if let b"foo" = &v[S] {}
|
||||||
|
if let b"foo" = &v {}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
105..109 'self': &[T; N]
|
||||||
|
111..116 'index': {unknown}
|
||||||
|
157..180 '{ ... }': &[u8]
|
||||||
|
167..174 'loop {}': !
|
||||||
|
172..174 '{}': ()
|
||||||
|
191..192 'v': [u8; 3]
|
||||||
|
203..261 '{ ...v {} }': ()
|
||||||
|
209..233 'if let...[S] {}': ()
|
||||||
|
212..230 'let b"... &v[S]': bool
|
||||||
|
216..222 'b"foo"': &[u8]
|
||||||
|
216..222 'b"foo"': &[u8]
|
||||||
|
225..230 '&v[S]': &[u8]
|
||||||
|
226..227 'v': [u8; 3]
|
||||||
|
226..230 'v[S]': [u8]
|
||||||
|
228..229 'S': S
|
||||||
|
231..233 '{}': ()
|
||||||
|
238..259 'if let... &v {}': ()
|
||||||
|
241..256 'let b"foo" = &v': bool
|
||||||
|
245..251 'b"foo"': &[u8; 3]
|
||||||
|
245..251 'b"foo"': &[u8; 3]
|
||||||
|
254..256 '&v': &[u8; 3]
|
||||||
|
255..256 'v': [u8; 3]
|
||||||
|
257..259 '{}': ()
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_pattern_match_or() {
|
fn infer_pattern_match_or() {
|
||||||
check_infer_with_mismatches(
|
check_infer_with_mismatches(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user