@@ -851,17 +851,21 @@ impl<'tcx> PatRange<'tcx> {
851851 //
852852 // Also, for performance, it's important to only do the second `try_to_bits` if necessary.
853853 let lo_is_min = match self . lo {
854+ PatRangeBoundary :: NegInfinity => true ,
854855 PatRangeBoundary :: Finite ( value) => {
855856 let lo = value. try_to_bits ( size) . unwrap ( ) ^ bias;
856857 lo <= min
857858 }
859+ PatRangeBoundary :: PosInfinity => false ,
858860 } ;
859861 if lo_is_min {
860862 let hi_is_max = match self . hi {
863+ PatRangeBoundary :: NegInfinity => false ,
861864 PatRangeBoundary :: Finite ( value) => {
862865 let hi = value. try_to_bits ( size) . unwrap ( ) ^ bias;
863866 hi > max || hi == max && self . end == RangeEnd :: Included
864867 }
868+ PatRangeBoundary :: PosInfinity => true ,
865869 } ;
866870 if hi_is_max {
867871 return Some ( true ) ;
@@ -920,11 +924,16 @@ impl<'tcx> PatRange<'tcx> {
920924
921925impl < ' tcx > fmt:: Display for PatRange < ' tcx > {
922926 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
923- let PatRangeBoundary :: Finite ( value) = & self . lo ;
924- write ! ( f, "{value}" ) ?;
925- write ! ( f, "{}" , self . end) ?;
926- let PatRangeBoundary :: Finite ( value) = & self . hi ;
927- write ! ( f, "{value}" ) ?;
927+ if let PatRangeBoundary :: Finite ( value) = & self . lo {
928+ write ! ( f, "{value}" ) ?;
929+ }
930+ if let PatRangeBoundary :: Finite ( value) = & self . hi {
931+ write ! ( f, "{}" , self . end) ?;
932+ write ! ( f, "{value}" ) ?;
933+ } else {
934+ // `0..` is parsed as an inclusive range, we must display it correctly.
935+ write ! ( f, ".." ) ?;
936+ }
928937 Ok ( ( ) )
929938 }
930939}
@@ -934,38 +943,49 @@ impl<'tcx> fmt::Display for PatRange<'tcx> {
934943#[ derive( Copy , Clone , Debug , PartialEq , HashStable , TypeVisitable ) ]
935944pub enum PatRangeBoundary < ' tcx > {
936945 Finite ( mir:: Const < ' tcx > ) ,
946+ NegInfinity ,
947+ PosInfinity ,
937948}
938949
939950impl < ' tcx > PatRangeBoundary < ' tcx > {
940951 #[ inline]
941- pub fn lower_bound ( ty : Ty < ' tcx > , tcx : TyCtxt < ' tcx > ) -> Self {
942- // Unwrap is ok because the type is known to be numeric.
943- let c = ty. numeric_min_val ( tcx) . unwrap ( ) ;
944- let value = mir:: Const :: from_ty_const ( c, tcx) ;
945- Self :: Finite ( value)
952+ pub fn is_finite ( self ) -> bool {
953+ matches ! ( self , Self :: Finite ( ..) )
946954 }
947955 #[ inline]
948- pub fn upper_bound ( ty : Ty < ' tcx > , tcx : TyCtxt < ' tcx > ) -> Self {
949- // Unwrap is ok because the type is known to be numeric.
950- let c = ty . numeric_max_val ( tcx ) . unwrap ( ) ;
951- let value = mir :: Const :: from_ty_const ( c , tcx ) ;
952- Self :: Finite ( value )
956+ pub fn as_finite ( self ) -> Option < mir :: Const < ' tcx > > {
957+ match self {
958+ Self :: Finite ( value ) => Some ( value ) ,
959+ Self :: NegInfinity | Self :: PosInfinity => None ,
960+ }
953961 }
954-
955962 #[ inline]
956- pub fn to_const ( self , _ty : Ty < ' tcx > , _tcx : TyCtxt < ' tcx > ) -> mir:: Const < ' tcx > {
963+ pub fn to_const ( self , ty : Ty < ' tcx > , tcx : TyCtxt < ' tcx > ) -> mir:: Const < ' tcx > {
957964 match self {
958965 Self :: Finite ( value) => value,
966+ Self :: NegInfinity => {
967+ // Unwrap is ok because the type is known to be numeric.
968+ let c = ty. numeric_min_val ( tcx) . unwrap ( ) ;
969+ mir:: Const :: from_ty_const ( c, tcx)
970+ }
971+ Self :: PosInfinity => {
972+ // Unwrap is ok because the type is known to be numeric.
973+ let c = ty. numeric_max_val ( tcx) . unwrap ( ) ;
974+ mir:: Const :: from_ty_const ( c, tcx)
975+ }
959976 }
960977 }
961- pub fn eval_bits (
962- self ,
963- _ty : Ty < ' tcx > ,
964- tcx : TyCtxt < ' tcx > ,
965- param_env : ty:: ParamEnv < ' tcx > ,
966- ) -> u128 {
978+ pub fn eval_bits ( self , ty : Ty < ' tcx > , tcx : TyCtxt < ' tcx > , param_env : ty:: ParamEnv < ' tcx > ) -> u128 {
967979 match self {
968980 Self :: Finite ( value) => value. eval_bits ( tcx, param_env) ,
981+ Self :: NegInfinity => {
982+ // Unwrap is ok because the type is known to be numeric.
983+ ty. numeric_min_and_max_as_bits ( tcx) . unwrap ( ) . 0
984+ }
985+ Self :: PosInfinity => {
986+ // Unwrap is ok because the type is known to be numeric.
987+ ty. numeric_min_and_max_as_bits ( tcx) . unwrap ( ) . 1
988+ }
969989 }
970990 }
971991
@@ -979,6 +999,12 @@ impl<'tcx> PatRangeBoundary<'tcx> {
979999 ) -> Option < Ordering > {
9801000 use PatRangeBoundary :: * ;
9811001 match ( self , other) {
1002+ // When comparing with infinities, we must remember that `0u8..` and `0u8..=255`
1003+ // describe the same range. These two shortcuts are ok, but for the rest we must check
1004+ // bit values.
1005+ ( PosInfinity , PosInfinity ) => return Some ( Ordering :: Equal ) ,
1006+ ( NegInfinity , NegInfinity ) => return Some ( Ordering :: Equal ) ,
1007+
9821008 // This code is hot when compiling matches with many ranges. So we
9831009 // special-case extraction of evaluated scalars for speed, for types where
9841010 // raw data comparisons are appropriate. E.g. `unicode-normalization` has
0 commit comments