Inline RangeInclusive into IntRange

This commit is contained in:
Nadrieril 2023-10-12 16:19:02 +02:00
parent a5c67f4107
commit 9bc4c378ab
2 changed files with 33 additions and 41 deletions

View File

@ -46,7 +46,6 @@
use std::cmp::{self, max, min, Ordering};
use std::fmt;
use std::iter::once;
use std::ops::RangeInclusive;
use smallvec::{smallvec, SmallVec};
@ -102,9 +101,10 @@ enum Presence {
///
/// `IntRange` is never used to encode an empty range or a "range" that wraps
/// around the (offset) space: i.e., `range.lo <= range.hi`.
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub(crate) struct IntRange {
range: RangeInclusive<u128>,
pub(crate) lo: u128,
pub(crate) hi: u128,
}
impl IntRange {
@ -114,20 +114,16 @@ pub(super) fn is_integral(ty: Ty<'_>) -> bool {
}
pub(super) fn is_singleton(&self) -> bool {
self.range.start() == self.range.end()
}
pub(super) fn boundaries(&self) -> (u128, u128) {
(*self.range.start(), *self.range.end())
self.lo == self.hi
}
#[inline]
fn from_bits<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, bits: u128) -> IntRange {
let bias = IntRange::signed_bias(tcx, ty);
// Perform a shift if the underlying types are signed,
// which makes the interval arithmetic simpler.
// Perform a shift if the underlying types are signed, which makes the interval arithmetic
// type-independent.
let val = bits ^ bias;
IntRange { range: val..=val }
IntRange { lo: val, hi: val }
}
#[inline]
@ -138,16 +134,17 @@ fn from_range<'tcx>(
ty: Ty<'tcx>,
end: RangeEnd,
) -> IntRange {
// Perform a shift if the underlying types are signed,
// which makes the interval arithmetic simpler.
// Perform a shift if the underlying types are signed, which makes the interval arithmetic
// type-independent.
let bias = IntRange::signed_bias(tcx, ty);
let (lo, hi) = (lo ^ bias, hi ^ bias);
let offset = (end == RangeEnd::Excluded) as u128;
if lo > hi || (lo == hi && end == RangeEnd::Excluded) {
let hi = hi - offset;
if lo > hi {
// This should have been caught earlier by E0030.
bug!("malformed range pattern: {}..={}", lo, (hi - offset));
bug!("malformed range pattern: {lo}..={hi}");
}
IntRange { range: lo..=(hi - offset) }
IntRange { lo, hi }
}
// The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
@ -162,14 +159,12 @@ fn signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> u128 {
}
fn is_subrange(&self, other: &Self) -> bool {
other.range.start() <= self.range.start() && self.range.end() <= other.range.end()
other.lo <= self.lo && self.hi <= other.hi
}
fn intersection(&self, other: &Self) -> Option<Self> {
let (lo, hi) = self.boundaries();
let (other_lo, other_hi) = other.boundaries();
if lo <= other_hi && other_lo <= hi {
Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi) })
if self.lo <= other.hi && other.lo <= self.hi {
Some(IntRange { lo: max(self.lo, other.lo), hi: min(self.hi, other.hi) })
} else {
None
}
@ -216,9 +211,8 @@ enum IntBoundary {
fn unpack_intrange(range: IntRange) -> [IntBoundary; 2] {
use IntBoundary::*;
let (lo, hi) = range.boundaries();
let lo = JustBefore(lo);
let hi = match hi.checked_add(1) {
let lo = JustBefore(range.lo);
let hi = match range.hi.checked_add(1) {
Some(m) => JustBefore(m),
None => AfterMax,
};
@ -264,21 +258,19 @@ enum IntBoundary {
use IntBoundary::*;
use Presence::*;
let presence = if paren_count > 0 { Seen } else { Unseen };
let range = match (prev_bdy, bdy) {
(JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1),
(JustBefore(n), AfterMax) => n..=u128::MAX,
let (lo, hi) = match (prev_bdy, bdy) {
(JustBefore(n), JustBefore(m)) if n < m => (n, m - 1),
(JustBefore(n), AfterMax) => (n, u128::MAX),
_ => unreachable!(), // Ruled out by the sorting and filtering we did
};
(presence, IntRange { range })
(presence, IntRange { lo, hi })
})
}
/// Only used for displaying the range.
pub(super) fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
let (lo, hi) = self.boundaries();
let bias = IntRange::signed_bias(tcx, ty);
let (lo_bits, hi_bits) = (lo ^ bias, hi ^ bias);
let (lo_bits, hi_bits) = (self.lo ^ bias, self.hi ^ bias);
let env = ty::ParamEnv::empty().and(ty);
let lo_const = mir::Const::from_bits(tcx, lo_bits, env);
@ -303,7 +295,7 @@ pub(super) fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx>
/// first.
impl fmt::Debug for IntRange {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (lo, hi) = self.boundaries();
let (lo, hi) = (self.lo, self.hi);
write!(f, "{lo}")?;
write!(f, "{}", RangeEnd::Included)?;
write!(f, "{hi}")

View File

@ -1031,9 +1031,10 @@ fn lint_overlapping_range_endpoints<'p, 'tcx>(
let split_int_ranges = set.present.iter().filter_map(|c| c.as_int_range());
for overlap_range in split_int_ranges.clone() {
if overlap_range.is_singleton() {
let overlap: u128 = overlap_range.boundaries().0;
// Spans of ranges that start or end with the overlap.
let overlap: u128 = overlap_range.lo;
// Ranges that look like `lo..=overlap`.
let mut prefixes: SmallVec<[_; 1]> = Default::default();
// Ranges that look like `overlap..=hi`.
let mut suffixes: SmallVec<[_; 1]> = Default::default();
// Iterate on patterns that contained `overlap`.
for pat in column.iter() {
@ -1043,17 +1044,16 @@ fn lint_overlapping_range_endpoints<'p, 'tcx>(
// Don't lint when one of the ranges is a singleton.
continue;
}
let (start, end) = this_range.boundaries();
if start == overlap {
// `this_range` looks like `overlap..=end`; it overlaps with any ranges that
// look like `start..=overlap`.
if this_range.lo == overlap {
// `this_range` looks like `overlap..=this_range.hi`; it overlaps with any
// ranges that look like `lo..=overlap`.
if !prefixes.is_empty() {
emit_lint(overlap_range, this_span, &prefixes);
}
suffixes.push(this_span)
} else if end == overlap {
// `this_range` looks like `start..=overlap`; it overlaps with any ranges
// that look like `overlap..=end`.
} else if this_range.hi == overlap {
// `this_range` looks like `this_range.lo..=overlap`; it overlaps with any
// ranges that look like `overlap..=hi`.
if !suffixes.is_empty() {
emit_lint(overlap_range, this_span, &suffixes);
}