shrink TestBranch::Constant and PatRangeBoundary::Finite

This commit is contained in:
Ralf Jung 2025-07-29 13:28:47 +02:00
parent a1acbfb050
commit dbc030e034
5 changed files with 23 additions and 17 deletions

View file

@ -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,

View file

@ -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 }
}
}

View file

@ -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)) => {

View file

@ -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() => {}

View file

@ -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