diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index aa02ca27add..16438ae574d 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -159,9 +159,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::RangeEnd; use rustc_index::IndexVec; use rustc_middle::mir::Const; -use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_target::abi::{Integer, VariantIdx}; +use rustc_target::abi::VariantIdx; use self::Constructor::*; use self::MaybeInfiniteInt::*; @@ -183,6 +181,7 @@ enum Presence { pub enum MaybeInfiniteInt { NegInfinity, /// Encoded value. DO NOT CONSTRUCT BY HAND; use `new_finite`. + #[non_exhaustive] Finite(u128), /// The integer after `u128::MAX`. We need it to represent `x..=u128::MAX` as an exclusive range. JustAfterMax, @@ -190,23 +189,31 @@ pub enum MaybeInfiniteInt { } impl MaybeInfiniteInt { - // The return value of `signed_bias` should be XORed with a value to encode/decode it. - pub(crate) fn signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> u128 { - match *ty.kind() { - ty::Int(ity) => { - let bits = Integer::from_int_ty(&tcx, ity).size().bits() as u128; - 1u128 << (bits - 1) - } - _ => 0, - } + pub fn new_finite_uint(bits: u128) -> Self { + Finite(bits) } - - pub fn new_finite(tcx: TyCtxt<'_>, ty: Ty<'_>, bits: u128) -> Self { - let bias = Self::signed_bias(tcx, ty); + pub fn new_finite_int(bits: u128, size: u64) -> Self { // Perform a shift if the underlying types are signed, which makes the interval arithmetic // type-independent. - let x = bits ^ bias; - Finite(x) + let bias = 1u128 << (size - 1); + Finite(bits ^ bias) + } + + pub fn as_finite_uint(self) -> Option { + match self { + Finite(bits) => Some(bits), + _ => None, + } + } + pub fn as_finite_int(self, size: u64) -> Option { + // We decode the shift. + match self { + Finite(bits) => { + let bias = 1u128 << (size - 1); + Some(bits ^ bias) + } + _ => None, + } } /// Note: this will not turn a finite value into an infinite one or vice-versa. @@ -253,8 +260,7 @@ impl IntRange { } #[inline] - pub fn from_bits<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, bits: u128) -> IntRange { - let x = MaybeInfiniteInt::new_finite(tcx, ty, bits); + pub fn from_singleton(x: MaybeInfiniteInt) -> IntRange { IntRange { lo: x, hi: x.plus_one() } } diff --git a/compiler/rustc_pattern_analysis/src/cx.rs b/compiler/rustc_pattern_analysis/src/cx.rs index ffcbd2f5d83..8a4f39a1f4a 100644 --- a/compiler/rustc_pattern_analysis/src/cx.rs +++ b/compiler/rustc_pattern_analysis/src/cx.rs @@ -204,10 +204,10 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> { #[instrument(level = "debug", skip(self), ret)] pub fn ctors_for_ty(&self, ty: Ty<'tcx>) -> ConstructorSet { let cx = self; - let make_range = |start, end| { + let make_uint_range = |start, end| { IntRange::from_range( - MaybeInfiniteInt::new_finite(cx.tcx, ty, start), - MaybeInfiniteInt::new_finite(cx.tcx, ty, end), + MaybeInfiniteInt::new_finite_uint(start), + MaybeInfiniteInt::new_finite_uint(end), RangeEnd::Included, ) }; @@ -218,8 +218,8 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> { ty::Char => { // The valid Unicode Scalar Value ranges. ConstructorSet::Integers { - range_1: make_range('\u{0000}' as u128, '\u{D7FF}' as u128), - range_2: Some(make_range('\u{E000}' as u128, '\u{10FFFF}' as u128)), + range_1: make_uint_range('\u{0000}' as u128, '\u{D7FF}' as u128), + range_2: Some(make_uint_range('\u{E000}' as u128, '\u{10FFFF}' as u128)), } } &ty::Int(ity) => { @@ -230,22 +230,24 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> { hi: MaybeInfiniteInt::PosInfinity, } } else { - let bits = Integer::from_int_ty(&cx.tcx, ity).size().bits() as u128; - let min = 1u128 << (bits - 1); + let size = Integer::from_int_ty(&cx.tcx, ity).size().bits(); + let min = 1u128 << (size - 1); let max = min - 1; - make_range(min, max) + let min = MaybeInfiniteInt::new_finite_int(min, size); + let max = MaybeInfiniteInt::new_finite_int(max, size); + IntRange::from_range(min, max, RangeEnd::Included) }; ConstructorSet::Integers { range_1: range, range_2: None } } &ty::Uint(uty) => { let range = if ty.is_ptr_sized_integral() { // The max value of `usize` is not allowed to be observed. - let lo = MaybeInfiniteInt::new_finite(cx.tcx, ty, 0); + let lo = MaybeInfiniteInt::new_finite_uint(0); IntRange { lo, hi: MaybeInfiniteInt::PosInfinity } } else { let size = Integer::from_uint_ty(&cx.tcx, uty).size(); let max = size.truncate(u128::MAX); - make_range(0, max) + make_uint_range(0, max) }; ConstructorSet::Integers { range_1: range, range_2: None } } @@ -329,7 +331,13 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> { PatRangeBoundary::NegInfinity => MaybeInfiniteInt::NegInfinity, PatRangeBoundary::Finite(value) => { let bits = value.eval_bits(self.tcx, self.param_env); - MaybeInfiniteInt::new_finite(self.tcx, ty, bits) + match *ty.kind() { + ty::Int(ity) => { + let size = Integer::from_int_ty(&self.tcx, ity).size().bits(); + MaybeInfiniteInt::new_finite_int(bits, size) + } + _ => MaybeInfiniteInt::new_finite_uint(bits), + } } PatRangeBoundary::PosInfinity => MaybeInfiniteInt::PosInfinity, } @@ -428,7 +436,16 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> { } ty::Char | ty::Int(_) | ty::Uint(_) => { ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { - Some(bits) => IntRange(IntRange::from_bits(cx.tcx, pat.ty, bits)), + Some(bits) => { + let x = match *pat.ty.kind() { + ty::Int(ity) => { + let size = Integer::from_int_ty(&cx.tcx, ity).size().bits(); + MaybeInfiniteInt::new_finite_int(bits, size) + } + _ => MaybeInfiniteInt::new_finite_uint(bits), + }; + IntRange(IntRange::from_singleton(x)) + } None => Opaque(OpaqueId::new()), }; fields = &[]; @@ -559,10 +576,12 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> { let tcx = self.tcx; match miint { NegInfinity => PatRangeBoundary::NegInfinity, - Finite(x) => { - let bias = MaybeInfiniteInt::signed_bias(tcx, ty); - let bits = x ^ bias; + Finite(_) => { let size = ty.primitive_size(tcx); + let bits = match *ty.kind() { + ty::Int(_) => miint.as_finite_int(size.bits()).unwrap(), + _ => miint.as_finite_uint().unwrap(), + }; match Scalar::try_from_uint(bits, size) { Some(scalar) => { let value = mir::Const::from_scalar(tcx, scalar, ty);