Don't use IntRange for booleans

This commit is contained in:
Nadrieril 2023-10-12 16:51:27 +02:00
parent 0ba6c4ab67
commit a5c67f4107

View File

@ -110,7 +110,7 @@ pub(crate) struct IntRange {
impl IntRange {
#[inline]
pub(super) fn is_integral(ty: Ty<'_>) -> bool {
matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool)
matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_))
}
pub(super) fn is_singleton(&self) -> bool {
@ -299,8 +299,8 @@ pub(super) fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx>
}
}
/// Note: this is often not what we want: e.g. `false` is converted into the range `0..=0` and
/// would be displayed as such. To render properly, convert to a pattern first.
/// Note: this will render signed ranges incorrectly. To render properly, convert to a pattern
/// first.
impl fmt::Debug for IntRange {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (lo, hi) = self.boundaries();
@ -541,6 +541,8 @@ pub(super) enum Constructor<'tcx> {
Single,
/// Enum variants.
Variant(VariantIdx),
/// Booleans
Bool(bool),
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
IntRange(IntRange),
/// Ranges of floating-point literal values (`2.0..=5.2`).
@ -581,6 +583,12 @@ pub(super) fn as_variant(&self) -> Option<VariantIdx> {
_ => None,
}
}
fn as_bool(&self) -> Option<bool> {
match self {
Bool(b) => Some(*b),
_ => None,
}
}
pub(super) fn as_int_range(&self) -> Option<&IntRange> {
match self {
IntRange(range) => Some(range),
@ -625,10 +633,11 @@ pub(super) fn arity(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> usize {
_ => bug!("Unexpected type for `Single` constructor: {:?}", pcx.ty),
},
Slice(slice) => slice.arity(),
Str(..)
Bool(..)
| IntRange(..)
| F32Range(..)
| F64Range(..)
| IntRange(..)
| Str(..)
| Opaque
| NonExhaustive
| Hidden
@ -744,6 +753,7 @@ pub(super) fn is_covered_by<'p>(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, other: &Self
(Single, Single) => true,
(Variant(self_id), Variant(other_id)) => self_id == other_id,
(Bool(self_b), Bool(other_b)) => self_b == other_b,
(IntRange(self_range), IntRange(other_range)) => self_range.is_subrange(other_range),
(F32Range(self_from, self_to, self_end), F32Range(other_from, other_to, other_end)) => {
@ -796,9 +806,10 @@ pub(super) enum ConstructorSet {
hidden_variants: Vec<VariantIdx>,
non_exhaustive: bool,
},
/// Booleans.
Bool,
/// The type is spanned by integer values. The range or ranges give the set of allowed values.
/// The second range is only useful for `char`.
/// This is reused for bool. FIXME: don't.
/// `non_exhaustive` is used when the range is not allowed to be matched exhaustively (that's
/// for usize/isize).
Integers { range_1: IntRange, range_2: Option<IntRange>, non_exhaustive: bool },
@ -848,9 +859,7 @@ pub(super) fn for_ty<'p, 'tcx>(cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>) -> S
// Invariant: this is `Uninhabited` if and only if the type is uninhabited (as determined by
// `cx.is_uninhabited()`).
match ty.kind() {
ty::Bool => {
Self::Integers { range_1: make_range(0, 1), range_2: None, non_exhaustive: false }
}
ty::Bool => Self::Bool,
ty::Char => {
// The valid Unicode Scalar Value ranges.
Self::Integers {
@ -1010,6 +1019,27 @@ pub(super) fn split<'a, 'tcx>(
missing.push(NonExhaustive);
}
}
ConstructorSet::Bool => {
let mut seen_false = false;
let mut seen_true = false;
for b in seen.map(|ctor| ctor.as_bool().unwrap()) {
if b {
seen_true = true;
} else {
seen_false = true;
}
}
if seen_false {
present.push(Bool(false));
} else {
missing.push(Bool(false));
}
if seen_true {
present.push(Bool(true));
} else {
missing.push(Bool(true));
}
}
ConstructorSet::Integers { range_1, range_2, non_exhaustive } => {
let seen_ranges: Vec<_> =
seen.map(|ctor| ctor.as_int_range().unwrap().clone()).collect();
@ -1205,10 +1235,11 @@ pub(super) fn wildcards(pcx: &PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'
}
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
},
Str(..)
Bool(..)
| IntRange(..)
| F32Range(..)
| F64Range(..)
| IntRange(..)
| Str(..)
| Opaque
| NonExhaustive
| Hidden
@ -1337,7 +1368,14 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
}
PatKind::Constant { value } => {
match pat.ty.kind() {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => {
ty::Bool => {
ctor = match value.try_eval_bool(cx.tcx, cx.param_env) {
Some(b) => Bool(b),
None => Opaque,
};
fields = Fields::empty();
}
ty::Char | ty::Int(_) | ty::Uint(_) => {
ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
Some(bits) => IntRange(IntRange::from_bits(cx.tcx, pat.ty, bits)),
None => Opaque,
@ -1616,9 +1654,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
write!(f, "]")
}
Bool(b) => write!(f, "{b}"),
// Best-effort, will render signed ranges incorrectly
IntRange(range) => write!(f, "{range:?}"),
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
IntRange(range) => write!(f, "{range:?}"), // Best-effort, will render e.g. `false` as `0..=0`
Str(value) => write!(f, "{value}"),
Opaque => write!(f, "<constant pattern>"),
Or => {
@ -1668,10 +1708,13 @@ pub(super) fn ty(&self) -> Ty<'tcx> {
self.ty
}
/// Convert back to a `thir::Pat` for diagnostic purposes.
pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'_, 'tcx>) -> Pat<'tcx> {
let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild);
let mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx)));
let kind = match &self.ctor {
Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) },
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
Single | Variant(_) => match self.ty.kind() {
ty::Tuple(..) => PatKind::Leaf {
subpatterns: subpatterns
@ -1741,7 +1784,6 @@ pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'_, 'tcx>) -> Pat<'tcx> {
}
}
&Str(value) => PatKind::Constant { value },
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
Wildcard | NonExhaustive | Hidden => PatKind::Wild,
Missing { .. } => bug!(
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,