@@ -50,6 +50,7 @@ use std::ops::RangeInclusive;
50
50
51
51
use smallvec:: { smallvec, SmallVec } ;
52
52
53
+ use rustc_apfloat:: ieee:: { DoubleS , IeeeFloat , SingleS } ;
53
54
use rustc_data_structures:: captures:: Captures ;
54
55
use rustc_hir:: { HirId , RangeEnd } ;
55
56
use rustc_index:: Idx ;
@@ -60,12 +61,11 @@ use rustc_middle::ty::layout::IntegerExt;
60
61
use rustc_middle:: ty:: { self , Ty , TyCtxt , VariantDef } ;
61
62
use rustc_session:: lint;
62
63
use rustc_span:: { Span , DUMMY_SP } ;
63
- use rustc_target:: abi:: { FieldIdx , Integer , Size , VariantIdx , FIRST_VARIANT } ;
64
+ use rustc_target:: abi:: { FieldIdx , Integer , VariantIdx , FIRST_VARIANT } ;
64
65
65
66
use self :: Constructor :: * ;
66
67
use self :: SliceKind :: * ;
67
68
68
- use super :: compare_const_vals;
69
69
use super :: usefulness:: { MatchCheckCtxt , PatCtxt } ;
70
70
use crate :: errors:: { Overlap , OverlappingRangeEndpoints } ;
71
71
@@ -99,10 +99,6 @@ fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
99
99
#[ derive( Clone , PartialEq , Eq ) ]
100
100
pub ( crate ) struct IntRange {
101
101
range : RangeInclusive < u128 > ,
102
- /// Keeps the bias used for encoding the range. It depends on the type of the range and
103
- /// possibly the pointer size of the current architecture. The algorithm ensures we never
104
- /// compare `IntRange`s with different types/architectures.
105
- bias : u128 ,
106
102
}
107
103
108
104
impl IntRange {
@@ -120,37 +116,12 @@ impl IntRange {
120
116
}
121
117
122
118
#[ inline]
123
- fn integral_size_and_signed_bias ( tcx : TyCtxt < ' _ > , ty : Ty < ' _ > ) -> Option < ( Size , u128 ) > {
124
- match * ty. kind ( ) {
125
- ty:: Bool => Some ( ( Size :: from_bytes ( 1 ) , 0 ) ) ,
126
- ty:: Char => Some ( ( Size :: from_bytes ( 4 ) , 0 ) ) ,
127
- ty:: Int ( ity) => {
128
- let size = Integer :: from_int_ty ( & tcx, ity) . size ( ) ;
129
- Some ( ( size, 1u128 << ( size. bits ( ) as u128 - 1 ) ) )
130
- }
131
- ty:: Uint ( uty) => Some ( ( Integer :: from_uint_ty ( & tcx, uty) . size ( ) , 0 ) ) ,
132
- _ => None ,
133
- }
134
- }
135
-
136
- #[ inline]
137
- fn from_constant < ' tcx > (
138
- tcx : TyCtxt < ' tcx > ,
139
- param_env : ty:: ParamEnv < ' tcx > ,
140
- value : mir:: Const < ' tcx > ,
141
- ) -> Option < IntRange > {
142
- let ty = value. ty ( ) ;
143
- let ( target_size, bias) = Self :: integral_size_and_signed_bias ( tcx, ty) ?;
144
- let val = match value {
145
- mir:: Const :: Ty ( c) if let ty:: ConstKind :: Value ( valtree) = c. kind ( ) => {
146
- valtree. unwrap_leaf ( ) . to_bits ( target_size) . ok ( )
147
- } ,
148
- // This is a more general form of the previous case.
149
- _ => value. try_eval_bits ( tcx, param_env) ,
150
- } ?;
151
-
152
- let val = val ^ bias;
153
- Some ( IntRange { range : val..=val, bias } )
119
+ fn from_bits < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > , bits : u128 ) -> IntRange {
120
+ let bias = IntRange :: signed_bias ( tcx, ty) ;
121
+ // Perform a shift if the underlying types are signed,
122
+ // which makes the interval arithmetic simpler.
123
+ let val = bits ^ bias;
124
+ IntRange { range : val..=val }
154
125
}
155
126
156
127
#[ inline]
@@ -159,20 +130,18 @@ impl IntRange {
159
130
lo : u128 ,
160
131
hi : u128 ,
161
132
ty : Ty < ' tcx > ,
162
- end : & RangeEnd ,
163
- ) -> Option < IntRange > {
164
- Self :: is_integral ( ty) . then ( || {
165
- // Perform a shift if the underlying types are signed,
166
- // which makes the interval arithmetic simpler.
167
- let bias = IntRange :: signed_bias ( tcx, ty) ;
168
- let ( lo, hi) = ( lo ^ bias, hi ^ bias) ;
169
- let offset = ( * end == RangeEnd :: Excluded ) as u128 ;
170
- if lo > hi || ( lo == hi && * end == RangeEnd :: Excluded ) {
171
- // This should have been caught earlier by E0030.
172
- bug ! ( "malformed range pattern: {}..={}" , lo, ( hi - offset) ) ;
173
- }
174
- IntRange { range : lo..=( hi - offset) , bias }
175
- } )
133
+ end : RangeEnd ,
134
+ ) -> IntRange {
135
+ // Perform a shift if the underlying types are signed,
136
+ // which makes the interval arithmetic simpler.
137
+ let bias = IntRange :: signed_bias ( tcx, ty) ;
138
+ let ( lo, hi) = ( lo ^ bias, hi ^ bias) ;
139
+ let offset = ( end == RangeEnd :: Excluded ) as u128 ;
140
+ if lo > hi || ( lo == hi && end == RangeEnd :: Excluded ) {
141
+ // This should have been caught earlier by E0030.
142
+ bug ! ( "malformed range pattern: {}..={}" , lo, ( hi - offset) ) ;
143
+ }
144
+ IntRange { range : lo..=( hi - offset) }
176
145
}
177
146
178
147
// The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
@@ -194,7 +163,7 @@ impl IntRange {
194
163
let ( lo, hi) = self . boundaries ( ) ;
195
164
let ( other_lo, other_hi) = other. boundaries ( ) ;
196
165
if lo <= other_hi && other_lo <= hi {
197
- Some ( IntRange { range : max ( lo, other_lo) ..=min ( hi, other_hi) , bias : self . bias } )
166
+ Some ( IntRange { range : max ( lo, other_lo) ..=min ( hi, other_hi) } )
198
167
} else {
199
168
None
200
169
}
@@ -221,7 +190,7 @@ impl IntRange {
221
190
fn to_pat < ' tcx > ( & self , tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> Pat < ' tcx > {
222
191
let ( lo, hi) = self . boundaries ( ) ;
223
192
224
- let bias = self . bias ;
193
+ let bias = IntRange :: signed_bias ( tcx , ty ) ;
225
194
let ( lo, hi) = ( lo ^ bias, hi ^ bias) ;
226
195
227
196
let env = ty:: ParamEnv :: empty ( ) . and ( ty) ;
@@ -304,8 +273,6 @@ impl IntRange {
304
273
impl fmt:: Debug for IntRange {
305
274
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
306
275
let ( lo, hi) = self . boundaries ( ) ;
307
- let bias = self . bias ;
308
- let ( lo, hi) = ( lo ^ bias, hi ^ bias) ;
309
276
write ! ( f, "{lo}" ) ?;
310
277
write ! ( f, "{}" , RangeEnd :: Included ) ?;
311
278
write ! ( f, "{hi}" )
@@ -402,7 +369,7 @@ impl SplitIntRange {
402
369
( JustBefore ( n) , AfterMax ) => n..=u128:: MAX ,
403
370
_ => unreachable ! ( ) , // Ruled out by the sorting and filtering we did
404
371
} ;
405
- IntRange { range, bias : self . range . bias }
372
+ IntRange { range }
406
373
} )
407
374
}
408
375
}
@@ -619,7 +586,8 @@ pub(super) enum Constructor<'tcx> {
619
586
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
620
587
IntRange ( IntRange ) ,
621
588
/// Ranges of floating-point literal values (`2.0..=5.2`).
622
- FloatRange ( mir:: Const < ' tcx > , mir:: Const < ' tcx > , RangeEnd ) ,
589
+ F32Range ( IeeeFloat < SingleS > , IeeeFloat < SingleS > , RangeEnd ) ,
590
+ F64Range ( IeeeFloat < DoubleS > , IeeeFloat < DoubleS > , RangeEnd ) ,
623
591
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
624
592
Str ( mir:: Const < ' tcx > ) ,
625
593
/// Array and slice patterns.
@@ -634,7 +602,9 @@ pub(super) enum Constructor<'tcx> {
634
602
/// Stands for constructors that are not seen in the matrix, as explained in the documentation
635
603
/// for [`SplitWildcard`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns`
636
604
/// lint.
637
- Missing { nonexhaustive_enum_missing_real_variants : bool } ,
605
+ Missing {
606
+ nonexhaustive_enum_missing_real_variants : bool ,
607
+ } ,
638
608
/// Wildcard pattern.
639
609
Wildcard ,
640
610
/// Or-pattern.
@@ -722,7 +692,8 @@ impl<'tcx> Constructor<'tcx> {
722
692
} ,
723
693
Slice ( slice) => slice. arity ( ) ,
724
694
Str ( ..)
725
- | FloatRange ( ..)
695
+ | F32Range ( ..)
696
+ | F64Range ( ..)
726
697
| IntRange ( ..)
727
698
| NonExhaustive
728
699
| Opaque
@@ -795,21 +766,21 @@ impl<'tcx> Constructor<'tcx> {
795
766
( Variant ( self_id) , Variant ( other_id) ) => self_id == other_id,
796
767
797
768
( IntRange ( self_range) , IntRange ( other_range) ) => self_range. is_covered_by ( other_range) ,
798
- (
799
- FloatRange ( self_from, self_to, self_end) ,
800
- FloatRange ( other_from, other_to, other_end) ,
801
- ) => {
802
- match (
803
- compare_const_vals ( pcx. cx . tcx , * self_to, * other_to, pcx. cx . param_env ) ,
804
- compare_const_vals ( pcx. cx . tcx , * self_from, * other_from, pcx. cx . param_env ) ,
805
- ) {
806
- ( Some ( to) , Some ( from) ) => {
807
- ( from == Ordering :: Greater || from == Ordering :: Equal )
808
- && ( to == Ordering :: Less
809
- || ( other_end == self_end && to == Ordering :: Equal ) )
769
+ ( F32Range ( self_from, self_to, self_end) , F32Range ( other_from, other_to, other_end) ) => {
770
+ self_from. ge ( other_from)
771
+ && match self_to. partial_cmp ( other_to) {
772
+ Some ( Ordering :: Less ) => true ,
773
+ Some ( Ordering :: Equal ) => other_end == self_end,
774
+ _ => false ,
775
+ }
776
+ }
777
+ ( F64Range ( self_from, self_to, self_end) , F64Range ( other_from, other_to, other_end) ) => {
778
+ self_from. ge ( other_from)
779
+ && match self_to. partial_cmp ( other_to) {
780
+ Some ( Ordering :: Less ) => true ,
781
+ Some ( Ordering :: Equal ) => other_end == self_end,
782
+ _ => false ,
810
783
}
811
- _ => false ,
812
- }
813
784
}
814
785
( Str ( self_val) , Str ( other_val) ) => {
815
786
// FIXME Once valtrees are available we can directly use the bytes
@@ -859,7 +830,7 @@ impl<'tcx> Constructor<'tcx> {
859
830
. any ( |other| slice. is_covered_by ( other) ) ,
860
831
// This constructor is never covered by anything else
861
832
NonExhaustive => false ,
862
- Str ( ..) | FloatRange ( ..) | Opaque | Missing { .. } | Wildcard | Or => {
833
+ Str ( ..) | F32Range ( .. ) | F64Range ( ..) | Opaque | Missing { .. } | Wildcard | Or => {
863
834
span_bug ! ( pcx. span, "found unexpected ctor in all_ctors: {:?}" , self )
864
835
}
865
836
}
@@ -896,7 +867,7 @@ impl<'tcx> SplitWildcard<'tcx> {
896
867
let make_range = |start, end| {
897
868
IntRange (
898
869
// `unwrap()` is ok because we know the type is an integer.
899
- IntRange :: from_range ( cx. tcx , start, end, pcx. ty , & RangeEnd :: Included ) . unwrap ( ) ,
870
+ IntRange :: from_range ( cx. tcx , start, end, pcx. ty , RangeEnd :: Included ) ,
900
871
)
901
872
} ;
902
873
// This determines the set of all possible constructors for the type `pcx.ty`. For numbers,
@@ -1203,7 +1174,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1203
1174
_ => bug ! ( "bad slice pattern {:?} {:?}" , constructor, pcx) ,
1204
1175
} ,
1205
1176
Str ( ..)
1206
- | FloatRange ( ..)
1177
+ | F32Range ( ..)
1178
+ | F64Range ( ..)
1207
1179
| IntRange ( ..)
1208
1180
| NonExhaustive
1209
1181
| Opaque
@@ -1343,50 +1315,78 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1343
1315
}
1344
1316
}
1345
1317
PatKind :: Constant { value } => {
1346
- if let Some ( int_range) = IntRange :: from_constant ( cx. tcx , cx. param_env , * value) {
1347
- ctor = IntRange ( int_range) ;
1348
- fields = Fields :: empty ( ) ;
1349
- } else {
1350
- match pat. ty . kind ( ) {
1351
- ty:: Float ( _) => {
1352
- ctor = FloatRange ( * value, * value, RangeEnd :: Included ) ;
1353
- fields = Fields :: empty ( ) ;
1354
- }
1355
- ty:: Ref ( _, t, _) if t. is_str ( ) => {
1356
- // We want a `&str` constant to behave like a `Deref` pattern, to be compatible
1357
- // with other `Deref` patterns. This could have been done in `const_to_pat`,
1358
- // but that causes issues with the rest of the matching code.
1359
- // So here, the constructor for a `"foo"` pattern is `&` (represented by
1360
- // `Single`), and has one field. That field has constructor `Str(value)` and no
1361
- // fields.
1362
- // Note: `t` is `str`, not `&str`.
1363
- let subpattern =
1364
- DeconstructedPat :: new ( Str ( * value) , Fields :: empty ( ) , * t, pat. span ) ;
1365
- ctor = Single ;
1366
- fields = Fields :: singleton ( cx, subpattern)
1367
- }
1368
- // All constants that can be structurally matched have already been expanded
1369
- // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
1370
- // opaque.
1371
- _ => {
1372
- ctor = Opaque ;
1373
- fields = Fields :: empty ( ) ;
1374
- }
1318
+ match pat. ty . kind ( ) {
1319
+ ty:: Bool | ty:: Char | ty:: Int ( _) | ty:: Uint ( _) => {
1320
+ ctor = match value. try_eval_bits ( cx. tcx , cx. param_env ) {
1321
+ Some ( bits) => IntRange ( IntRange :: from_bits ( cx. tcx , pat. ty , bits) ) ,
1322
+ None => Opaque ,
1323
+ } ;
1324
+ fields = Fields :: empty ( ) ;
1325
+ }
1326
+ ty:: Float ( ty:: FloatTy :: F32 ) => {
1327
+ ctor = match value. try_eval_bits ( cx. tcx , cx. param_env ) {
1328
+ Some ( bits) => {
1329
+ use rustc_apfloat:: Float ;
1330
+ let value = rustc_apfloat:: ieee:: Single :: from_bits ( bits) ;
1331
+ F32Range ( value, value, RangeEnd :: Included )
1332
+ }
1333
+ None => Opaque ,
1334
+ } ;
1335
+ fields = Fields :: empty ( ) ;
1336
+ }
1337
+ ty:: Float ( ty:: FloatTy :: F64 ) => {
1338
+ ctor = match value. try_eval_bits ( cx. tcx , cx. param_env ) {
1339
+ Some ( bits) => {
1340
+ use rustc_apfloat:: Float ;
1341
+ let value = rustc_apfloat:: ieee:: Double :: from_bits ( bits) ;
1342
+ F64Range ( value, value, RangeEnd :: Included )
1343
+ }
1344
+ None => Opaque ,
1345
+ } ;
1346
+ fields = Fields :: empty ( ) ;
1347
+ }
1348
+ ty:: Ref ( _, t, _) if t. is_str ( ) => {
1349
+ // We want a `&str` constant to behave like a `Deref` pattern, to be compatible
1350
+ // with other `Deref` patterns. This could have been done in `const_to_pat`,
1351
+ // but that causes issues with the rest of the matching code.
1352
+ // So here, the constructor for a `"foo"` pattern is `&` (represented by
1353
+ // `Single`), and has one field. That field has constructor `Str(value)` and no
1354
+ // fields.
1355
+ // Note: `t` is `str`, not `&str`.
1356
+ let subpattern =
1357
+ DeconstructedPat :: new ( Str ( * value) , Fields :: empty ( ) , * t, pat. span ) ;
1358
+ ctor = Single ;
1359
+ fields = Fields :: singleton ( cx, subpattern)
1360
+ }
1361
+ // All constants that can be structurally matched have already been expanded
1362
+ // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
1363
+ // opaque.
1364
+ _ => {
1365
+ ctor = Opaque ;
1366
+ fields = Fields :: empty ( ) ;
1375
1367
}
1376
1368
}
1377
1369
}
1378
- & PatKind :: Range ( box PatRange { lo, hi, end } ) => {
1370
+ PatKind :: Range ( box PatRange { lo, hi, end } ) => {
1371
+ use rustc_apfloat:: Float ;
1379
1372
let ty = lo. ty ( ) ;
1380
- ctor = if let Some ( int_range) = IntRange :: from_range (
1381
- cx. tcx ,
1382
- lo. eval_bits ( cx. tcx , cx. param_env ) ,
1383
- hi. eval_bits ( cx. tcx , cx. param_env ) ,
1384
- ty,
1385
- & end,
1386
- ) {
1387
- IntRange ( int_range)
1388
- } else {
1389
- FloatRange ( lo, hi, end)
1373
+ let lo = lo. try_eval_bits ( cx. tcx , cx. param_env ) . unwrap ( ) ;
1374
+ let hi = hi. try_eval_bits ( cx. tcx , cx. param_env ) . unwrap ( ) ;
1375
+ ctor = match ty. kind ( ) {
1376
+ ty:: Char | ty:: Int ( _) | ty:: Uint ( _) => {
1377
+ IntRange ( IntRange :: from_range ( cx. tcx , lo, hi, ty, * end) )
1378
+ }
1379
+ ty:: Float ( ty:: FloatTy :: F32 ) => {
1380
+ let lo = rustc_apfloat:: ieee:: Single :: from_bits ( lo) ;
1381
+ let hi = rustc_apfloat:: ieee:: Single :: from_bits ( hi) ;
1382
+ F32Range ( lo, hi, * end)
1383
+ }
1384
+ ty:: Float ( ty:: FloatTy :: F64 ) => {
1385
+ let lo = rustc_apfloat:: ieee:: Double :: from_bits ( lo) ;
1386
+ let hi = rustc_apfloat:: ieee:: Double :: from_bits ( hi) ;
1387
+ F64Range ( lo, hi, * end)
1388
+ }
1389
+ _ => bug ! ( "invalid type for range pattern: {}" , ty) ,
1390
1390
} ;
1391
1391
fields = Fields :: empty ( ) ;
1392
1392
}
@@ -1491,14 +1491,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1491
1491
}
1492
1492
}
1493
1493
& Str ( value) => PatKind :: Constant { value } ,
1494
- & FloatRange ( lo, hi, end) => PatKind :: Range ( Box :: new ( PatRange { lo, hi, end } ) ) ,
1495
1494
IntRange ( range) => return range. to_pat ( cx. tcx , self . ty ) ,
1496
1495
Wildcard | NonExhaustive => PatKind :: Wild ,
1497
1496
Missing { .. } => bug ! (
1498
1497
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
1499
1498
`Missing` should have been processed in `apply_constructors`"
1500
1499
) ,
1501
- Opaque | Or => {
1500
+ F32Range ( .. ) | F64Range ( .. ) | Opaque | Or => {
1502
1501
bug ! ( "can't convert to pattern: {:?}" , self )
1503
1502
}
1504
1503
} ;
@@ -1673,11 +1672,8 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
1673
1672
}
1674
1673
write ! ( f, "]" )
1675
1674
}
1676
- & FloatRange ( lo, hi, end) => {
1677
- write ! ( f, "{lo}" ) ?;
1678
- write ! ( f, "{end}" ) ?;
1679
- write ! ( f, "{hi}" )
1680
- }
1675
+ F32Range ( lo, hi, end) => write ! ( f, "{lo}{end}{hi}" ) ,
1676
+ F64Range ( lo, hi, end) => write ! ( f, "{lo}{end}{hi}" ) ,
1681
1677
IntRange ( range) => write ! ( f, "{range:?}" ) , // Best-effort, will render e.g. `false` as `0..=0`
1682
1678
Wildcard | Missing { .. } | NonExhaustive => write ! ( f, "_ : {:?}" , self . ty) ,
1683
1679
Or => {
0 commit comments