Document and simplify pattern matching with constants as patterns
This commit is contained in:
parent
a5a7fcbde3
commit
8f2ce3d839
1 changed files with 51 additions and 42 deletions
|
@ -209,10 +209,16 @@ struct LiteralExpander<'a, 'tcx> {
|
||||||
|
|
||||||
impl<'a, 'tcx> LiteralExpander<'a, 'tcx> {
|
impl<'a, 'tcx> LiteralExpander<'a, 'tcx> {
|
||||||
/// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice
|
/// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice
|
||||||
|
///
|
||||||
|
/// `crty` and `rty` can differ because you can use array constants in the presence of slice
|
||||||
|
/// patterns. So the pattern may end up being a slice, but the constant is an array. We convert
|
||||||
|
/// the array to a slice in that case
|
||||||
fn fold_const_value_deref(
|
fn fold_const_value_deref(
|
||||||
&mut self,
|
&mut self,
|
||||||
val: ConstValue<'tcx>,
|
val: ConstValue<'tcx>,
|
||||||
|
// the pattern's pointee type
|
||||||
rty: Ty<'tcx>,
|
rty: Ty<'tcx>,
|
||||||
|
// the constant's pointee type
|
||||||
crty: Ty<'tcx>,
|
crty: Ty<'tcx>,
|
||||||
) -> ConstValue<'tcx> {
|
) -> ConstValue<'tcx> {
|
||||||
match (val, &crty.sty, &rty.sty) {
|
match (val, &crty.sty, &rty.sty) {
|
||||||
|
@ -776,6 +782,7 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
|
||||||
for row in patterns {
|
for row in patterns {
|
||||||
match *row.kind {
|
match *row.kind {
|
||||||
PatternKind::Constant { value } => {
|
PatternKind::Constant { value } => {
|
||||||
|
// extract the length of an array/slice from a constant
|
||||||
match (value.val, &value.ty.sty) {
|
match (value.val, &value.ty.sty) {
|
||||||
(_, ty::Array(_, n)) => max_fixed_len = cmp::max(
|
(_, ty::Array(_, n)) => max_fixed_len = cmp::max(
|
||||||
max_fixed_len,
|
max_fixed_len,
|
||||||
|
@ -1393,53 +1400,55 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slice_pat_covered_by_constructor<'tcx>(
|
// checks whether a constant is equal to a user-written slice pattern. Only supports byte slices,
|
||||||
|
// meaning all other types will compare unequal and thus equal patterns often do not cause the
|
||||||
|
// second pattern to lint about unreachable match arms.
|
||||||
|
fn slice_pat_covered_by_const<'tcx>(
|
||||||
tcx: TyCtxt<'_, 'tcx, '_>,
|
tcx: TyCtxt<'_, 'tcx, '_>,
|
||||||
_span: Span,
|
_span: Span,
|
||||||
ctor: &Constructor,
|
const_val: &ty::Const<'tcx>,
|
||||||
prefix: &[Pattern<'tcx>],
|
prefix: &[Pattern<'tcx>],
|
||||||
slice: &Option<Pattern<'tcx>>,
|
slice: &Option<Pattern<'tcx>>,
|
||||||
suffix: &[Pattern<'tcx>]
|
suffix: &[Pattern<'tcx>]
|
||||||
) -> Result<bool, ErrorReported> {
|
) -> Result<bool, ErrorReported> {
|
||||||
let data: &[u8] = match *ctor {
|
let data: &[u8] = match (const_val.val, &const_val.ty.sty) {
|
||||||
ConstantValue(const_val) => {
|
(ConstValue::ByRef(id, alloc, offset), ty::Array(t, n)) => {
|
||||||
match (const_val.val, &const_val.ty.sty) {
|
if *t != tcx.types.u8 {
|
||||||
(ConstValue::ByRef(id, alloc, offset), ty::Array(t, n)) => {
|
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
|
||||||
if *t != tcx.types.u8 {
|
// any sort of exhaustiveness/unreachable check yet
|
||||||
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
|
return Ok(false);
|
||||||
// any sort of exhaustiveness/unreachable check yet
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
let ptr = Pointer::new(id, offset);
|
|
||||||
let n = n.assert_usize(tcx).unwrap();
|
|
||||||
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
|
|
||||||
},
|
|
||||||
(ConstValue::ScalarPair(Scalar::Bits { .. }, n), ty::Slice(_)) => {
|
|
||||||
assert_eq!(n.to_usize(&tcx).unwrap(), 0);
|
|
||||||
&[]
|
|
||||||
},
|
|
||||||
(ConstValue::ScalarPair(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
|
|
||||||
if *t != tcx.types.u8 {
|
|
||||||
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
|
|
||||||
// any sort of exhaustiveness/unreachable check yet
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
let n = n.to_usize(&tcx).unwrap();
|
|
||||||
tcx.alloc_map
|
|
||||||
.lock()
|
|
||||||
.unwrap_memory(ptr.alloc_id)
|
|
||||||
.get_bytes(&tcx, ptr, Size::from_bytes(n))
|
|
||||||
.unwrap()
|
|
||||||
},
|
|
||||||
_ => bug!(
|
|
||||||
"slice_pat_covered_by_constructor: {:#?}, {:#?}, {:#?}, {:#?}",
|
|
||||||
ctor, prefix, slice, suffix,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
let ptr = Pointer::new(id, offset);
|
||||||
|
let n = n.assert_usize(tcx).unwrap();
|
||||||
|
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
|
||||||
|
},
|
||||||
|
// a slice fat pointer to a zero length slice
|
||||||
|
(ConstValue::ScalarPair(Scalar::Bits { .. }, n), ty::Slice(t)) => {
|
||||||
|
if *t != tcx.types.u8 {
|
||||||
|
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
|
||||||
|
// any sort of exhaustiveness/unreachable check yet
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
assert_eq!(n.to_usize(&tcx).unwrap(), 0);
|
||||||
|
&[]
|
||||||
|
},
|
||||||
|
//
|
||||||
|
(ConstValue::ScalarPair(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
|
||||||
|
if *t != tcx.types.u8 {
|
||||||
|
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
|
||||||
|
// any sort of exhaustiveness/unreachable check yet
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
let n = n.to_usize(&tcx).unwrap();
|
||||||
|
tcx.alloc_map
|
||||||
|
.lock()
|
||||||
|
.unwrap_memory(ptr.alloc_id)
|
||||||
|
.get_bytes(&tcx, ptr, Size::from_bytes(n))
|
||||||
|
.unwrap()
|
||||||
|
},
|
||||||
_ => bug!(
|
_ => bug!(
|
||||||
"slice_pat_covered_by_constructor not ConstValue: {:#?}, {:#?}, {:#?}, {:#?}",
|
"slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
|
||||||
ctor, prefix, slice, suffix,
|
const_val, prefix, slice, suffix,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1837,9 +1846,9 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConstantValue(..) => {
|
ConstantValue(cv) => {
|
||||||
match slice_pat_covered_by_constructor(
|
match slice_pat_covered_by_const(
|
||||||
cx.tcx, pat.span, constructor, prefix, slice, suffix
|
cx.tcx, pat.span, cv, prefix, slice, suffix
|
||||||
) {
|
) {
|
||||||
Ok(true) => Some(smallvec![]),
|
Ok(true) => Some(smallvec![]),
|
||||||
Ok(false) => None,
|
Ok(false) => None,
|
||||||
|
|
Loading…
Reference in a new issue