FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
/// Array patterns of length `n`.
FixedLenSlice(u64),
+ /// Array patterns of length `len`, but for which we only care about the `prefix` first values
+ /// and the `suffix` last values. This avoids unnecessarily going through values we know to be
+ /// uninteresting, which can be a major problem for large arrays.
+ LazyFixedLenSlice {
+ len: u64, // The actual length of the array
+ prefix: u64,
+ suffix: u64,
+ },
/// Slice patterns. Captures any array constructor of `length >= i + j`.
VarLenSlice(u64, u64),
/// Fake extra constructor for enums that aren't allowed to be matched exhaustively.
impl<'tcx> Constructor<'tcx> {
fn is_slice(&self) -> bool {
match self {
- FixedLenSlice { .. } | VarLenSlice { .. } => true,
+ FixedLenSlice { .. } | LazyFixedLenSlice { .. } | VarLenSlice { .. } => true,
_ => false,
}
}
Single | Variant(_) | ConstantValue(..) | FloatRange(..) => {
if other_ctors.iter().any(|c| c == self) { vec![] } else { vec![self.clone()] }
}
- &FixedLenSlice(self_len) => {
+ &FixedLenSlice(self_len) | &LazyFixedLenSlice { len: self_len, .. } => {
let overlaps = |c: &Constructor<'_>| match *c {
- FixedLenSlice(other_len) => other_len == self_len,
+ FixedLenSlice(len) | LazyFixedLenSlice { len, .. } => len == self_len,
VarLenSlice(prefix, suffix) => prefix + suffix <= self_len,
_ => false,
};
// Compute `pos_ctor \ neg_ctor`.
match pos_ctor {
FixedLenSlice(pos_len) => match *neg_ctor {
- FixedLenSlice(neg_len) if neg_len == pos_len => smallvec![],
+ FixedLenSlice(neg_len)
+ | LazyFixedLenSlice { len: neg_len, .. }
+ if neg_len == pos_len =>
+ {
+ smallvec![]
+ }
VarLenSlice(neg_prefix, neg_suffix)
if neg_prefix + neg_suffix <= pos_len =>
{
VarLenSlice(pos_prefix, pos_suffix) => {
let pos_len = pos_prefix + pos_suffix;
match *neg_ctor {
- FixedLenSlice(neg_len) if neg_len >= pos_len => {
+ FixedLenSlice(neg_len)
+ | LazyFixedLenSlice { len: neg_len, .. }
+ if neg_len >= pos_len =>
+ {
(pos_len..neg_len)
.map(FixedLenSlice)
// We know that `neg_len + 1 >= pos_len >=
}
_ => vec![],
},
- FixedLenSlice(_) | VarLenSlice(..) => match ty.kind {
+ FixedLenSlice(_) | LazyFixedLenSlice { .. } | VarLenSlice(..) => match ty.kind {
ty::Slice(ty) | ty::Array(ty, _) => {
let arity = self.arity(cx, ty);
(0..arity).map(|_| Pat::wildcard_from_ty(ty)).collect()
_ => 0,
},
FixedLenSlice(length) => *length,
- VarLenSlice(prefix, suffix) => prefix + suffix,
+ VarLenSlice(prefix, suffix) | LazyFixedLenSlice { prefix, suffix, .. } => {
+ prefix + suffix
+ }
ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => 0,
}
}
FixedLenSlice(_) => {
PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
}
- &VarLenSlice(prefix_len, _) => {
- let prefix = subpatterns.by_ref().take(prefix_len as usize).collect();
+ LazyFixedLenSlice { len, prefix, suffix } if prefix + suffix == *len => {
+ PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
+ }
+ VarLenSlice(prefix, _) | LazyFixedLenSlice { prefix, .. } => {
+ let prefix = subpatterns.by_ref().take(*prefix as usize).collect();
let suffix = subpatterns.collect();
let wild = Pat::wildcard_from_ty(ty);
PatKind::Slice { prefix, slice: Some(wild), suffix }
}
ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
let len = len.eval_usize(cx.tcx, cx.param_env);
- if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { vec![FixedLenSlice(len)] }
+ if len != 0 && cx.is_uninhabited(sub_ty) {
+ vec![]
+ } else {
+ vec![LazyFixedLenSlice { len, prefix: 0, suffix: 0 }]
+ }
}
// Treat arrays of a constant but unknown length like slices.
ty::Array(ref sub_ty, _) | ty::Slice(ref sub_ty) => {
Some(FloatRange(lo, hi, end))
}
}
- PatKind::Array { .. } => match pat.ty.kind {
- ty::Array(_, length) => Some(FixedLenSlice(length.eval_usize(tcx, param_env))),
- _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pat.ty),
- },
+ PatKind::Array { ref prefix, ref slice, ref suffix } => {
+ let len = match pat.ty.kind {
+ ty::Array(_, length) => length.eval_usize(tcx, param_env),
+ _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pat.ty),
+ };
+ let prefix = prefix.len() as u64;
+ let suffix = suffix.len() as u64;
+ if slice.is_some() {
+ Some(LazyFixedLenSlice { len, prefix, suffix })
+ } else {
+ Some(FixedLenSlice(len))
+ }
+ }
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
let prefix = prefix.len() as u64;
let suffix = suffix.len() as u64;
) -> Vec<Constructor<'tcx>> {
let ty = pcx.ty;
let mut split_ctors = Vec::with_capacity(ctors.len());
+ debug!("split_grouped_constructors({:#?}, {:#?})", matrix, ctors);
for ctor in ctors.into_iter() {
match ctor {
.map(IntRange),
);
}
- VarLenSlice(self_prefix, self_suffix) => {
+ VarLenSlice(self_prefix, self_suffix)
+ | LazyFixedLenSlice { prefix: self_prefix, suffix: self_suffix, .. } => {
// The exhaustiveness-checking paper does not include any details on
// checking variable-length slice patterns. However, they are matched
// by an infinite collection of fixed-length array patterns.
_ => {}
}
}
- PatKind::Slice { ref prefix, slice: None, ref suffix } => {
+ PatKind::Slice { ref prefix, slice: None, ref suffix }
+ | PatKind::Array { ref prefix, slice: None, ref suffix } => {
let fixed_len = prefix.len() as u64 + suffix.len() as u64;
max_fixed_len = cmp::max(max_fixed_len, fixed_len);
}
- PatKind::Slice { ref prefix, slice: Some(_), ref suffix } => {
+ PatKind::Slice { ref prefix, slice: Some(_), ref suffix }
+ | PatKind::Array { ref prefix, slice: Some(_), ref suffix } => {
max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64);
max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64);
}
max_prefix_len = max_fixed_len + 1 - max_suffix_len;
}
- // `ctor` originally covered the range `(self_prefix + self_suffix..infinity)`. We
- // now split it into two: lengths smaller than `max_prefix_len + max_suffix_len`
- // are treated independently as fixed-lengths slices, and lengths above are
- // captured by a final VarLenSlice constructor.
- split_ctors.extend(
- (self_prefix + self_suffix..max_prefix_len + max_suffix_len).map(FixedLenSlice),
- );
- split_ctors.push(VarLenSlice(max_prefix_len, max_suffix_len));
+ match ctor {
+ LazyFixedLenSlice { len, .. } => {
+ if max_prefix_len + max_suffix_len < len {
+ split_ctors.push(LazyFixedLenSlice {
+ len,
+ prefix: max_prefix_len,
+ suffix: max_suffix_len,
+ });
+ } else {
+ split_ctors.push(FixedLenSlice(len));
+ }
+ }
+ _ => {
+ // `ctor` originally covered the range `(self_prefix + self_suffix..infinity)`. We
+ // now split it into two: lengths smaller than `max_prefix_len + max_suffix_len`
+ // are treated independently as fixed-lengths slices, and lengths above are
+ // captured by a final VarLenSlice constructor.
+ split_ctors.extend(
+ (self_prefix + self_suffix..max_prefix_len + max_suffix_len)
+ .map(FixedLenSlice),
+ );
+ split_ctors.push(VarLenSlice(max_prefix_len, max_suffix_len));
+ }
+ }
}
// Any other constructor can be used unchanged.
_ => split_ctors.push(ctor),
}
}
+ debug!("split_grouped_constructors(..)={:#?}", split_ctors);
split_ctors
}
PatKind::Array { ref prefix, ref slice, ref suffix }
| PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor {
- FixedLenSlice(..) | VarLenSlice(..) => {
+ FixedLenSlice(..) | LazyFixedLenSlice { .. } | VarLenSlice(..) => {
let pat_len = prefix.len() + suffix.len();
if let Some(slice_count) = ctor_wild_subpatterns.len().checked_sub(pat_len) {
if slice_count == 0 || slice.is_some() {
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: `&[false, _, _]` not covered
+error[E0004]: non-exhaustive patterns: `&[false, .., _]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:14:11
|
LL | match s3 {
- | ^^ pattern `&[false, _, _]` not covered
+ | ^^ pattern `&[false, .., _]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: `&[false, _, _, _, _, _, _, _, _, _]` not covered
+error[E0004]: non-exhaustive patterns: `&[false, .., _]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:18:11
|
LL | match s10 {
- | ^^^ pattern `&[false, _, _, _, _, _, _, _, _, _]` not covered
+ | ^^^ pattern `&[false, .., _]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: `&[false, _, true]` not covered
+error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:32:11
|
LL | match s3 {
- | ^^ pattern `&[false, _, true]` not covered
+ | ^^ pattern `&[false, .., true]` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms