1
Fork 0

Special-case range inclusion when the range is integral but non-exhaustive

This commit is contained in:
Nadrieril 2019-11-07 18:52:13 +00:00
parent f3752ee5d5
commit 81db2ee902

View file

@ -641,6 +641,15 @@ impl<'tcx> Constructor<'tcx> {
IntRange::should_treat_range_exhaustively(tcx, ty)
}
fn is_integral_range(&self) -> bool {
let ty = match self {
ConstantValue(value, _) => value.ty,
ConstantRange(_, _, ty, _, _) => ty,
_ => return false,
};
IntRange::is_integral(ty)
}
fn variant_index_for_adt<'a>(
&self,
cx: &MatchCheckCtxt<'a, 'tcx>,
@ -1471,6 +1480,12 @@ impl<'tcx> IntRange<'tcx> {
}
}
fn is_subrange(&self, other: &Self) -> bool {
let (lo, hi) = (*self.range.start(), *self.range.end());
let (other_lo, other_hi) = (*other.range.start(), *other.range.end());
other_lo <= lo && hi <= other_hi
}
fn suspicious_intersection(&self, other: &Self) -> bool {
// `false` in the following cases:
// 1 ---- // 1 ---------- // 1 ---- // 1 ----
@ -2300,6 +2315,8 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
IntRange::from_pat(cx.tcx, cx.param_env, pat),
) {
(Some(ctor), Some(pat)) => ctor.intersection(&pat).map(|_| {
// Constructor splitting should ensure that all intersections we encounter
// are actually inclusions.
let (pat_lo, pat_hi) = pat.range.into_inner();
let (ctor_lo, ctor_hi) = ctor.range.into_inner();
assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi);
@ -2307,6 +2324,16 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
}),
_ => None,
}
} else if constructor.is_integral_range() {
// If we have an integer range that should not be matched exhaustively, fallback to
// checking for inclusion.
match (
IntRange::from_ctor(cx.tcx, cx.param_env, constructor),
IntRange::from_pat(cx.tcx, cx.param_env, pat),
) {
(Some(ctor), Some(pat)) if ctor.is_subrange(&pat) => Some(PatStack::default()),
_ => None,
}
} else {
// Fallback for non-ranges and ranges that involve
// floating-point numbers, which are not conveniently handled