Skip to content

Commit 84784dd

Browse files
committed
Eagerly convert ranges to IntRange
That way no `ConstantRange` or `ConstantValue` ever needs to be converted to `IntRange`.
1 parent 6b8bfef commit 84784dd

File tree

1 file changed

+63
-58
lines changed

1 file changed

+63
-58
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 63 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -593,8 +593,7 @@ enum Constructor<'tcx> {
593593
ConstantValue(&'tcx ty::Const<'tcx>, Span),
594594
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
595595
IntRange(IntRange<'tcx>),
596-
// TODO: non-integer
597-
/// Ranges of literal values (`2.0..=5.2`).
596+
/// Ranges of non-integer literal values (`2.0..=5.2`).
598597
ConstantRange(u128, u128, Ty<'tcx>, RangeEnd, Span),
599598
/// Array patterns of length `n`.
600599
FixedLenSlice(u64),
@@ -636,13 +635,10 @@ impl<'tcx> Constructor<'tcx> {
636635
}
637636

638637
fn is_integral_range(&self) -> bool {
639-
let ty = match self {
640-
ConstantValue(value, _) => value.ty,
641-
ConstantRange(_, _, ty, _, _) => ty,
638+
match self {
642639
IntRange(_) => return true,
643640
_ => return false,
644641
};
645-
IntRange::is_integral(ty)
646642
}
647643

648644
fn variant_index_for_adt<'a>(
@@ -669,7 +665,7 @@ impl<'tcx> Constructor<'tcx> {
669665
param_env: ty::ParamEnv<'tcx>,
670666
other_ctors: &Vec<Constructor<'tcx>>,
671667
) -> Vec<Constructor<'tcx>> {
672-
match *self {
668+
match self {
673669
// Those constructors can only match themselves.
674670
Single | Variant(_) => {
675671
if other_ctors.iter().any(|c| c == self) {
@@ -678,7 +674,7 @@ impl<'tcx> Constructor<'tcx> {
678674
vec![self.clone()]
679675
}
680676
}
681-
FixedLenSlice(self_len) => {
677+
&FixedLenSlice(self_len) => {
682678
let overlaps = |c: &Constructor<'_>| match *c {
683679
FixedLenSlice(other_len) => other_len == self_len,
684680
VarLenSlice(prefix, suffix) => prefix + suffix <= self_len,
@@ -749,41 +745,39 @@ impl<'tcx> Constructor<'tcx> {
749745

750746
remaining_ctors
751747
}
752-
IntRange(..) | ConstantRange(..) | ConstantValue(..) => {
753-
if let Some(self_range) = IntRange::from_ctor(tcx, param_env, self) {
754-
let mut remaining_ranges = vec![self_range.clone()];
755-
let other_ranges = other_ctors
756-
.into_iter()
757-
.filter_map(|c| IntRange::from_ctor(tcx, param_env, c));
758-
for other_range in other_ranges {
759-
if other_range == self_range {
760-
// If the `self` range appears directly in a `match` arm, we can
761-
// eliminate it straight away.
762-
remaining_ranges = vec![];
763-
} else {
764-
// Otherwise explicitely compute the remaining ranges.
765-
remaining_ranges = other_range.subtract_from(remaining_ranges);
766-
}
748+
IntRange(self_range) => {
749+
let mut remaining_ranges = vec![self_range.clone()];
750+
let other_ranges =
751+
other_ctors.into_iter().filter_map(|c| IntRange::from_ctor(tcx, param_env, c));
752+
for other_range in other_ranges {
753+
if other_range == *self_range {
754+
// If the `self` range appears directly in a `match` arm, we can
755+
// eliminate it straight away.
756+
remaining_ranges = vec![];
757+
} else {
758+
// Otherwise explicitely compute the remaining ranges.
759+
remaining_ranges = other_range.subtract_from(remaining_ranges);
760+
}
767761

768-
// If the ranges that have been considered so far already cover the entire
769-
// range of values, we can return early.
770-
if remaining_ranges.is_empty() {
771-
break;
772-
}
762+
// If the ranges that have been considered so far already cover the entire
763+
// range of values, we can return early.
764+
if remaining_ranges.is_empty() {
765+
break;
773766
}
767+
}
774768

775-
// Convert the ranges back into constructors
776-
remaining_ranges.into_iter().map(IntRange).collect()
769+
// Convert the ranges back into constructors
770+
remaining_ranges.into_iter().map(IntRange).collect()
771+
}
772+
ConstantRange(..) | ConstantValue(..) => {
773+
if other_ctors.iter().any(|c| {
774+
c == self
775+
// FIXME(Nadrieril): This condition looks fishy
776+
|| IntRange::from_ctor(tcx, param_env, c).is_some()
777+
}) {
778+
vec![]
777779
} else {
778-
if other_ctors.iter().any(|c| {
779-
c == self
780-
// FIXME(Nadrieril): This condition looks fishy
781-
|| IntRange::from_ctor(tcx, param_env, c).is_some()
782-
}) {
783-
vec![]
784-
} else {
785-
vec![self.clone()]
786-
}
780+
vec![self.clone()]
787781
}
788782
}
789783
// This constructor is never covered by anything else
@@ -1285,6 +1279,10 @@ impl<'tcx> IntRange<'tcx> {
12851279
}
12861280
}
12871281

1282+
fn is_singleton(&self) -> bool {
1283+
self.range.start() == self.range.end()
1284+
}
1285+
12881286
fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
12891287
// Don't treat `usize`/`isize` exhaustively unless the `precise_pointer_size_matching`
12901288
// feature is enabled.
@@ -1363,15 +1361,13 @@ impl<'tcx> IntRange<'tcx> {
13631361
}
13641362

13651363
fn from_ctor(
1366-
tcx: TyCtxt<'tcx>,
1367-
param_env: ty::ParamEnv<'tcx>,
1364+
_tcx: TyCtxt<'tcx>,
1365+
_param_env: ty::ParamEnv<'tcx>,
13681366
ctor: &Constructor<'tcx>,
13691367
) -> Option<IntRange<'tcx>> {
13701368
// Floating-point ranges are permitted and we don't want
13711369
// to consider them when constructing integer ranges.
13721370
match ctor {
1373-
ConstantRange(lo, hi, ty, end, span) => Self::from_range(tcx, *lo, *hi, ty, end, *span),
1374-
ConstantValue(val, span) => Self::from_const(tcx, param_env, val, *span),
13751371
IntRange(range) => Some(range.clone()),
13761372
_ => None,
13771373
}
@@ -1747,14 +1743,23 @@ fn pat_constructor<'tcx>(
17471743
PatKind::Variant { adt_def, variant_index, .. } => {
17481744
Some(Variant(adt_def.variants[variant_index].def_id))
17491745
}
1750-
PatKind::Constant { value } => Some(ConstantValue(value, pat.span)),
1751-
PatKind::Range(PatRange { lo, hi, end }) => Some(ConstantRange(
1752-
lo.eval_bits(tcx, param_env, lo.ty),
1753-
hi.eval_bits(tcx, param_env, hi.ty),
1754-
lo.ty,
1755-
end,
1756-
pat.span,
1757-
)),
1746+
PatKind::Constant { value } => {
1747+
if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) {
1748+
Some(IntRange(int_range))
1749+
} else {
1750+
Some(ConstantValue(value, pat.span))
1751+
}
1752+
}
1753+
PatKind::Range(PatRange { lo, hi, end }) => {
1754+
let ty = lo.ty;
1755+
let lo = lo.eval_bits(tcx, param_env, lo.ty);
1756+
let hi = hi.eval_bits(tcx, param_env, hi.ty);
1757+
if let Some(int_range) = IntRange::from_range(tcx, lo, hi, ty, &end, pat.span) {
1758+
Some(IntRange(int_range))
1759+
} else {
1760+
Some(ConstantRange(lo, hi, ty, end, pat.span))
1761+
}
1762+
}
17581763
PatKind::Array { .. } => match pat.ty.kind {
17591764
ty::Array(_, length) => Some(FixedLenSlice(length.eval_usize(tcx, param_env))),
17601765
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pat.ty),
@@ -1897,13 +1902,13 @@ fn split_grouped_constructors<'p, 'tcx>(
18971902

18981903
for ctor in ctors.into_iter() {
18991904
match ctor {
1900-
IntRange(..) | ConstantRange(..)
1901-
if IntRange::should_treat_range_exhaustively(tcx, ty) =>
1902-
{
1903-
// We only care about finding all the subranges within the range of the constructor
1904-
// range. Anything else is irrelevant, because it is guaranteed to result in
1905-
// `NotUseful`, which is the default case anyway, and can be ignored.
1906-
let ctor_range = IntRange::from_ctor(tcx, param_env, &ctor).unwrap();
1905+
IntRange(ctor_range) if IntRange::should_treat_range_exhaustively(tcx, ty) => {
1906+
// Fast-track if the range is trivial. In particular, don't do the overlapping
1907+
// ranges check.
1908+
if ctor_range.is_singleton() {
1909+
split_ctors.push(IntRange(ctor_range));
1910+
continue;
1911+
}
19071912

19081913
/// Represents a border between 2 integers. Because the intervals spanning borders
19091914
/// must be able to cover every integer, we need to be able to represent

0 commit comments

Comments
 (0)