make [u8] and [u8;N] literal patterns usable in deref patterns
Specifically, this allows byte string literal patterns to be used where a `[u8]` or `[u8;N]` is expected when `deref_patterns` is enabled.
This commit is contained in:
parent
61840254c5
commit
32503440cd
7 changed files with 181 additions and 10 deletions
|
|
@ -759,19 +759,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Byte string patterns behave the same way as array patterns
|
||||
// They can denote both statically and dynamically-sized byte arrays.
|
||||
// Additionally, when `deref_patterns` is enabled, byte string literal patterns may have
|
||||
// types `[u8]` or `[u8; N]`, in order to type, e.g., `deref!(b"..."): Vec<u8>`.
|
||||
let mut pat_ty = ty;
|
||||
if let hir::PatExprKind::Lit {
|
||||
lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
|
||||
} = lt.kind
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
let expected = self.structurally_resolve_type(span, expected);
|
||||
if let ty::Ref(_, inner_ty, _) = *expected.kind()
|
||||
&& self.try_structurally_resolve_type(span, inner_ty).is_slice()
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
|
||||
pat_ty =
|
||||
Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8));
|
||||
match *expected.kind() {
|
||||
// Allow `b"...": &[u8]`
|
||||
ty::Ref(_, inner_ty, _)
|
||||
if self.try_structurally_resolve_type(span, inner_ty).is_slice() =>
|
||||
{
|
||||
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
|
||||
pat_ty = Ty::new_imm_ref(
|
||||
tcx,
|
||||
tcx.lifetimes.re_static,
|
||||
Ty::new_slice(tcx, tcx.types.u8),
|
||||
);
|
||||
}
|
||||
// Allow `b"...": [u8; 3]` for `deref_patterns`
|
||||
ty::Array(..) if tcx.features().deref_patterns() => {
|
||||
pat_ty = match *ty.kind() {
|
||||
ty::Ref(_, inner_ty, _) => inner_ty,
|
||||
_ => span_bug!(span, "found byte string literal with non-ref type {ty:?}"),
|
||||
}
|
||||
}
|
||||
// Allow `b"...": [u8]` for `deref_patterns`
|
||||
ty::Slice(..) if tcx.features().deref_patterns() => {
|
||||
pat_ty = Ty::new_slice(tcx, tcx.types.u8);
|
||||
}
|
||||
// Otherwise, `b"...": &[u8; 3]`
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,12 +44,16 @@ pub(crate) fn lit_to_const<'tcx>(
|
|||
ty::ValTree::from_raw_bytes(tcx, str_bytes)
|
||||
}
|
||||
(ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _))
|
||||
if matches!(inner_ty.kind(), ty::Slice(_)) =>
|
||||
if matches!(inner_ty.kind(), ty::Slice(_) | ty::Array(..)) =>
|
||||
{
|
||||
let bytes = data as &[u8];
|
||||
ty::ValTree::from_raw_bytes(tcx, bytes)
|
||||
}
|
||||
(ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
|
||||
(ast::LitKind::ByteStr(data, _), ty::Slice(_) | ty::Array(..))
|
||||
if tcx.features().deref_patterns() =>
|
||||
{
|
||||
// Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is
|
||||
// enabled, in order to allow, e.g., `deref!(b"..."): Vec<u8>`.
|
||||
let bytes = data as &[u8];
|
||||
ty::ValTree::from_raw_bytes(tcx, bytes)
|
||||
}
|
||||
|
|
|
|||
34
tests/ui/pattern/deref-patterns/byte-string-type-errors.rs
Normal file
34
tests/ui/pattern/deref-patterns/byte-string-type-errors.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
//! Test type errors for byte string literal patterns. `deref_patterns` allows byte string literal
|
||||
//! patterns to have type `[u8]` or `[u8; N]` when matching on a slice or array; this can affect the
|
||||
//! "found" type reported in error messages when matching on a slice or array of the wrong type.
|
||||
|
||||
#![feature(deref_patterns)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
fn main() {
|
||||
// Baseline 1: under normal circumstances, byte string literal patterns have type `&[u8; N]`,
|
||||
// the same as byte string literals.
|
||||
if let b"test" = () {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `()`, found `&[u8; 4]`
|
||||
|
||||
// Baseline 2: there's a special case for byte string patterns in stable rust, allowing them to
|
||||
// match on slice references. This affects the error when matching on a non-`&[u8]` slice ref,
|
||||
// reporting the "found" type as `&[u8]`.
|
||||
if let b"test" = &[] as &[i8] {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `&[i8]`, found `&[u8]`
|
||||
|
||||
// Test matching on a non-`[u8]` slice: the pattern has type `[u8]` if a slice is expected.
|
||||
if let b"test" = *(&[] as &[i8]) {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `[i8]`, found `[u8]`
|
||||
|
||||
// Test matching on a non-`[u8;4]` array: the pattern has type `[u8;4]` if an array is expected.
|
||||
if let b"test" = [()] {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `[(); 1]`, found `[u8; 4]`
|
||||
if let b"test" = *b"this array is too long" {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected an array with a size of 22, found one with a size of 4
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:11:12
|
||||
|
|
||||
LL | if let b"test" = () {}
|
||||
| ^^^^^^^ -- this expression has type `()`
|
||||
| |
|
||||
| expected `()`, found `&[u8; 4]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:18:12
|
||||
|
|
||||
LL | if let b"test" = &[] as &[i8] {}
|
||||
| ^^^^^^^ ------------ this expression has type `&[i8]`
|
||||
| |
|
||||
| expected `&[i8]`, found `&[u8]`
|
||||
|
|
||||
= note: expected reference `&[i8]`
|
||||
found reference `&'static [u8]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:23:12
|
||||
|
|
||||
LL | if let b"test" = *(&[] as &[i8]) {}
|
||||
| ^^^^^^^ --------------- this expression has type `[i8]`
|
||||
| |
|
||||
| expected `[i8]`, found `[u8]`
|
||||
|
|
||||
= note: expected slice `[i8]`
|
||||
found slice `[u8]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:28:12
|
||||
|
|
||||
LL | if let b"test" = [()] {}
|
||||
| ^^^^^^^ ---- this expression has type `[(); 1]`
|
||||
| |
|
||||
| expected `[(); 1]`, found `[u8; 4]`
|
||||
|
|
||||
= note: expected array `[(); 1]`
|
||||
found array `[u8; 4]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:31:12
|
||||
|
|
||||
LL | if let b"test" = *b"this array is too long" {}
|
||||
| ^^^^^^^ -------------------------- this expression has type `[u8; 22]`
|
||||
| |
|
||||
| expected an array with a size of 22, found one with a size of 4
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
|
@ -19,4 +19,14 @@ fn main() {
|
|||
//~^ ERROR: mismatched types
|
||||
_ => {}
|
||||
}
|
||||
match *b"test" {
|
||||
b"test" => {}
|
||||
//~^ ERROR: mismatched types
|
||||
_ => {}
|
||||
}
|
||||
match *(b"test" as &[u8]) {
|
||||
b"test" => {}
|
||||
//~^ ERROR: mismatched types
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,23 @@ LL | match *"test" {
|
|||
LL | "test" => {}
|
||||
| ^^^^^^ expected `str`, found `&str`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/needs-gate.rs:23:9
|
||||
|
|
||||
LL | match *b"test" {
|
||||
| -------- this expression has type `[u8; 4]`
|
||||
LL | b"test" => {}
|
||||
| ^^^^^^^ expected `[u8; 4]`, found `&[u8; 4]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/needs-gate.rs:28:9
|
||||
|
|
||||
LL | match *(b"test" as &[u8]) {
|
||||
| ------------------- this expression has type `[u8]`
|
||||
LL | b"test" => {}
|
||||
| ^^^^^^^ expected `[u8]`, found `&[u8; 4]`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0658.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
|
|
|
|||
|
|
@ -29,4 +29,38 @@ fn main() {
|
|||
s.make_ascii_uppercase();
|
||||
}
|
||||
assert_eq!(test, "TEST");
|
||||
|
||||
for (test_in, test_expect) in [(b"0", 0), (b"1", 1), (b"2", 2)] {
|
||||
// Test byte string literal patterns having type `[u8; N]`
|
||||
let test_actual = match *test_in {
|
||||
b"0" => 0,
|
||||
b"1" => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test byte string literal patterns having type `[u8]`
|
||||
let test_actual = match *(test_in as &[u8]) {
|
||||
b"0" => 0,
|
||||
b"1" => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test byte string literals used as arrays in explicit `deref!(_)` patterns.
|
||||
let test_actual = match Box::new(*test_in) {
|
||||
deref!(b"0") => 0,
|
||||
deref!(b"1") => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test byte string literals used as slices in explicit `deref!(_)` patterns.
|
||||
let test_actual = match test_in.to_vec() {
|
||||
deref!(b"0") => 0,
|
||||
deref!(b"1") => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue