Skip to content

Commit e48f4c6

Browse files
committed
Don't use IntRange for booleans
1 parent aaa1b64 commit e48f4c6

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

+56-14
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ pub(crate) struct IntRange {
112112
impl IntRange {
113113
#[inline]
114114
fn is_integral(ty: Ty<'_>) -> bool {
115-
matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool)
115+
matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_))
116116
}
117117

118118
fn is_singleton(&self) -> bool {
@@ -363,8 +363,8 @@ impl IntRange {
363363
}
364364
}
365365

366-
/// Note: this is often not what we want: e.g. `false` is converted into the range `0..=0` and
367-
/// would be displayed as such. To render properly, convert to a pattern first.
366+
/// Note: this will render signed ranges incorrectly. To render properly, convert to a pattern
367+
/// first.
368368
impl fmt::Debug for IntRange {
369369
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370370
let (lo, hi) = self.boundaries();
@@ -605,6 +605,8 @@ pub(super) enum Constructor<'tcx> {
605605
Single,
606606
/// Enum variants.
607607
Variant(VariantIdx),
608+
/// Booleans
609+
Bool(bool),
608610
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
609611
IntRange(IntRange),
610612
/// Ranges of floating-point literal values (`2.0..=5.2`).
@@ -645,6 +647,12 @@ impl<'tcx> Constructor<'tcx> {
645647
_ => None,
646648
}
647649
}
650+
fn as_bool(&self) -> Option<bool> {
651+
match self {
652+
Bool(b) => Some(*b),
653+
_ => None,
654+
}
655+
}
648656
fn as_int_range(&self) -> Option<&IntRange> {
649657
match self {
650658
IntRange(range) => Some(range),
@@ -689,10 +697,11 @@ impl<'tcx> Constructor<'tcx> {
689697
_ => bug!("Unexpected type for `Single` constructor: {:?}", pcx.ty),
690698
},
691699
Slice(slice) => slice.arity(),
692-
Str(..)
700+
Bool(..)
701+
| IntRange(..)
693702
| F32Range(..)
694703
| F64Range(..)
695-
| IntRange(..)
704+
| Str(..)
696705
| Opaque
697706
| NonExhaustive
698707
| Hidden
@@ -808,6 +817,7 @@ impl<'tcx> Constructor<'tcx> {
808817

809818
(Single, Single) => true,
810819
(Variant(self_id), Variant(other_id)) => self_id == other_id,
820+
(Bool(self_b), Bool(other_b)) => self_b == other_b,
811821

812822
(IntRange(self_range), IntRange(other_range)) => self_range.is_subrange(other_range),
813823
(F32Range(self_from, self_to, self_end), F32Range(other_from, other_to, other_end)) => {
@@ -860,9 +870,10 @@ pub(super) enum ConstructorSet {
860870
hidden_variants: Vec<VariantIdx>,
861871
non_exhaustive: bool,
862872
},
873+
/// Booleans.
874+
Bool,
863875
/// The type is spanned by integer values. The range or ranges give the set of allowed values.
864876
/// The second range is only useful for `char`.
865-
/// This is reused for bool. FIXME: don't.
866877
/// `non_exhaustive` is used when the range is not allowed to be matched exhaustively (that's
867878
/// for usize/isize).
868879
Integers { range_1: IntRange, range_2: Option<IntRange>, non_exhaustive: bool },
@@ -912,9 +923,7 @@ impl ConstructorSet {
912923
// Invariant: this is `Uninhabited` if and only if the type is uninhabited (as determined by
913924
// `cx.is_uninhabited()`).
914925
match ty.kind() {
915-
ty::Bool => {
916-
Self::Integers { range_1: make_range(0, 1), range_2: None, non_exhaustive: false }
917-
}
926+
ty::Bool => Self::Bool,
918927
ty::Char => {
919928
// The valid Unicode Scalar Value ranges.
920929
Self::Integers {
@@ -1074,6 +1083,27 @@ impl ConstructorSet {
10741083
missing.push(NonExhaustive);
10751084
}
10761085
}
1086+
ConstructorSet::Bool => {
1087+
let mut seen_false = false;
1088+
let mut seen_true = false;
1089+
for b in seen.map(|ctor| ctor.as_bool().unwrap()) {
1090+
if b {
1091+
seen_true = true;
1092+
} else {
1093+
seen_false = true;
1094+
}
1095+
}
1096+
if seen_false {
1097+
present.push(Bool(false));
1098+
} else {
1099+
missing.push(Bool(false));
1100+
}
1101+
if seen_true {
1102+
present.push(Bool(true));
1103+
} else {
1104+
missing.push(Bool(true));
1105+
}
1106+
}
10771107
ConstructorSet::Integers { range_1, range_2, non_exhaustive } => {
10781108
let seen_ranges: Vec<_> =
10791109
seen.map(|ctor| ctor.as_int_range().unwrap().clone()).collect();
@@ -1269,10 +1299,11 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12691299
}
12701300
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
12711301
},
1272-
Str(..)
1302+
Bool(..)
1303+
| IntRange(..)
12731304
| F32Range(..)
12741305
| F64Range(..)
1275-
| IntRange(..)
1306+
| Str(..)
12761307
| Opaque
12771308
| NonExhaustive
12781309
| Hidden
@@ -1400,7 +1431,14 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
14001431
}
14011432
PatKind::Constant { value } => {
14021433
match pat.ty.kind() {
1403-
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => {
1434+
ty::Bool => {
1435+
ctor = match value.try_eval_bool(cx.tcx, cx.param_env) {
1436+
Some(b) => Bool(b),
1437+
None => Opaque,
1438+
};
1439+
fields = Fields::empty();
1440+
}
1441+
ty::Char | ty::Int(_) | ty::Uint(_) => {
14041442
ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
14051443
Some(bits) => IntRange(IntRange::from_bits(cx.tcx, pat.ty, bits)),
14061444
None => Opaque,
@@ -1679,9 +1717,11 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
16791717
}
16801718
write!(f, "]")
16811719
}
1720+
Bool(b) => write!(f, "{b}"),
1721+
// Best-effort, will render signed ranges incorrectly
1722+
IntRange(range) => write!(f, "{range:?}"),
16821723
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
16831724
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
1684-
IntRange(range) => write!(f, "{range:?}"), // Best-effort, will render e.g. `false` as `0..=0`
16851725
Str(value) => write!(f, "{value}"),
16861726
Opaque => write!(f, "<constant pattern>"),
16871727
Or => {
@@ -1731,10 +1771,13 @@ impl<'tcx> WitnessPat<'tcx> {
17311771
self.ty
17321772
}
17331773

1774+
/// Convert back to a `thir::Pat` for diagnostic purposes.
17341775
pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'_, 'tcx>) -> Pat<'tcx> {
17351776
let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild);
17361777
let mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx)));
17371778
let kind = match &self.ctor {
1779+
Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) },
1780+
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
17381781
Single | Variant(_) => match self.ty.kind() {
17391782
ty::Tuple(..) => PatKind::Leaf {
17401783
subpatterns: subpatterns
@@ -1804,7 +1847,6 @@ impl<'tcx> WitnessPat<'tcx> {
18041847
}
18051848
}
18061849
&Str(value) => PatKind::Constant { value },
1807-
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
18081850
Wildcard | NonExhaustive | Hidden => PatKind::Wild,
18091851
Missing { .. } => bug!(
18101852
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,

0 commit comments

Comments
 (0)