Skip to content

Commit a9ce750

Browse files
committed
Pull array length determination out of prefix_slice_suffix
1 parent 414e00d commit a9ce750

1 file changed

Lines changed: 48 additions & 37 deletions

File tree

compiler/rustc_mir_build/src/builder/matches/match_pair.rs

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -40,33 +40,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4040
match_pairs: &mut Vec<MatchPairTree<'tcx>>,
4141
extra_data: &mut PatternExtraData<'tcx>,
4242
place: &PlaceBuilder<'tcx>,
43+
array_len: Option<u64>,
4344
prefix: &[Pat<'tcx>],
4445
opt_slice: &Option<Box<Pat<'tcx>>>,
4546
suffix: &[Pat<'tcx>],
4647
) {
47-
let tcx = self.tcx;
48-
let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
49-
let place_ty = place_resolved.ty(&self.local_decls, tcx).ty;
50-
match place_ty.kind() {
51-
ty::Array(_, length) => {
52-
if let Some(length) = length.try_to_target_usize(tcx) {
53-
(length, true)
54-
} else {
55-
// This can happen when the array length is a generic const
56-
// expression that couldn't be evaluated (e.g., due to an error).
57-
// Since there's already a compilation error, we use a fallback
58-
// to avoid an ICE.
59-
tcx.dcx().span_delayed_bug(
60-
tcx.def_span(self.def_id),
61-
"array length in pattern couldn't be evaluated",
62-
);
63-
((prefix.len() + suffix.len()).try_into().unwrap(), false)
64-
}
65-
}
66-
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
67-
}
68-
} else {
69-
((prefix.len() + suffix.len()).try_into().unwrap(), false)
48+
let prefix_len = u64::try_from(prefix.len()).unwrap();
49+
let suffix_len = u64::try_from(suffix.len()).unwrap();
50+
51+
// For slice patterns with a `..` followed by 0 or more suffix subpatterns,
52+
// the actual slice index of those subpatterns isn't statically known, so
53+
// we have to index them relative to the end of the slice.
54+
//
55+
// For array patterns, all subpatterns are indexed relative to the start.
56+
let (min_length, is_array) = match array_len {
57+
Some(len) => (len, true),
58+
None => (prefix_len + suffix_len, false),
7059
};
7160

7261
for (idx, subpattern) in prefix.iter().enumerate() {
@@ -77,21 +66,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
7766
}
7867

7968
if let Some(subslice_pat) = opt_slice {
80-
let suffix_len = suffix.len() as u64;
8169
let subslice = place.clone_project(PlaceElem::Subslice {
82-
from: prefix.len() as u64,
83-
to: if exact_size { min_length - suffix_len } else { suffix_len },
84-
from_end: !exact_size,
70+
from: prefix_len,
71+
to: if is_array { min_length - suffix_len } else { suffix_len },
72+
from_end: !is_array,
8573
});
8674
MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data);
8775
}
8876

8977
for (idx, subpattern) in suffix.iter().rev().enumerate() {
9078
let end_offset = (idx + 1) as u64;
9179
let elem = ProjectionElem::ConstantIndex {
92-
offset: if exact_size { min_length - end_offset } else { end_offset },
80+
offset: if is_array { min_length - end_offset } else { end_offset },
9381
min_length,
94-
from_end: !exact_size,
82+
from_end: !is_array,
9583
};
9684
let place = place.clone_project(elem);
9785
MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data)
@@ -256,21 +244,44 @@ impl<'tcx> MatchPairTree<'tcx> {
256244
}
257245

258246
PatKind::Array { ref prefix, ref slice, ref suffix } => {
259-
cx.prefix_slice_suffix(
260-
&mut subpairs,
261-
extra_data,
262-
&place_builder,
263-
prefix,
264-
slice,
265-
suffix,
266-
);
247+
// Determine the statically-known length of the array type being matched.
248+
// This should always succeed for legal programs, but could fail for
249+
// erroneous programs (e.g. the type is `[u8; const { panic!() }]`),
250+
// so take care not to ICE if this fails.
251+
let array_len = match pattern.ty.kind() {
252+
ty::Array(_, len) => len.try_to_target_usize(cx.tcx),
253+
_ => None,
254+
};
255+
if let Some(array_len) = array_len {
256+
cx.prefix_slice_suffix(
257+
&mut subpairs,
258+
extra_data,
259+
&place_builder,
260+
Some(array_len),
261+
prefix,
262+
slice,
263+
suffix,
264+
);
265+
} else {
266+
// If the array length couldn't be determined, ignore the
267+
// subpatterns and delayed-assert that compilation will fail.
268+
cx.tcx.dcx().span_delayed_bug(
269+
pattern.span,
270+
format!(
271+
"array length in pattern couldn't be determined for ty={:?}",
272+
pattern.ty
273+
),
274+
);
275+
}
276+
267277
None
268278
}
269279
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
270280
cx.prefix_slice_suffix(
271281
&mut subpairs,
272282
extra_data,
273283
&place_builder,
284+
None,
274285
prefix,
275286
slice,
276287
suffix,

0 commit comments

Comments
 (0)