Skip to content

Commit 66dac52

Browse files
committed
Move range exhaustiveness check to IntRange::intersection
Only IntRange needs to worry about range exhaustiveness really.
1 parent d8b71d4 commit 66dac52

File tree

1 file changed

+30
-18
lines changed

1 file changed

+30
-18
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,9 @@ impl<'tcx> Constructor<'tcx> {
647647
match self {
648648
// Any base constructor can be used unchanged.
649649
Single | Variant(_) | ConstantValue(_) | FixedLenSlice(_) => smallvec![self],
650-
ConstantRange(..) if should_treat_range_exhaustively(cx.tcx, &self) => {
650+
ConstantRange(ref lo, ..)
651+
if IntRange::should_treat_range_exhaustively(cx.tcx, lo.ty) =>
652+
{
651653
// Splitting up a range naïvely would mean creating a separate constructor for
652654
// every single value in the range, which is clearly impractical. We therefore want
653655
// to keep together subranges for which the specialisation will be identical across
@@ -707,7 +709,7 @@ impl<'tcx> Constructor<'tcx> {
707709
let row_borders = head_ctors
708710
.iter()
709711
.flat_map(|ctor| IntRange::from_ctor(cx.tcx, cx.param_env, ctor))
710-
.flat_map(|range| ctor_range.intersection(&range))
712+
.flat_map(|range| ctor_range.intersection(cx.tcx, &range))
711713
.flat_map(|range| range_borders(range));
712714
let ctor_borders = range_borders(ctor_range.clone());
713715
let mut borders: Vec<_> = row_borders.chain(ctor_borders).collect();
@@ -1477,6 +1479,13 @@ impl<'tcx> IntRange<'tcx> {
14771479
}
14781480
}
14791481

1482+
fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
1483+
// Don't treat `usize`/`isize` exhaustively unless the `precise_pointer_size_matching`
1484+
// feature is enabled.
1485+
IntRange::is_integral(ty)
1486+
&& (!ty.is_ptr_sized_integral() || tcx.features().precise_pointer_size_matching)
1487+
}
1488+
14801489
#[inline]
14811490
fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> {
14821491
match ty.kind {
@@ -1625,14 +1634,19 @@ impl<'tcx> IntRange<'tcx> {
16251634
remaining_ranges
16261635
}
16271636

1628-
fn intersection(&self, other: &Self) -> Option<Self> {
1637+
fn intersection(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Option<Self> {
16291638
let ty = self.ty;
16301639
let (lo, hi) = (*self.range.start(), *self.range.end());
16311640
let (other_lo, other_hi) = (*other.range.start(), *other.range.end());
1632-
if lo <= other_hi && other_lo <= hi {
1633-
Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), ty })
1641+
if Self::should_treat_range_exhaustively(tcx, ty) {
1642+
if lo <= other_hi && other_lo <= hi {
1643+
Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), ty })
1644+
} else {
1645+
None
1646+
}
16341647
} else {
1635-
None
1648+
// If the range sould not be treated exhaustively, fallback to checking for inclusion.
1649+
if other_lo <= lo && hi <= other_hi { Some(self.clone()) } else { None }
16361650
}
16371651
}
16381652
}
@@ -1918,19 +1932,14 @@ fn slice_pat_covered_by_const<'tcx>(
19181932
Ok(true)
19191933
}
19201934

1921-
// Whether to evaluate a constructor using exhaustive integer matching. This is true if the
1922-
// constructor is a range or constant with an integer type.
1923-
fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>) -> bool {
1935+
// Whether a constructor is a range or constant with an integer type.
1936+
fn is_integral_range(ctor: &Constructor<'tcx>) -> bool {
19241937
let ty = match ctor {
19251938
ConstantValue(value) => value.ty,
19261939
ConstantRange(lo, _, _) => lo.ty,
19271940
_ => return false,
19281941
};
1929-
if let ty::Char | ty::Int(_) | ty::Uint(_) = ty.kind {
1930-
!ty.is_ptr_sized_integral() || tcx.features().precise_pointer_size_matching
1931-
} else {
1932-
false
1933-
}
1942+
IntRange::is_integral(ty)
19341943
}
19351944

19361945
/// Checks whether there exists any shared value in either `ctor` or `pat` by intersecting them.
@@ -1945,7 +1954,7 @@ fn constructor_intersects_pattern<'p, 'tcx>(
19451954
trace!("constructor_intersects_pattern {:#?}, {:#?}", ctor, pat);
19461955
if let Single = ctor {
19471956
Some(PatStack::default())
1948-
} else if should_treat_range_exhaustively(tcx, ctor) {
1957+
} else if is_integral_range(ctor) {
19491958
let range = match *pat.kind {
19501959
PatKind::Constant { value } => ConstantValue(value),
19511960
PatKind::Range(PatRange { lo, hi, end }) => ConstantRange(lo, hi, end),
@@ -1954,11 +1963,14 @@ fn constructor_intersects_pattern<'p, 'tcx>(
19541963

19551964
let pat = IntRange::from_ctor(tcx, param_env, &range)?;
19561965
let ctor = IntRange::from_ctor(tcx, param_env, ctor)?;
1957-
ctor.intersection(&pat)?;
1966+
ctor.intersection(tcx, &pat)?;
19581967

1968+
// Constructor splitting should ensure that all intersections we encounter are actually
1969+
// inclusions.
19591970
let (pat_lo, pat_hi) = pat.range.into_inner();
19601971
let (ctor_lo, ctor_hi) = ctor.range.into_inner();
19611972
assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi);
1973+
19621974
Some(PatStack::default())
19631975
} else {
19641976
// Fallback for non-ranges and ranges that involve floating-point numbers, which are not
@@ -1976,10 +1988,10 @@ fn constructor_intersects_pattern<'p, 'tcx>(
19761988
};
19771989
let order_to = compare_const_vals(tcx, ctor_to, pat_to, param_env, pat_from.ty)?;
19781990
let order_from = compare_const_vals(tcx, ctor_from, pat_from, param_env, pat_from.ty)?;
1979-
let intersects = (order_from != Ordering::Less)
1991+
let included = (order_from != Ordering::Less)
19801992
&& ((order_to == Ordering::Less)
19811993
|| (pat_end == ctor_end && order_to == Ordering::Equal));
1982-
if intersects { Some(PatStack::default()) } else { None }
1994+
if included { Some(PatStack::default()) } else { None }
19831995
}
19841996
}
19851997

0 commit comments

Comments
 (0)