Skip to content

Commit 8f2ce3d

Browse files
committed
Document and simplify pattern matching with constants as patterns
1 parent a5a7fcb commit 8f2ce3d

File tree

1 file changed

+51
-42
lines changed

1 file changed

+51
-42
lines changed

src/librustc_mir/hair/pattern/_match.rs

+51-42
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,16 @@ struct LiteralExpander<'a, 'tcx> {
209209

210210
impl<'a, 'tcx> LiteralExpander<'a, 'tcx> {
211211
/// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice
212+
///
213+
/// `crty` and `rty` can differ because you can use array constants in the presence of slice
214+
/// patterns. So the pattern may end up being a slice, but the constant is an array. We convert
215+
/// the array to a slice in that case
212216
fn fold_const_value_deref(
213217
&mut self,
214218
val: ConstValue<'tcx>,
219+
// the pattern's pointee type
215220
rty: Ty<'tcx>,
221+
// the constant's pointee type
216222
crty: Ty<'tcx>,
217223
) -> ConstValue<'tcx> {
218224
match (val, &crty.sty, &rty.sty) {
@@ -776,6 +782,7 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
776782
for row in patterns {
777783
match *row.kind {
778784
PatternKind::Constant { value } => {
785+
// extract the length of an array/slice from a constant
779786
match (value.val, &value.ty.sty) {
780787
(_, ty::Array(_, n)) => max_fixed_len = cmp::max(
781788
max_fixed_len,
@@ -1393,53 +1400,55 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
13931400
}
13941401
}
13951402

1396-
fn slice_pat_covered_by_constructor<'tcx>(
1403+
// checks whether a constant is equal to a user-written slice pattern. Only supports byte slices,
1404+
// meaning all other types will compare unequal and thus equal patterns often do not cause the
1405+
// second pattern to lint about unreachable match arms.
1406+
fn slice_pat_covered_by_const<'tcx>(
13971407
tcx: TyCtxt<'_, 'tcx, '_>,
13981408
_span: Span,
1399-
ctor: &Constructor,
1409+
const_val: &ty::Const<'tcx>,
14001410
prefix: &[Pattern<'tcx>],
14011411
slice: &Option<Pattern<'tcx>>,
14021412
suffix: &[Pattern<'tcx>]
14031413
) -> Result<bool, ErrorReported> {
1404-
let data: &[u8] = match *ctor {
1405-
ConstantValue(const_val) => {
1406-
match (const_val.val, &const_val.ty.sty) {
1407-
(ConstValue::ByRef(id, alloc, offset), ty::Array(t, n)) => {
1408-
if *t != tcx.types.u8 {
1409-
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
1410-
// any sort of exhaustiveness/unreachable check yet
1411-
return Ok(false);
1412-
}
1413-
let ptr = Pointer::new(id, offset);
1414-
let n = n.assert_usize(tcx).unwrap();
1415-
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
1416-
},
1417-
(ConstValue::ScalarPair(Scalar::Bits { .. }, n), ty::Slice(_)) => {
1418-
assert_eq!(n.to_usize(&tcx).unwrap(), 0);
1419-
&[]
1420-
},
1421-
(ConstValue::ScalarPair(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
1422-
if *t != tcx.types.u8 {
1423-
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
1424-
// any sort of exhaustiveness/unreachable check yet
1425-
return Ok(false);
1426-
}
1427-
let n = n.to_usize(&tcx).unwrap();
1428-
tcx.alloc_map
1429-
.lock()
1430-
.unwrap_memory(ptr.alloc_id)
1431-
.get_bytes(&tcx, ptr, Size::from_bytes(n))
1432-
.unwrap()
1433-
},
1434-
_ => bug!(
1435-
"slice_pat_covered_by_constructor: {:#?}, {:#?}, {:#?}, {:#?}",
1436-
ctor, prefix, slice, suffix,
1437-
),
1414+
let data: &[u8] = match (const_val.val, &const_val.ty.sty) {
1415+
(ConstValue::ByRef(id, alloc, offset), ty::Array(t, n)) => {
1416+
if *t != tcx.types.u8 {
1417+
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
1418+
// any sort of exhaustiveness/unreachable check yet
1419+
return Ok(false);
14381420
}
1439-
}
1421+
let ptr = Pointer::new(id, offset);
1422+
let n = n.assert_usize(tcx).unwrap();
1423+
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
1424+
},
1425+
// a slice fat pointer to a zero length slice
1426+
(ConstValue::ScalarPair(Scalar::Bits { .. }, n), ty::Slice(t)) => {
1427+
if *t != tcx.types.u8 {
1428+
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
1429+
// any sort of exhaustiveness/unreachable check yet
1430+
return Ok(false);
1431+
}
1432+
assert_eq!(n.to_usize(&tcx).unwrap(), 0);
1433+
&[]
1434+
},
1435+
//
1436+
(ConstValue::ScalarPair(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
1437+
if *t != tcx.types.u8 {
1438+
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
1439+
// any sort of exhaustiveness/unreachable check yet
1440+
return Ok(false);
1441+
}
1442+
let n = n.to_usize(&tcx).unwrap();
1443+
tcx.alloc_map
1444+
.lock()
1445+
.unwrap_memory(ptr.alloc_id)
1446+
.get_bytes(&tcx, ptr, Size::from_bytes(n))
1447+
.unwrap()
1448+
},
14401449
_ => bug!(
1441-
"slice_pat_covered_by_constructor not ConstValue: {:#?}, {:#?}, {:#?}, {:#?}",
1442-
ctor, prefix, slice, suffix,
1450+
"slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
1451+
const_val, prefix, slice, suffix,
14431452
),
14441453
};
14451454

@@ -1837,9 +1846,9 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
18371846
None
18381847
}
18391848
}
1840-
ConstantValue(..) => {
1841-
match slice_pat_covered_by_constructor(
1842-
cx.tcx, pat.span, constructor, prefix, slice, suffix
1849+
ConstantValue(cv) => {
1850+
match slice_pat_covered_by_const(
1851+
cx.tcx, pat.span, cv, prefix, slice, suffix
18431852
) {
18441853
Ok(true) => Some(smallvec![]),
18451854
Ok(false) => None,

0 commit comments

Comments
 (0)