Don't use IntRange
for booleans
This commit is contained in:
parent
0ba6c4ab67
commit
a5c67f4107
1 changed files with 56 additions and 14 deletions
|
@ -110,7 +110,7 @@ pub(crate) struct IntRange {
|
||||||
impl IntRange {
|
impl IntRange {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn is_integral(ty: Ty<'_>) -> bool {
|
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 {
|
pub(super) fn is_singleton(&self) -> bool {
|
||||||
|
@ -299,8 +299,8 @@ impl IntRange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Note: this is often not what we want: e.g. `false` is converted into the range `0..=0` and
|
/// Note: this will render signed ranges incorrectly. To render properly, convert to a pattern
|
||||||
/// would be displayed as such. To render properly, convert to a pattern first.
|
/// first.
|
||||||
impl fmt::Debug for IntRange {
|
impl fmt::Debug for IntRange {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let (lo, hi) = self.boundaries();
|
let (lo, hi) = self.boundaries();
|
||||||
|
@ -541,6 +541,8 @@ pub(super) enum Constructor<'tcx> {
|
||||||
Single,
|
Single,
|
||||||
/// Enum variants.
|
/// Enum variants.
|
||||||
Variant(VariantIdx),
|
Variant(VariantIdx),
|
||||||
|
/// Booleans
|
||||||
|
Bool(bool),
|
||||||
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
|
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
|
||||||
IntRange(IntRange),
|
IntRange(IntRange),
|
||||||
/// Ranges of floating-point literal values (`2.0..=5.2`).
|
/// Ranges of floating-point literal values (`2.0..=5.2`).
|
||||||
|
@ -581,6 +583,12 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn as_bool(&self) -> Option<bool> {
|
||||||
|
match self {
|
||||||
|
Bool(b) => Some(*b),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub(super) fn as_int_range(&self) -> Option<&IntRange> {
|
pub(super) fn as_int_range(&self) -> Option<&IntRange> {
|
||||||
match self {
|
match self {
|
||||||
IntRange(range) => Some(range),
|
IntRange(range) => Some(range),
|
||||||
|
@ -625,10 +633,11 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
_ => bug!("Unexpected type for `Single` constructor: {:?}", pcx.ty),
|
_ => bug!("Unexpected type for `Single` constructor: {:?}", pcx.ty),
|
||||||
},
|
},
|
||||||
Slice(slice) => slice.arity(),
|
Slice(slice) => slice.arity(),
|
||||||
Str(..)
|
Bool(..)
|
||||||
|
| IntRange(..)
|
||||||
| F32Range(..)
|
| F32Range(..)
|
||||||
| F64Range(..)
|
| F64Range(..)
|
||||||
| IntRange(..)
|
| Str(..)
|
||||||
| Opaque
|
| Opaque
|
||||||
| NonExhaustive
|
| NonExhaustive
|
||||||
| Hidden
|
| Hidden
|
||||||
|
@ -744,6 +753,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
|
|
||||||
(Single, Single) => true,
|
(Single, Single) => true,
|
||||||
(Variant(self_id), Variant(other_id)) => self_id == other_id,
|
(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),
|
(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)) => {
|
(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>,
|
hidden_variants: Vec<VariantIdx>,
|
||||||
non_exhaustive: bool,
|
non_exhaustive: bool,
|
||||||
},
|
},
|
||||||
|
/// Booleans.
|
||||||
|
Bool,
|
||||||
/// The type is spanned by integer values. The range or ranges give the set of allowed values.
|
/// 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`.
|
/// 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
|
/// `non_exhaustive` is used when the range is not allowed to be matched exhaustively (that's
|
||||||
/// for usize/isize).
|
/// for usize/isize).
|
||||||
Integers { range_1: IntRange, range_2: Option<IntRange>, non_exhaustive: bool },
|
Integers { range_1: IntRange, range_2: Option<IntRange>, non_exhaustive: bool },
|
||||||
|
@ -848,9 +859,7 @@ impl ConstructorSet {
|
||||||
// Invariant: this is `Uninhabited` if and only if the type is uninhabited (as determined by
|
// Invariant: this is `Uninhabited` if and only if the type is uninhabited (as determined by
|
||||||
// `cx.is_uninhabited()`).
|
// `cx.is_uninhabited()`).
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Bool => {
|
ty::Bool => Self::Bool,
|
||||||
Self::Integers { range_1: make_range(0, 1), range_2: None, non_exhaustive: false }
|
|
||||||
}
|
|
||||||
ty::Char => {
|
ty::Char => {
|
||||||
// The valid Unicode Scalar Value ranges.
|
// The valid Unicode Scalar Value ranges.
|
||||||
Self::Integers {
|
Self::Integers {
|
||||||
|
@ -1010,6 +1019,27 @@ impl ConstructorSet {
|
||||||
missing.push(NonExhaustive);
|
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 } => {
|
ConstructorSet::Integers { range_1, range_2, non_exhaustive } => {
|
||||||
let seen_ranges: Vec<_> =
|
let seen_ranges: Vec<_> =
|
||||||
seen.map(|ctor| ctor.as_int_range().unwrap().clone()).collect();
|
seen.map(|ctor| ctor.as_int_range().unwrap().clone()).collect();
|
||||||
|
@ -1205,10 +1235,11 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
|
||||||
}
|
}
|
||||||
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
|
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
|
||||||
},
|
},
|
||||||
Str(..)
|
Bool(..)
|
||||||
|
| IntRange(..)
|
||||||
| F32Range(..)
|
| F32Range(..)
|
||||||
| F64Range(..)
|
| F64Range(..)
|
||||||
| IntRange(..)
|
| Str(..)
|
||||||
| Opaque
|
| Opaque
|
||||||
| NonExhaustive
|
| NonExhaustive
|
||||||
| Hidden
|
| Hidden
|
||||||
|
@ -1337,7 +1368,14 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
|
||||||
}
|
}
|
||||||
PatKind::Constant { value } => {
|
PatKind::Constant { value } => {
|
||||||
match pat.ty.kind() {
|
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) {
|
ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
|
||||||
Some(bits) => IntRange(IntRange::from_bits(cx.tcx, pat.ty, bits)),
|
Some(bits) => IntRange(IntRange::from_bits(cx.tcx, pat.ty, bits)),
|
||||||
None => Opaque,
|
None => Opaque,
|
||||||
|
@ -1616,9 +1654,11 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
|
||||||
}
|
}
|
||||||
write!(f, "]")
|
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}"),
|
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
||||||
F64Range(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}"),
|
Str(value) => write!(f, "{value}"),
|
||||||
Opaque => write!(f, "<constant pattern>"),
|
Opaque => write!(f, "<constant pattern>"),
|
||||||
Or => {
|
Or => {
|
||||||
|
@ -1668,10 +1708,13 @@ impl<'tcx> WitnessPat<'tcx> {
|
||||||
self.ty
|
self.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert back to a `thir::Pat` for diagnostic purposes.
|
||||||
pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'_, 'tcx>) -> Pat<'tcx> {
|
pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'_, 'tcx>) -> Pat<'tcx> {
|
||||||
let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild);
|
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 mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx)));
|
||||||
let kind = match &self.ctor {
|
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() {
|
Single | Variant(_) => match self.ty.kind() {
|
||||||
ty::Tuple(..) => PatKind::Leaf {
|
ty::Tuple(..) => PatKind::Leaf {
|
||||||
subpatterns: subpatterns
|
subpatterns: subpatterns
|
||||||
|
@ -1741,7 +1784,6 @@ impl<'tcx> WitnessPat<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Str(value) => PatKind::Constant { value },
|
&Str(value) => PatKind::Constant { value },
|
||||||
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
|
|
||||||
Wildcard | NonExhaustive | Hidden => PatKind::Wild,
|
Wildcard | NonExhaustive | Hidden => PatKind::Wild,
|
||||||
Missing { .. } => bug!(
|
Missing { .. } => bug!(
|
||||||
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
|
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue