@@ -851,17 +851,21 @@ impl<'tcx> PatRange<'tcx> {
851
851
//
852
852
// Also, for performance, it's important to only do the second `try_to_bits` if necessary.
853
853
let lo_is_min = match self . lo {
854
+ PatRangeBoundary :: NegInfinity => true ,
854
855
PatRangeBoundary :: Finite ( value) => {
855
856
let lo = value. try_to_bits ( size) . unwrap ( ) ^ bias;
856
857
lo <= min
857
858
}
859
+ PatRangeBoundary :: PosInfinity => false ,
858
860
} ;
859
861
if lo_is_min {
860
862
let hi_is_max = match self . hi {
863
+ PatRangeBoundary :: NegInfinity => false ,
861
864
PatRangeBoundary :: Finite ( value) => {
862
865
let hi = value. try_to_bits ( size) . unwrap ( ) ^ bias;
863
866
hi > max || hi == max && self . end == RangeEnd :: Included
864
867
}
868
+ PatRangeBoundary :: PosInfinity => true ,
865
869
} ;
866
870
if hi_is_max {
867
871
return Some ( true ) ;
@@ -920,11 +924,16 @@ impl<'tcx> PatRange<'tcx> {
920
924
921
925
impl < ' tcx > fmt:: Display for PatRange < ' tcx > {
922
926
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
+ }
928
937
Ok ( ( ) )
929
938
}
930
939
}
@@ -934,38 +943,49 @@ impl<'tcx> fmt::Display for PatRange<'tcx> {
934
943
#[ derive( Copy , Clone , Debug , PartialEq , HashStable , TypeVisitable ) ]
935
944
pub enum PatRangeBoundary < ' tcx > {
936
945
Finite ( mir:: Const < ' tcx > ) ,
946
+ NegInfinity ,
947
+ PosInfinity ,
937
948
}
938
949
939
950
impl < ' tcx > PatRangeBoundary < ' tcx > {
940
951
#[ 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 ( ..) )
946
954
}
947
955
#[ 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
+ }
953
961
}
954
-
955
962
#[ 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 > {
957
964
match self {
958
965
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
+ }
959
976
}
960
977
}
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 {
967
979
match self {
968
980
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
+ }
969
989
}
970
990
}
971
991
@@ -979,6 +999,12 @@ impl<'tcx> PatRangeBoundary<'tcx> {
979
999
) -> Option < Ordering > {
980
1000
use PatRangeBoundary :: * ;
981
1001
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
+
982
1008
// This code is hot when compiling matches with many ranges. So we
983
1009
// special-case extraction of evaluated scalars for speed, for types where
984
1010
// raw data comparisons are appropriate. E.g. `unicode-normalization` has
0 commit comments