shrink TestBranch::Constant and PatRangeBoundary::Finite
This commit is contained in:
parent
a1acbfb050
commit
dbc030e034
5 changed files with 23 additions and 17 deletions
|
|
@ -959,9 +959,9 @@ impl<'tcx> PatRange<'tcx> {
|
|||
#[inline]
|
||||
pub fn contains(&self, value: ty::Value<'tcx>, tcx: TyCtxt<'tcx>) -> Option<bool> {
|
||||
use Ordering::*;
|
||||
debug_assert_eq!(self.ty, value.ty);
|
||||
debug_assert_eq!(value.ty, self.ty);
|
||||
let ty = self.ty;
|
||||
let value = PatRangeBoundary::Finite(value);
|
||||
let value = PatRangeBoundary::Finite(value.valtree);
|
||||
// For performance, it's important to only do the second comparison if necessary.
|
||||
Some(
|
||||
match self.lo.compare_with(value, ty, tcx)? {
|
||||
|
|
@ -996,11 +996,13 @@ impl<'tcx> PatRange<'tcx> {
|
|||
|
||||
impl<'tcx> fmt::Display for PatRange<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let PatRangeBoundary::Finite(value) = &self.lo {
|
||||
if let &PatRangeBoundary::Finite(valtree) = &self.lo {
|
||||
let value = ty::Value { ty: self.ty, valtree };
|
||||
write!(f, "{value}")?;
|
||||
}
|
||||
if let PatRangeBoundary::Finite(value) = &self.hi {
|
||||
if let &PatRangeBoundary::Finite(valtree) = &self.hi {
|
||||
write!(f, "{}", self.end)?;
|
||||
let value = ty::Value { ty: self.ty, valtree };
|
||||
write!(f, "{value}")?;
|
||||
} else {
|
||||
// `0..` is parsed as an inclusive range, we must display it correctly.
|
||||
|
|
@ -1014,7 +1016,8 @@ impl<'tcx> fmt::Display for PatRange<'tcx> {
|
|||
/// If present, the const must be of a numeric type.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, HashStable, TypeVisitable)]
|
||||
pub enum PatRangeBoundary<'tcx> {
|
||||
Finite(ty::Value<'tcx>),
|
||||
/// The type of this valtree is stored in the surrounding `PatRange`.
|
||||
Finite(ty::ValTree<'tcx>),
|
||||
NegInfinity,
|
||||
PosInfinity,
|
||||
}
|
||||
|
|
@ -1025,7 +1028,7 @@ impl<'tcx> PatRangeBoundary<'tcx> {
|
|||
matches!(self, Self::Finite(..))
|
||||
}
|
||||
#[inline]
|
||||
pub fn as_finite(self) -> Option<ty::Value<'tcx>> {
|
||||
pub fn as_finite(self) -> Option<ty::ValTree<'tcx>> {
|
||||
match self {
|
||||
Self::Finite(value) => Some(value),
|
||||
Self::NegInfinity | Self::PosInfinity => None,
|
||||
|
|
|
|||
|
|
@ -1357,8 +1357,8 @@ pub(crate) struct Test<'tcx> {
|
|||
enum TestBranch<'tcx> {
|
||||
/// Success branch, used for tests with two possible outcomes.
|
||||
Success,
|
||||
/// Branch corresponding to this constant.
|
||||
Constant(ty::Value<'tcx>, u128),
|
||||
/// Branch corresponding to this constant. Must be a scalar.
|
||||
Constant(ty::Value<'tcx>),
|
||||
/// Branch corresponding to this variant.
|
||||
Variant(VariantIdx),
|
||||
/// Failure branch for tests with two possible outcomes, and "otherwise" branch for other tests.
|
||||
|
|
@ -1367,7 +1367,7 @@ enum TestBranch<'tcx> {
|
|||
|
||||
impl<'tcx> TestBranch<'tcx> {
|
||||
fn as_constant(&self) -> Option<ty::Value<'tcx>> {
|
||||
if let Self::Constant(v, _) = self { Some(*v) } else { None }
|
||||
if let Self::Constant(v) = self { Some(*v) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let otherwise_block = target_block(TestBranch::Failure);
|
||||
let switch_targets = SwitchTargets::new(
|
||||
target_blocks.iter().filter_map(|(&branch, &block)| {
|
||||
if let TestBranch::Constant(_, bits) = branch {
|
||||
if let TestBranch::Constant(value) = branch {
|
||||
let bits = value.try_to_scalar_int().unwrap().to_bits_unchecked();
|
||||
Some((bits, block))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -279,6 +280,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
};
|
||||
|
||||
if let Some(lo) = range.lo.as_finite() {
|
||||
let lo = ty::Value { ty: range.ty, valtree: lo };
|
||||
let lo = self.literal_operand(test.span, Const::from_ty_value(self.tcx, lo));
|
||||
self.compare(
|
||||
block,
|
||||
|
|
@ -292,6 +294,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
};
|
||||
|
||||
if let Some(hi) = range.hi.as_finite() {
|
||||
let hi = ty::Value { ty: range.ty, valtree: hi };
|
||||
let hi = self.literal_operand(test.span, Const::from_ty_value(self.tcx, hi));
|
||||
let op = match range.end {
|
||||
RangeEnd::Included => BinOp::Le,
|
||||
|
|
@ -575,8 +578,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
None
|
||||
} else {
|
||||
fully_matched = true;
|
||||
let bits = value.try_to_scalar_int().unwrap().to_bits_unchecked();
|
||||
Some(TestBranch::Constant(value, bits))
|
||||
Some(TestBranch::Constant(value))
|
||||
}
|
||||
}
|
||||
(TestKind::SwitchInt, TestCase::Range(range)) => {
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
format!("found bad range pattern endpoint `{expr:?}` outside of error recovery");
|
||||
return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
|
||||
};
|
||||
Ok(Some(PatRangeBoundary::Finite(value)))
|
||||
Ok(Some(PatRangeBoundary::Finite(value.valtree)))
|
||||
}
|
||||
|
||||
/// Overflowing literals are linted against in a late pass. This is mostly fine, except when we
|
||||
|
|
@ -243,7 +243,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
(RangeEnd::Included, Some(Ordering::Less)) => {}
|
||||
// `x..=y` where `x == y` and `x` and `y` are finite.
|
||||
(RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => {
|
||||
kind = PatKind::Constant { value: lo.as_finite().unwrap() };
|
||||
let value = ty::Value { ty, valtree: lo.as_finite().unwrap() };
|
||||
kind = PatKind::Constant { value };
|
||||
}
|
||||
// `..=x` where `x == ty::MIN`.
|
||||
(RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {}
|
||||
|
|
|
|||
|
|
@ -722,7 +722,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
|||
match ScalarInt::try_from_uint(bits, size) {
|
||||
Some(scalar) => {
|
||||
let valtree = ty::ValTree::from_scalar_int(tcx, scalar);
|
||||
PatRangeBoundary::Finite(ty::Value { ty: ty.inner(), valtree })
|
||||
PatRangeBoundary::Finite(valtree)
|
||||
}
|
||||
// The value doesn't fit. Since `x >= 0` and 0 always encodes the minimum value
|
||||
// for a type, the problem isn't that the value is too small. So it must be too
|
||||
|
|
@ -742,7 +742,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
|||
"_".to_string()
|
||||
} else if range.is_singleton() {
|
||||
let lo = cx.hoist_pat_range_bdy(range.lo, ty);
|
||||
let value = lo.as_finite().unwrap();
|
||||
let value = ty::Value { ty: ty.inner(), valtree: lo.as_finite().unwrap() };
|
||||
value.to_string()
|
||||
} else {
|
||||
// We convert to an inclusive range for diagnostics.
|
||||
|
|
@ -756,7 +756,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
|||
// probably clear enough.
|
||||
let max = ty.numeric_max_val(cx.tcx).unwrap();
|
||||
let max = ty::ValTree::from_scalar_int(cx.tcx, max.try_to_scalar_int().unwrap());
|
||||
lo = PatRangeBoundary::Finite(ty::Value { ty: ty.inner(), valtree: max });
|
||||
lo = PatRangeBoundary::Finite(max);
|
||||
}
|
||||
let hi = if let Some(hi) = range.hi.minus_one() {
|
||||
hi
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue