Propagate half-open ranges through exhaustiveness checking
This commit is contained in:
parent
9bc4c378ab
commit
6f35ae6f9b
@ -63,6 +63,7 @@
|
|||||||
use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
|
use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
|
||||||
|
|
||||||
use self::Constructor::*;
|
use self::Constructor::*;
|
||||||
|
use self::MaybeInfiniteInt::*;
|
||||||
use self::SliceKind::*;
|
use self::SliceKind::*;
|
||||||
|
|
||||||
use super::usefulness::{MatchCheckCtxt, PatCtxt};
|
use super::usefulness::{MatchCheckCtxt, PatCtxt};
|
||||||
@ -91,63 +92,21 @@ enum Presence {
|
|||||||
Seen,
|
Seen,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An inclusive interval, used for precise integer exhaustiveness checking.
|
/// A possibly infinite integer. Values are encoded such that the ordering on `u128` matches the
|
||||||
/// `IntRange`s always store a contiguous range. This means that values are
|
/// natural order on the original type. For example, `-128i8` is encoded as `0` and `127i8` as
|
||||||
/// encoded such that `0` encodes the minimum value for the integer,
|
/// `255`. See `signed_bias` for details.
|
||||||
/// regardless of the signedness.
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
/// For example, the pattern `-128..=127i8` is encoded as `0..=255`.
|
pub(crate) enum MaybeInfiniteInt {
|
||||||
/// This makes comparisons and arithmetic on interval endpoints much more
|
NegInfinity,
|
||||||
/// straightforward. See `signed_bias` for details.
|
/// Encoded value. DO NOT CONSTRUCT BY HAND; use `new_finite`.
|
||||||
///
|
Finite(u128),
|
||||||
/// `IntRange` is never used to encode an empty range or a "range" that wraps
|
/// The integer after `u128::MAX`. Used when we switch to exclusive ranges in `IntRange::split`.
|
||||||
/// around the (offset) space: i.e., `range.lo <= range.hi`.
|
JustAfterMax,
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
PosInfinity,
|
||||||
pub(crate) struct IntRange {
|
|
||||||
pub(crate) lo: u128,
|
|
||||||
pub(crate) hi: u128,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntRange {
|
impl MaybeInfiniteInt {
|
||||||
#[inline]
|
// The return value of `signed_bias` should be XORed with a value to encode/decode it.
|
||||||
pub(super) fn is_integral(ty: Ty<'_>) -> bool {
|
|
||||||
matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn is_singleton(&self) -> bool {
|
|
||||||
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
|
|
||||||
// type-independent.
|
|
||||||
let val = bits ^ bias;
|
|
||||||
IntRange { lo: val, hi: val }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_range<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
lo: u128,
|
|
||||||
hi: u128,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
end: RangeEnd,
|
|
||||||
) -> IntRange {
|
|
||||||
// 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;
|
|
||||||
let hi = hi - offset;
|
|
||||||
if lo > hi {
|
|
||||||
// This should have been caught earlier by E0030.
|
|
||||||
bug!("malformed range pattern: {lo}..={hi}");
|
|
||||||
}
|
|
||||||
IntRange { lo, hi }
|
|
||||||
}
|
|
||||||
|
|
||||||
// The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
|
|
||||||
fn signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> u128 {
|
fn signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> u128 {
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Int(ity) => {
|
ty::Int(ity) => {
|
||||||
@ -158,6 +117,107 @@ fn signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> u128 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_finite(tcx: TyCtxt<'_>, ty: Ty<'_>, bits: u128) -> Self {
|
||||||
|
let bias = Self::signed_bias(tcx, ty);
|
||||||
|
// Perform a shift if the underlying types are signed, which makes the interval arithmetic
|
||||||
|
// type-independent.
|
||||||
|
let x = bits ^ bias;
|
||||||
|
Finite(x)
|
||||||
|
}
|
||||||
|
fn from_pat_range_bdy<'tcx>(
|
||||||
|
bdy: PatRangeBoundary<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
) -> Self {
|
||||||
|
match bdy {
|
||||||
|
PatRangeBoundary::NegInfinity => NegInfinity,
|
||||||
|
PatRangeBoundary::Finite(value) => {
|
||||||
|
let bits = value.eval_bits(tcx, param_env);
|
||||||
|
Self::new_finite(tcx, ty, bits)
|
||||||
|
}
|
||||||
|
PatRangeBoundary::PosInfinity => PosInfinity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn to_pat_range_bdy<'tcx>(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> PatRangeBoundary<'tcx> {
|
||||||
|
match self {
|
||||||
|
NegInfinity => PatRangeBoundary::NegInfinity,
|
||||||
|
Finite(x) => {
|
||||||
|
let bias = Self::signed_bias(tcx, ty);
|
||||||
|
let bits = x ^ bias;
|
||||||
|
let env = ty::ParamEnv::empty().and(ty);
|
||||||
|
let value = mir::Const::from_bits(tcx, bits, env);
|
||||||
|
PatRangeBoundary::Finite(value)
|
||||||
|
}
|
||||||
|
JustAfterMax | PosInfinity => PatRangeBoundary::PosInfinity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn minus_one(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Finite(n) => match n.checked_sub(1) {
|
||||||
|
Some(m) => Finite(m),
|
||||||
|
None => NegInfinity,
|
||||||
|
},
|
||||||
|
JustAfterMax => Finite(u128::MAX),
|
||||||
|
x => x,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn plus_one(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Finite(n) => match n.checked_add(1) {
|
||||||
|
Some(m) => Finite(m),
|
||||||
|
None => JustAfterMax,
|
||||||
|
},
|
||||||
|
x => x,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An inclusive interval, used for precise integer exhaustiveness checking.
|
||||||
|
/// `IntRange`s always store a contiguous range.
|
||||||
|
///
|
||||||
|
/// `IntRange` is never used to encode an empty range or a "range" that wraps
|
||||||
|
/// around the (offset) space: i.e., `range.lo <= range.hi`.
|
||||||
|
///
|
||||||
|
/// The range can have open ends.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub(crate) struct IntRange {
|
||||||
|
pub(crate) lo: MaybeInfiniteInt, // Must not be `PosInfinity`.
|
||||||
|
pub(crate) hi: MaybeInfiniteInt, // Must not be `NegInfinity`.
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntRange {
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn is_integral(ty: Ty<'_>) -> bool {
|
||||||
|
matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Best effort; will not know that e.g. `255u8..` is a singleton.
|
||||||
|
pub(super) fn is_singleton(&self) -> bool {
|
||||||
|
// Since `lo` and `hi` can't be the same `Infinity`, this correctly only detects a
|
||||||
|
// `Finite(x)` singleton.
|
||||||
|
self.lo == self.hi
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_bits<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, bits: u128) -> IntRange {
|
||||||
|
let x = MaybeInfiniteInt::new_finite(tcx, ty, bits);
|
||||||
|
IntRange { lo: x, hi: x }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_range(lo: MaybeInfiniteInt, mut hi: MaybeInfiniteInt, end: RangeEnd) -> IntRange {
|
||||||
|
if end == RangeEnd::Excluded {
|
||||||
|
hi = hi.minus_one();
|
||||||
|
}
|
||||||
|
if lo > hi {
|
||||||
|
// This should have been caught earlier by E0030.
|
||||||
|
bug!("malformed range pattern: {lo:?}..={hi:?}");
|
||||||
|
}
|
||||||
|
IntRange { lo, hi }
|
||||||
|
}
|
||||||
|
|
||||||
fn is_subrange(&self, other: &Self) -> bool {
|
fn is_subrange(&self, other: &Self) -> bool {
|
||||||
other.lo <= self.lo && self.hi <= other.hi
|
other.lo <= self.lo && self.hi <= other.hi
|
||||||
}
|
}
|
||||||
@ -201,29 +261,16 @@ fn split(
|
|||||||
&self,
|
&self,
|
||||||
column_ranges: impl Iterator<Item = IntRange>,
|
column_ranges: impl Iterator<Item = IntRange>,
|
||||||
) -> impl Iterator<Item = (Presence, IntRange)> {
|
) -> impl Iterator<Item = (Presence, IntRange)> {
|
||||||
/// Represents a boundary between 2 integers. Because the intervals spanning boundaries must be
|
// Make the range into an exclusive range.
|
||||||
/// able to cover every integer, we need to be able to represent 2^128 + 1 such boundaries.
|
fn unpack_intrange(range: IntRange) -> [MaybeInfiniteInt; 2] {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
[range.lo, range.hi.plus_one()]
|
||||||
enum IntBoundary {
|
|
||||||
JustBefore(u128),
|
|
||||||
AfterMax,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unpack_intrange(range: IntRange) -> [IntBoundary; 2] {
|
|
||||||
use IntBoundary::*;
|
|
||||||
let lo = JustBefore(range.lo);
|
|
||||||
let hi = match range.hi.checked_add(1) {
|
|
||||||
Some(m) => JustBefore(m),
|
|
||||||
None => AfterMax,
|
|
||||||
};
|
|
||||||
[lo, hi]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The boundaries of ranges in `column_ranges` intersected with `self`.
|
// The boundaries of ranges in `column_ranges` intersected with `self`.
|
||||||
// We do parenthesis matching for input ranges. A boundary counts as +1 if it starts
|
// We do parenthesis matching for input ranges. A boundary counts as +1 if it starts
|
||||||
// a range and -1 if it ends it. When the count is > 0 between two boundaries, we
|
// a range and -1 if it ends it. When the count is > 0 between two boundaries, we
|
||||||
// are within an input range.
|
// are within an input range.
|
||||||
let mut boundaries: Vec<(IntBoundary, isize)> = column_ranges
|
let mut boundaries: Vec<(MaybeInfiniteInt, isize)> = column_ranges
|
||||||
.filter_map(|r| self.intersection(&r))
|
.filter_map(|r| self.intersection(&r))
|
||||||
.map(unpack_intrange)
|
.map(unpack_intrange)
|
||||||
.flat_map(|[lo, hi]| [(lo, 1), (hi, -1)])
|
.flat_map(|[lo, hi]| [(lo, 1), (hi, -1)])
|
||||||
@ -233,7 +280,7 @@ enum IntBoundary {
|
|||||||
// the accumulated count between distinct boundary values.
|
// the accumulated count between distinct boundary values.
|
||||||
boundaries.sort_unstable();
|
boundaries.sort_unstable();
|
||||||
|
|
||||||
let [self_start, self_end] = unpack_intrange(self.clone());
|
let [self_start, self_end] = unpack_intrange(*self);
|
||||||
// Accumulate parenthesis counts.
|
// Accumulate parenthesis counts.
|
||||||
let mut paren_counter = 0isize;
|
let mut paren_counter = 0isize;
|
||||||
// Gather pairs of adjacent boundaries.
|
// Gather pairs of adjacent boundaries.
|
||||||
@ -255,36 +302,26 @@ enum IntBoundary {
|
|||||||
.filter(|&(prev_bdy, _, bdy)| prev_bdy != bdy)
|
.filter(|&(prev_bdy, _, bdy)| prev_bdy != bdy)
|
||||||
// Convert back to ranges.
|
// Convert back to ranges.
|
||||||
.map(move |(prev_bdy, paren_count, bdy)| {
|
.map(move |(prev_bdy, paren_count, bdy)| {
|
||||||
use IntBoundary::*;
|
|
||||||
use Presence::*;
|
use Presence::*;
|
||||||
let presence = if paren_count > 0 { Seen } else { Unseen };
|
let presence = if paren_count > 0 { Seen } else { Unseen };
|
||||||
let (lo, hi) = match (prev_bdy, bdy) {
|
// Turn back into an inclusive range.
|
||||||
(JustBefore(n), JustBefore(m)) if n < m => (n, m - 1),
|
let range = IntRange::from_range(prev_bdy, bdy, RangeEnd::Excluded);
|
||||||
(JustBefore(n), AfterMax) => (n, u128::MAX),
|
(presence, range)
|
||||||
_ => unreachable!(), // Ruled out by the sorting and filtering we did
|
|
||||||
};
|
|
||||||
(presence, IntRange { lo, hi })
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only used for displaying the range.
|
/// Only used for displaying the range.
|
||||||
pub(super) fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
|
pub(super) fn to_pat<'tcx>(&self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Pat<'tcx> {
|
||||||
let bias = IntRange::signed_bias(tcx, ty);
|
let lo = self.lo.to_pat_range_bdy(ty, tcx);
|
||||||
let (lo_bits, hi_bits) = (self.lo ^ bias, self.hi ^ bias);
|
let hi = self.hi.to_pat_range_bdy(ty, tcx);
|
||||||
|
|
||||||
let env = ty::ParamEnv::empty().and(ty);
|
let kind = if self.is_singleton() {
|
||||||
let lo_const = mir::Const::from_bits(tcx, lo_bits, env);
|
let value = lo.as_finite().unwrap();
|
||||||
let hi_const = mir::Const::from_bits(tcx, hi_bits, env);
|
PatKind::Constant { value }
|
||||||
|
} else if matches!((self.lo, self.hi), (NegInfinity, PosInfinity)) {
|
||||||
let kind = if lo_bits == hi_bits {
|
PatKind::Wild
|
||||||
PatKind::Constant { value: lo_const }
|
|
||||||
} else {
|
} else {
|
||||||
PatKind::Range(Box::new(PatRange {
|
PatKind::Range(Box::new(PatRange { lo, hi, end: RangeEnd::Included, ty }))
|
||||||
lo: PatRangeBoundary::Finite(lo_const),
|
|
||||||
hi: PatRangeBoundary::Finite(hi_const),
|
|
||||||
end: RangeEnd::Included,
|
|
||||||
ty,
|
|
||||||
}))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Pat { ty, span: DUMMY_SP, kind }
|
Pat { ty, span: DUMMY_SP, kind }
|
||||||
@ -295,10 +332,14 @@ pub(super) fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx>
|
|||||||
/// 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.lo, self.hi);
|
if let Finite(lo) = self.lo {
|
||||||
write!(f, "{lo}")?;
|
write!(f, "{lo}")?;
|
||||||
|
}
|
||||||
write!(f, "{}", RangeEnd::Included)?;
|
write!(f, "{}", RangeEnd::Included)?;
|
||||||
write!(f, "{hi}")
|
if let Finite(hi) = self.hi {
|
||||||
|
write!(f, "{hi}")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -840,8 +881,13 @@ pub(super) struct SplitConstructorSet<'tcx> {
|
|||||||
impl ConstructorSet {
|
impl ConstructorSet {
|
||||||
#[instrument(level = "debug", skip(cx), ret)]
|
#[instrument(level = "debug", skip(cx), ret)]
|
||||||
pub(super) fn for_ty<'p, 'tcx>(cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>) -> Self {
|
pub(super) fn for_ty<'p, 'tcx>(cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>) -> Self {
|
||||||
let make_range =
|
let make_range = |start, end| {
|
||||||
|start, end| IntRange::from_range(cx.tcx, start, end, ty, RangeEnd::Included);
|
IntRange::from_range(
|
||||||
|
MaybeInfiniteInt::new_finite(cx.tcx, ty, start),
|
||||||
|
MaybeInfiniteInt::new_finite(cx.tcx, ty, end),
|
||||||
|
RangeEnd::Included,
|
||||||
|
)
|
||||||
|
};
|
||||||
// This determines the set of all possible constructors for the type `ty`. For numbers,
|
// This determines the set of all possible constructors for the type `ty`. For numbers,
|
||||||
// arrays and slices we use ranges and variable-length slices when appropriate.
|
// arrays and slices we use ranges and variable-length slices when appropriate.
|
||||||
//
|
//
|
||||||
@ -1419,25 +1465,34 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::Range(box PatRange { lo, hi, end, .. }) => {
|
PatKind::Range(box PatRange { lo, hi, end, .. }) => {
|
||||||
use rustc_apfloat::Float;
|
|
||||||
let ty = pat.ty;
|
let ty = pat.ty;
|
||||||
// FIXME: handle half-open ranges
|
|
||||||
let lo = lo.eval_bits(ty, cx.tcx, cx.param_env);
|
|
||||||
let hi = hi.eval_bits(ty, cx.tcx, cx.param_env);
|
|
||||||
ctor = match ty.kind() {
|
ctor = match ty.kind() {
|
||||||
ty::Char | ty::Int(_) | ty::Uint(_) => {
|
ty::Char | ty::Int(_) | ty::Uint(_) => {
|
||||||
IntRange(IntRange::from_range(cx.tcx, lo, hi, ty, *end))
|
let lo =
|
||||||
|
MaybeInfiniteInt::from_pat_range_bdy(*lo, ty, cx.tcx, cx.param_env);
|
||||||
|
let hi =
|
||||||
|
MaybeInfiniteInt::from_pat_range_bdy(*hi, ty, cx.tcx, cx.param_env);
|
||||||
|
IntRange(IntRange::from_range(lo, hi, *end))
|
||||||
}
|
}
|
||||||
ty::Float(ty::FloatTy::F32) => {
|
ty::Float(fty) => {
|
||||||
let lo = rustc_apfloat::ieee::Single::from_bits(lo);
|
use rustc_apfloat::Float;
|
||||||
let hi = rustc_apfloat::ieee::Single::from_bits(hi);
|
let lo = lo.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env));
|
||||||
|
let hi = hi.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env));
|
||||||
|
match fty {
|
||||||
|
ty::FloatTy::F32 => {
|
||||||
|
use rustc_apfloat::ieee::Single;
|
||||||
|
let lo = lo.map(Single::from_bits).unwrap_or(-Single::INFINITY);
|
||||||
|
let hi = hi.map(Single::from_bits).unwrap_or(Single::INFINITY);
|
||||||
F32Range(lo, hi, *end)
|
F32Range(lo, hi, *end)
|
||||||
}
|
}
|
||||||
ty::Float(ty::FloatTy::F64) => {
|
ty::FloatTy::F64 => {
|
||||||
let lo = rustc_apfloat::ieee::Double::from_bits(lo);
|
use rustc_apfloat::ieee::Double;
|
||||||
let hi = rustc_apfloat::ieee::Double::from_bits(hi);
|
let lo = lo.map(Double::from_bits).unwrap_or(-Double::INFINITY);
|
||||||
|
let hi = hi.map(Double::from_bits).unwrap_or(Double::INFINITY);
|
||||||
F64Range(lo, hi, *end)
|
F64Range(lo, hi, *end)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => bug!("invalid type for range pattern: {}", ty),
|
_ => bug!("invalid type for range pattern: {}", ty),
|
||||||
};
|
};
|
||||||
fields = Fields::empty();
|
fields = Fields::empty();
|
||||||
@ -1706,7 +1761,7 @@ pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'_, 'tcx>) -> Pat<'tcx> {
|
|||||||
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) },
|
Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) },
|
||||||
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
|
IntRange(range) => return range.to_pat(self.ty, cx.tcx),
|
||||||
Single | Variant(_) => match self.ty.kind() {
|
Single | Variant(_) => match self.ty.kind() {
|
||||||
ty::Tuple(..) => PatKind::Leaf {
|
ty::Tuple(..) => PatKind::Leaf {
|
||||||
subpatterns: subpatterns
|
subpatterns: subpatterns
|
||||||
|
@ -308,7 +308,8 @@
|
|||||||
use self::ArmType::*;
|
use self::ArmType::*;
|
||||||
use self::Usefulness::*;
|
use self::Usefulness::*;
|
||||||
use super::deconstruct_pat::{
|
use super::deconstruct_pat::{
|
||||||
Constructor, ConstructorSet, DeconstructedPat, IntRange, SplitConstructorSet, WitnessPat,
|
Constructor, ConstructorSet, DeconstructedPat, IntRange, MaybeInfiniteInt, SplitConstructorSet,
|
||||||
|
WitnessPat,
|
||||||
};
|
};
|
||||||
use crate::errors::{NonExhaustiveOmittedPattern, Overlap, OverlappingRangeEndpoints, Uncovered};
|
use crate::errors::{NonExhaustiveOmittedPattern, Overlap, OverlappingRangeEndpoints, Uncovered};
|
||||||
|
|
||||||
@ -1013,7 +1014,7 @@ fn lint_overlapping_range_endpoints<'p, 'tcx>(
|
|||||||
|
|
||||||
if IntRange::is_integral(ty) {
|
if IntRange::is_integral(ty) {
|
||||||
let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| {
|
let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| {
|
||||||
let overlap_as_pat = overlap.to_pat(cx.tcx, ty);
|
let overlap_as_pat = overlap.to_pat(ty, cx.tcx);
|
||||||
let overlaps: Vec<_> = overlapped_spans
|
let overlaps: Vec<_> = overlapped_spans
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
@ -1031,7 +1032,7 @@ fn lint_overlapping_range_endpoints<'p, 'tcx>(
|
|||||||
let split_int_ranges = set.present.iter().filter_map(|c| c.as_int_range());
|
let split_int_ranges = set.present.iter().filter_map(|c| c.as_int_range());
|
||||||
for overlap_range in split_int_ranges.clone() {
|
for overlap_range in split_int_ranges.clone() {
|
||||||
if overlap_range.is_singleton() {
|
if overlap_range.is_singleton() {
|
||||||
let overlap: u128 = overlap_range.lo;
|
let overlap: MaybeInfiniteInt = overlap_range.lo;
|
||||||
// Ranges that look like `lo..=overlap`.
|
// Ranges that look like `lo..=overlap`.
|
||||||
let mut prefixes: SmallVec<[_; 1]> = Default::default();
|
let mut prefixes: SmallVec<[_; 1]> = Default::default();
|
||||||
// Ranges that look like `overlap..=hi`.
|
// Ranges that look like `overlap..=hi`.
|
||||||
|
Loading…
Reference in New Issue
Block a user