Skip to content

Commit b85e4be

Browse files
committed
Introduce IntRange meta-constructor
1 parent 66dac52 commit b85e4be

File tree

1 file changed

+93
-23
lines changed

1 file changed

+93
-23
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 93 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,9 @@ enum Constructor<'tcx> {
585585
FixedLenSlice(u64),
586586

587587
// Meta-constructors
588-
/// Ranges of literal values (`2..=5` and `2..5`).
588+
/// Ranges of integer literal values (`2..=5` and `2..5`).
589+
IntRange(IntRange<'tcx>),
590+
/// Ranges of non-integer literal values (`2.0..=5.2`).
589591
ConstantRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
590592
/// Slice patterns. Captures any array constructor of length >= i+j.
591593
VarLenSlice(u64, u64),
@@ -647,8 +649,8 @@ impl<'tcx> Constructor<'tcx> {
647649
match self {
648650
// Any base constructor can be used unchanged.
649651
Single | Variant(_) | ConstantValue(_) | FixedLenSlice(_) => smallvec![self],
650-
ConstantRange(ref lo, ..)
651-
if IntRange::should_treat_range_exhaustively(cx.tcx, lo.ty) =>
652+
ConstantRange(..) | IntRange(..)
653+
if IntRange::should_treat_range_exhaustively(cx.tcx, ty) =>
652654
{
653655
// Splitting up a range naïvely would mean creating a separate constructor for
654656
// every single value in the range, which is clearly impractical. We therefore want
@@ -734,7 +736,7 @@ impl<'tcx> Constructor<'tcx> {
734736
.map(|range| IntRange::range_to_ctor(cx.tcx, ty, range))
735737
.collect()
736738
}
737-
ConstantRange(..) => smallvec![self],
739+
ConstantRange(..) | IntRange(..) => smallvec![self],
738740
VarLenSlice(self_prefix, self_suffix) => {
739741
// A variable-length slice pattern is matched by an infinite collection of
740742
// fixed-length array patterns. However it turns out that for each finite set of
@@ -1045,7 +1047,7 @@ impl<'tcx> Constructor<'tcx> {
10451047

10461048
remaining_ctors
10471049
}
1048-
ConstantRange(..) | ConstantValue(..) => {
1050+
ConstantRange(..) | ConstantValue(..) | IntRange(..) => {
10491051
let mut remaining_ctors = smallvec![self];
10501052

10511053
// For each used ctor, subtract from the current set of constructors.
@@ -1137,7 +1139,11 @@ impl<'tcx> Constructor<'tcx> {
11371139
ty::Slice(ty) | ty::Array(ty, _) => (0..prefix + suffix).map(|_| ty).collect(),
11381140
_ => bug!("bad slice pattern {:?} {:?}", self, ty),
11391141
},
1140-
ConstantValue(_) | MissingConstructors(_) | ConstantRange(..) | Wildcard => vec![],
1142+
ConstantValue(_)
1143+
| MissingConstructors(_)
1144+
| ConstantRange(..)
1145+
| IntRange(..)
1146+
| Wildcard => vec![],
11411147
};
11421148

11431149
subpattern_types.into_iter().map(|ty| Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild })
@@ -1162,7 +1168,11 @@ impl<'tcx> Constructor<'tcx> {
11621168
},
11631169
FixedLenSlice(length) => length,
11641170
VarLenSlice(prefix, suffix) => prefix + suffix,
1165-
ConstantValue(_) | ConstantRange(..) | Wildcard | MissingConstructors(_) => 0,
1171+
ConstantValue(_)
1172+
| ConstantRange(..)
1173+
| IntRange(..)
1174+
| Wildcard
1175+
| MissingConstructors(_) => 0,
11661176
}
11671177
}
11681178

@@ -1230,6 +1240,7 @@ impl<'tcx> Constructor<'tcx> {
12301240
},
12311241
ConstantValue(value) => PatKind::Constant { value },
12321242
ConstantRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
1243+
IntRange(ref range) => range.to_patkind(cx.tcx),
12331244
Wildcard => PatKind::Wild,
12341245
MissingConstructors(ref missing_ctors) => {
12351246
// Construct for each missing constructor a "wildcard" version of this
@@ -1424,8 +1435,26 @@ fn all_constructors<'a, 'tcx>(
14241435
let to_const = |x| ty::Const::from_bits(cx.tcx, x as u128, param_env);
14251436
vec![
14261437
// The valid Unicode Scalar Value ranges.
1427-
ConstantRange(to_const('\u{0000}'), to_const('\u{D7FF}'), RangeEnd::Included),
1428-
ConstantRange(to_const('\u{E000}'), to_const('\u{10FFFF}'), RangeEnd::Included),
1438+
IntRange(
1439+
IntRange::from_range(
1440+
cx.tcx,
1441+
cx.param_env,
1442+
to_const('\u{0000}'),
1443+
to_const('\u{D7FF}'),
1444+
&RangeEnd::Included,
1445+
)
1446+
.unwrap(),
1447+
),
1448+
IntRange(
1449+
IntRange::from_range(
1450+
cx.tcx,
1451+
cx.param_env,
1452+
to_const('\u{E000}'),
1453+
to_const('\u{10FFFF}'),
1454+
&RangeEnd::Included,
1455+
)
1456+
.unwrap(),
1457+
),
14291458
]
14301459
}
14311460
ty::Int(ity) => {
@@ -1434,14 +1463,32 @@ fn all_constructors<'a, 'tcx>(
14341463
let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128;
14351464
let min = 1u128 << (bits - 1);
14361465
let max = min - 1;
1437-
vec![ConstantRange(to_const(min), to_const(max), RangeEnd::Included)]
1466+
vec![IntRange(
1467+
IntRange::from_range(
1468+
cx.tcx,
1469+
cx.param_env,
1470+
to_const(min),
1471+
to_const(max),
1472+
&RangeEnd::Included,
1473+
)
1474+
.unwrap(),
1475+
)]
14381476
}
14391477
ty::Uint(uty) => {
14401478
let param_env = ty::ParamEnv::empty().and(ty);
14411479
let to_const = |x| ty::Const::from_bits(cx.tcx, x, param_env);
14421480
let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size();
14431481
let max = truncate(u128::max_value(), size);
1444-
vec![ConstantRange(to_const(0), to_const(max), RangeEnd::Included)]
1482+
vec![IntRange(
1483+
IntRange::from_range(
1484+
cx.tcx,
1485+
cx.param_env,
1486+
to_const(0),
1487+
to_const(max),
1488+
&RangeEnd::Included,
1489+
)
1490+
.unwrap(),
1491+
)]
14451492
}
14461493
_ => {
14471494
if cx.is_uninhabited(ty) {
@@ -1464,7 +1511,7 @@ fn all_constructors<'a, 'tcx>(
14641511
///
14651512
/// `IntRange` is never used to encode an empty range or a "range" that wraps
14661513
/// around the (offset) space: i.e., `range.lo <= range.hi`.
1467-
#[derive(Clone)]
1514+
#[derive(Debug, Clone, PartialEq)]
14681515
struct IntRange<'tcx> {
14691516
pub range: RangeInclusive<u128>,
14701517
pub ty: Ty<'tcx>,
@@ -1563,6 +1610,7 @@ impl<'tcx> IntRange<'tcx> {
15631610
// Floating-point ranges are permitted and we don't want
15641611
// to consider them when constructing integer ranges.
15651612
match ctor {
1613+
IntRange(range) => Some(range.clone()),
15661614
ConstantRange(lo, hi, end) => Self::from_range(tcx, param_env, lo, hi, end),
15671615
ConstantValue(val) => Self::from_const(tcx, param_env, val),
15681616
_ => None,
@@ -1580,21 +1628,30 @@ impl<'tcx> IntRange<'tcx> {
15801628
}
15811629
}
15821630

1583-
/// Converts a `RangeInclusive` to a `ConstantValue` or inclusive `ConstantRange`.
1631+
/// Converts a `RangeInclusive` to a `Constructor`.
15841632
fn range_to_ctor(
1585-
tcx: TyCtxt<'tcx>,
1633+
_tcx: TyCtxt<'tcx>,
15861634
ty: Ty<'tcx>,
1587-
r: RangeInclusive<u128>,
1635+
range: RangeInclusive<u128>,
15881636
) -> Constructor<'tcx> {
1589-
let bias = IntRange::signed_bias(tcx, ty);
1590-
let (lo, hi) = r.into_inner();
1637+
IntRange(IntRange { ty, range })
1638+
}
1639+
1640+
/// Converts an `IntRange` to a `PatKind::Constant` or inclusive `PatKind::Range`.
1641+
fn to_patkind(&self, tcx: TyCtxt<'tcx>) -> PatKind<'tcx> {
1642+
let bias = IntRange::signed_bias(tcx, self.ty);
1643+
let (lo, hi) = self.range.clone().into_inner();
15911644
if lo == hi {
1592-
let ty = ty::ParamEnv::empty().and(ty);
1593-
ConstantValue(ty::Const::from_bits(tcx, lo ^ bias, ty))
1645+
let ty = ty::ParamEnv::empty().and(self.ty);
1646+
PatKind::Constant { value: ty::Const::from_bits(tcx, lo ^ bias, ty) }
15941647
} else {
1595-
let param_env = ty::ParamEnv::empty().and(ty);
1648+
let param_env = ty::ParamEnv::empty().and(self.ty);
15961649
let to_const = |x| ty::Const::from_bits(tcx, x, param_env);
1597-
ConstantRange(to_const(lo ^ bias), to_const(hi ^ bias), RangeEnd::Included)
1650+
PatKind::Range(PatRange {
1651+
lo: to_const(lo ^ bias),
1652+
hi: to_const(hi ^ bias),
1653+
end: RangeEnd::Included,
1654+
})
15981655
}
15991656
}
16001657

@@ -1851,8 +1908,20 @@ fn pat_constructors<'tcx>(
18511908
PatKind::Variant { adt_def, variant_index, .. } => {
18521909
smallvec![Variant(adt_def.variants[variant_index].def_id)]
18531910
}
1854-
PatKind::Constant { value } => smallvec![ConstantValue(value)],
1855-
PatKind::Range(PatRange { lo, hi, end }) => smallvec![ConstantRange(lo, hi, end)],
1911+
PatKind::Constant { value } => {
1912+
if let Some(range) = IntRange::from_const(tcx, param_env, value) {
1913+
smallvec![IntRange(range)]
1914+
} else {
1915+
smallvec![ConstantValue(value)]
1916+
}
1917+
}
1918+
PatKind::Range(PatRange { lo, hi, end }) => {
1919+
if let Some(range) = IntRange::from_range(tcx, param_env, &lo, &hi, &end) {
1920+
smallvec![IntRange(range)]
1921+
} else {
1922+
smallvec![ConstantRange(lo, hi, end)]
1923+
}
1924+
}
18561925
PatKind::Array { .. } => match ty.kind {
18571926
ty::Array(_, length) => smallvec![FixedLenSlice(length.eval_usize(tcx, param_env))],
18581927
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", ty),
@@ -1935,6 +2004,7 @@ fn slice_pat_covered_by_const<'tcx>(
19352004
// Whether a constructor is a range or constant with an integer type.
19362005
fn is_integral_range(ctor: &Constructor<'tcx>) -> bool {
19372006
let ty = match ctor {
2007+
IntRange(_) => return true,
19382008
ConstantValue(value) => value.ty,
19392009
ConstantRange(lo, _, _) => lo.ty,
19402010
_ => return false,

0 commit comments

Comments
 (0)