Skip to content

Commit a5c67f4

Browse files
committed
Don't use IntRange for booleans
1 parent 0ba6c4a commit a5c67f4

File tree

1 file changed

+56
-14
lines changed

1 file changed

+56
-14
lines changed

compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ pub(crate) struct IntRange {
110110
impl IntRange {
111111
#[inline]
112112
pub(super) fn is_integral(ty: Ty<'_>) -> bool {
113-
matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool)
113+
matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_))
114114
}
115115

116116
pub(super) fn is_singleton(&self) -> bool {
@@ -299,8 +299,8 @@ impl IntRange {
299299
}
300300
}
301301

302-
/// Note: this is often not what we want: e.g. `false` is converted into the range `0..=0` and
303-
/// would be displayed as such. To render properly, convert to a pattern first.
302+
/// Note: this will render signed ranges incorrectly. To render properly, convert to a pattern
303+
/// first.
304304
impl fmt::Debug for IntRange {
305305
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306306
let (lo, hi) = self.boundaries();
@@ -541,6 +541,8 @@ pub(super) enum Constructor<'tcx> {
541541
Single,
542542
/// Enum variants.
543543
Variant(VariantIdx),
544+
/// Booleans
545+
Bool(bool),
544546
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
545547
IntRange(IntRange),
546548
/// Ranges of floating-point literal values (`2.0..=5.2`).
@@ -581,6 +583,12 @@ impl<'tcx> Constructor<'tcx> {
581583
_ => None,
582584
}
583585
}
586+
fn as_bool(&self) -> Option<bool> {
587+
match self {
588+
Bool(b) => Some(*b),
589+
_ => None,
590+
}
591+
}
584592
pub(super) fn as_int_range(&self) -> Option<&IntRange> {
585593
match self {
586594
IntRange(range) => Some(range),
@@ -625,10 +633,11 @@ impl<'tcx> Constructor<'tcx> {
625633
_ => bug!("Unexpected type for `Single` constructor: {:?}", pcx.ty),
626634
},
627635
Slice(slice) => slice.arity(),
628-
Str(..)
636+
Bool(..)
637+
| IntRange(..)
629638
| F32Range(..)
630639
| F64Range(..)
631-
| IntRange(..)
640+
| Str(..)
632641
| Opaque
633642
| NonExhaustive
634643
| Hidden
@@ -744,6 +753,7 @@ impl<'tcx> Constructor<'tcx> {
744753

745754
(Single, Single) => true,
746755
(Variant(self_id), Variant(other_id)) => self_id == other_id,
756+
(Bool(self_b), Bool(other_b)) => self_b == other_b,
747757

748758
(IntRange(self_range), IntRange(other_range)) => self_range.is_subrange(other_range),
749759
(F32Range(self_from, self_to, self_end), F32Range(other_from, other_to, other_end)) => {
@@ -796,9 +806,10 @@ pub(super) enum ConstructorSet {
796806
hidden_variants: Vec<VariantIdx>,
797807
non_exhaustive: bool,
798808
},
809+
/// Booleans.
810+
Bool,
799811
/// The type is spanned by integer values. The range or ranges give the set of allowed values.
800812
/// The second range is only useful for `char`.
801-
/// This is reused for bool. FIXME: don't.
802813
/// `non_exhaustive` is used when the range is not allowed to be matched exhaustively (that's
803814
/// for usize/isize).
804815
Integers { range_1: IntRange, range_2: Option<IntRange>, non_exhaustive: bool },
@@ -848,9 +859,7 @@ impl ConstructorSet {
848859
// Invariant: this is `Uninhabited` if and only if the type is uninhabited (as determined by
849860
// `cx.is_uninhabited()`).
850861
match ty.kind() {
851-
ty::Bool => {
852-
Self::Integers { range_1: make_range(0, 1), range_2: None, non_exhaustive: false }
853-
}
862+
ty::Bool => Self::Bool,
854863
ty::Char => {
855864
// The valid Unicode Scalar Value ranges.
856865
Self::Integers {
@@ -1010,6 +1019,27 @@ impl ConstructorSet {
10101019
missing.push(NonExhaustive);
10111020
}
10121021
}
1022+
ConstructorSet::Bool => {
1023+
let mut seen_false = false;
1024+
let mut seen_true = false;
1025+
for b in seen.map(|ctor| ctor.as_bool().unwrap()) {
1026+
if b {
1027+
seen_true = true;
1028+
} else {
1029+
seen_false = true;
1030+
}
1031+
}
1032+
if seen_false {
1033+
present.push(Bool(false));
1034+
} else {
1035+
missing.push(Bool(false));
1036+
}
1037+
if seen_true {
1038+
present.push(Bool(true));
1039+
} else {
1040+
missing.push(Bool(true));
1041+
}
1042+
}
10131043
ConstructorSet::Integers { range_1, range_2, non_exhaustive } => {
10141044
let seen_ranges: Vec<_> =
10151045
seen.map(|ctor| ctor.as_int_range().unwrap().clone()).collect();
@@ -1205,10 +1235,11 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12051235
}
12061236
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
12071237
},
1208-
Str(..)
1238+
Bool(..)
1239+
| IntRange(..)
12091240
| F32Range(..)
12101241
| F64Range(..)
1211-
| IntRange(..)
1242+
| Str(..)
12121243
| Opaque
12131244
| NonExhaustive
12141245
| Hidden
@@ -1337,7 +1368,14 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
13371368
}
13381369
PatKind::Constant { value } => {
13391370
match pat.ty.kind() {
1340-
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => {
1371+
ty::Bool => {
1372+
ctor = match value.try_eval_bool(cx.tcx, cx.param_env) {
1373+
Some(b) => Bool(b),
1374+
None => Opaque,
1375+
};
1376+
fields = Fields::empty();
1377+
}
1378+
ty::Char | ty::Int(_) | ty::Uint(_) => {
13411379
ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
13421380
Some(bits) => IntRange(IntRange::from_bits(cx.tcx, pat.ty, bits)),
13431381
None => Opaque,
@@ -1616,9 +1654,11 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
16161654
}
16171655
write!(f, "]")
16181656
}
1657+
Bool(b) => write!(f, "{b}"),
1658+
// Best-effort, will render signed ranges incorrectly
1659+
IntRange(range) => write!(f, "{range:?}"),
16191660
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
16201661
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
1621-
IntRange(range) => write!(f, "{range:?}"), // Best-effort, will render e.g. `false` as `0..=0`
16221662
Str(value) => write!(f, "{value}"),
16231663
Opaque => write!(f, "<constant pattern>"),
16241664
Or => {
@@ -1668,10 +1708,13 @@ impl<'tcx> WitnessPat<'tcx> {
16681708
self.ty
16691709
}
16701710

1711+
/// Convert back to a `thir::Pat` for diagnostic purposes.
16711712
pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'_, 'tcx>) -> Pat<'tcx> {
16721713
let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild);
16731714
let mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx)));
16741715
let kind = match &self.ctor {
1716+
Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) },
1717+
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
16751718
Single | Variant(_) => match self.ty.kind() {
16761719
ty::Tuple(..) => PatKind::Leaf {
16771720
subpatterns: subpatterns
@@ -1741,7 +1784,6 @@ impl<'tcx> WitnessPat<'tcx> {
17411784
}
17421785
}
17431786
&Str(value) => PatKind::Constant { value },
1744-
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
17451787
Wildcard | NonExhaustive | Hidden => PatKind::Wild,
17461788
Missing { .. } => bug!(
17471789
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,

0 commit comments

Comments
 (0)