41
41
//! or-patterns; instead we just try the alternatives one-by-one. For details on splitting
42
42
//! wildcards, see [`Constructor::split`]; for integer ranges, see
43
43
//! [`IntRange::split`]; for slices, see [`Slice::split`].
44
+ //!
45
+ //! ## Opaque patterns
46
+ //!
47
+ //! Some patterns, such as TODO, cannot be inspected, which we handle with `Constructor::Opaque`.
48
+ //! Since we know nothing of these patterns, we assume they never cover each other. In order to
49
+ //! respect the invariants of [`SplitConstructorSet`], we give each `Opaque` constructor a unique id
50
+ //! so we can recognize it.
44
51
45
52
use std:: cell:: Cell ;
46
53
use std:: cmp:: { self , max, min, Ordering } ;
@@ -617,6 +624,18 @@ impl Slice {
617
624
}
618
625
}
619
626
627
+ /// A globally unique id to distinguish `Opaque` patterns.
628
+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
629
+ pub ( super ) struct OpaqueId ( u32 ) ;
630
+
631
+ impl OpaqueId {
632
+ fn new ( ) -> Self {
633
+ use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
634
+ static OPAQUE_ID : AtomicU32 = AtomicU32 :: new ( 0 ) ;
635
+ OpaqueId ( OPAQUE_ID . fetch_add ( 1 , Ordering :: SeqCst ) )
636
+ }
637
+ }
638
+
620
639
/// A value can be decomposed into a constructor applied to some fields. This struct represents
621
640
/// the constructor. See also `Fields`.
622
641
///
@@ -642,10 +661,12 @@ pub(super) enum Constructor<'tcx> {
642
661
Str ( mir:: Const < ' tcx > ) ,
643
662
/// Array and slice patterns.
644
663
Slice ( Slice ) ,
645
- /// Constants that must not be matched structurally. They are treated as black
646
- /// boxes for the purposes of exhaustiveness: we must not inspect them, and they
647
- /// don't count towards making a match exhaustive.
648
- Opaque ,
664
+ /// Constants that must not be matched structurally. They are treated as black boxes for the
665
+ /// purposes of exhaustiveness: we must not inspect them, and they don't count towards making a
666
+ /// match exhaustive.
667
+ /// Carries an id that must be unique within a match. We need this to ensure the invariants of
668
+ /// [`SplitConstructorSet`].
669
+ Opaque ( OpaqueId ) ,
649
670
/// Or-pattern.
650
671
Or ,
651
672
/// Wildcard pattern.
@@ -663,6 +684,9 @@ pub(super) enum Constructor<'tcx> {
663
684
}
664
685
665
686
impl < ' tcx > Constructor < ' tcx > {
687
+ pub ( super ) fn is_wildcard ( & self ) -> bool {
688
+ matches ! ( self , Wildcard )
689
+ }
666
690
pub ( super ) fn is_non_exhaustive ( & self ) -> bool {
667
691
matches ! ( self , NonExhaustive )
668
692
}
@@ -728,7 +752,7 @@ impl<'tcx> Constructor<'tcx> {
728
752
| F32Range ( ..)
729
753
| F64Range ( ..)
730
754
| Str ( ..)
731
- | Opaque
755
+ | Opaque ( .. )
732
756
| NonExhaustive
733
757
| Hidden
734
758
| Missing { .. }
@@ -869,8 +893,10 @@ impl<'tcx> Constructor<'tcx> {
869
893
}
870
894
( Slice ( self_slice) , Slice ( other_slice) ) => self_slice. is_covered_by ( * other_slice) ,
871
895
872
- // We are trying to inspect an opaque constant. Thus we skip the row.
873
- ( Opaque , _) | ( _, Opaque ) => false ,
896
+ // Opaque constructors don't interact with anything unless they come from the
897
+ // syntactically identical pattern.
898
+ ( Opaque ( self_id) , Opaque ( other_id) ) => self_id == other_id,
899
+ ( Opaque ( ..) , _) | ( _, Opaque ( ..) ) => false ,
874
900
875
901
_ => span_bug ! (
876
902
pcx. span,
@@ -1083,18 +1109,26 @@ impl ConstructorSet {
1083
1109
{
1084
1110
let mut present: SmallVec < [ _ ; 1 ] > = SmallVec :: new ( ) ;
1085
1111
let mut missing = Vec :: new ( ) ;
1086
- // Constructors in `ctors`, except wildcards.
1087
- let mut seen = ctors. filter ( |c| !( matches ! ( c, Opaque | Wildcard ) ) ) ;
1112
+ // Constructors in `ctors`, except wildcards and opaques.
1113
+ let mut seen = Vec :: new ( ) ;
1114
+ for ctor in ctors. cloned ( ) {
1115
+ if let Constructor :: Opaque ( ..) = ctor {
1116
+ present. push ( ctor) ;
1117
+ } else if !ctor. is_wildcard ( ) {
1118
+ seen. push ( ctor) ;
1119
+ }
1120
+ }
1121
+
1088
1122
match self {
1089
1123
ConstructorSet :: Single => {
1090
- if seen. next ( ) . is_none ( ) {
1124
+ if seen. is_empty ( ) {
1091
1125
missing. push ( Single ) ;
1092
1126
} else {
1093
1127
present. push ( Single ) ;
1094
1128
}
1095
1129
}
1096
1130
ConstructorSet :: Variants { visible_variants, hidden_variants, non_exhaustive } => {
1097
- let seen_set: FxHashSet < _ > = seen. map ( |c| c. as_variant ( ) . unwrap ( ) ) . collect ( ) ;
1131
+ let seen_set: FxHashSet < _ > = seen. iter ( ) . map ( |c| c. as_variant ( ) . unwrap ( ) ) . collect ( ) ;
1098
1132
let mut skipped_a_hidden_variant = false ;
1099
1133
1100
1134
for variant in visible_variants {
@@ -1125,7 +1159,7 @@ impl ConstructorSet {
1125
1159
ConstructorSet :: Bool => {
1126
1160
let mut seen_false = false ;
1127
1161
let mut seen_true = false ;
1128
- for b in seen. map ( |ctor| ctor. as_bool ( ) . unwrap ( ) ) {
1162
+ for b in seen. iter ( ) . map ( |ctor| ctor. as_bool ( ) . unwrap ( ) ) {
1129
1163
if b {
1130
1164
seen_true = true ;
1131
1165
} else {
@@ -1145,7 +1179,7 @@ impl ConstructorSet {
1145
1179
}
1146
1180
ConstructorSet :: Integers { range_1, range_2 } => {
1147
1181
let seen_ranges: Vec < _ > =
1148
- seen. map ( |ctor| ctor. as_int_range ( ) . unwrap ( ) . clone ( ) ) . collect ( ) ;
1182
+ seen. iter ( ) . map ( |ctor| ctor. as_int_range ( ) . unwrap ( ) . clone ( ) ) . collect ( ) ;
1149
1183
for ( seen, splitted_range) in range_1. split ( seen_ranges. iter ( ) . cloned ( ) ) {
1150
1184
match seen {
1151
1185
Presence :: Unseen => missing. push ( IntRange ( splitted_range) ) ,
@@ -1162,7 +1196,7 @@ impl ConstructorSet {
1162
1196
}
1163
1197
}
1164
1198
& ConstructorSet :: Slice ( array_len) => {
1165
- let seen_slices = seen. map ( |c| c. as_slice ( ) . unwrap ( ) ) ;
1199
+ let seen_slices = seen. iter ( ) . map ( |c| c. as_slice ( ) . unwrap ( ) ) ;
1166
1200
let base_slice = Slice :: new ( array_len, VarLen ( 0 , 0 ) ) ;
1167
1201
for ( seen, splitted_slice) in base_slice. split ( seen_slices) {
1168
1202
let ctor = Slice ( splitted_slice) ;
@@ -1178,7 +1212,7 @@ impl ConstructorSet {
1178
1212
// unreachable if length != 0.
1179
1213
// We still gather the seen constructors in `present`, but the only slice that can
1180
1214
// go in `missing` is `[]`.
1181
- let seen_slices = seen. map ( |c| c. as_slice ( ) . unwrap ( ) ) ;
1215
+ let seen_slices = seen. iter ( ) . map ( |c| c. as_slice ( ) . unwrap ( ) ) ;
1182
1216
let base_slice = Slice :: new ( None , VarLen ( 0 , 0 ) ) ;
1183
1217
for ( seen, splitted_slice) in base_slice. split ( seen_slices) {
1184
1218
let ctor = Slice ( splitted_slice) ;
@@ -1194,7 +1228,7 @@ impl ConstructorSet {
1194
1228
ConstructorSet :: Unlistable => {
1195
1229
// Since we can't list constructors, we take the ones in the column. This might list
1196
1230
// some constructors several times but there's not much we can do.
1197
- present. extend ( seen. cloned ( ) ) ;
1231
+ present. extend ( seen) ;
1198
1232
missing. push ( NonExhaustive ) ;
1199
1233
}
1200
1234
// If `exhaustive_patterns` is disabled and our scrutinee is an empty type, we cannot
@@ -1339,7 +1373,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1339
1373
| F32Range ( ..)
1340
1374
| F64Range ( ..)
1341
1375
| Str ( ..)
1342
- | Opaque
1376
+ | Opaque ( .. )
1343
1377
| NonExhaustive
1344
1378
| Hidden
1345
1379
| Missing { .. }
@@ -1470,14 +1504,14 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1470
1504
ty:: Bool => {
1471
1505
ctor = match value. try_eval_bool ( cx. tcx , cx. param_env ) {
1472
1506
Some ( b) => Bool ( b) ,
1473
- None => Opaque ,
1507
+ None => Opaque ( OpaqueId :: new ( ) ) ,
1474
1508
} ;
1475
1509
fields = Fields :: empty ( ) ;
1476
1510
}
1477
1511
ty:: Char | ty:: Int ( _) | ty:: Uint ( _) => {
1478
1512
ctor = match value. try_eval_bits ( cx. tcx , cx. param_env ) {
1479
1513
Some ( bits) => IntRange ( IntRange :: from_bits ( cx. tcx , pat. ty , bits) ) ,
1480
- None => Opaque ,
1514
+ None => Opaque ( OpaqueId :: new ( ) ) ,
1481
1515
} ;
1482
1516
fields = Fields :: empty ( ) ;
1483
1517
}
@@ -1488,7 +1522,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1488
1522
let value = rustc_apfloat:: ieee:: Single :: from_bits ( bits) ;
1489
1523
F32Range ( value, value, RangeEnd :: Included )
1490
1524
}
1491
- None => Opaque ,
1525
+ None => Opaque ( OpaqueId :: new ( ) ) ,
1492
1526
} ;
1493
1527
fields = Fields :: empty ( ) ;
1494
1528
}
@@ -1499,7 +1533,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1499
1533
let value = rustc_apfloat:: ieee:: Double :: from_bits ( bits) ;
1500
1534
F64Range ( value, value, RangeEnd :: Included )
1501
1535
}
1502
- None => Opaque ,
1536
+ None => Opaque ( OpaqueId :: new ( ) ) ,
1503
1537
} ;
1504
1538
fields = Fields :: empty ( ) ;
1505
1539
}
@@ -1520,7 +1554,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1520
1554
// into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
1521
1555
// opaque.
1522
1556
_ => {
1523
- ctor = Opaque ;
1557
+ ctor = Opaque ( OpaqueId :: new ( ) ) ;
1524
1558
fields = Fields :: empty ( ) ;
1525
1559
}
1526
1560
}
@@ -1581,7 +1615,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
1581
1615
fields = Fields :: from_iter ( cx, pats. into_iter ( ) . map ( mkpat) ) ;
1582
1616
}
1583
1617
PatKind :: Error ( _) => {
1584
- ctor = Opaque ;
1618
+ ctor = Opaque ( OpaqueId :: new ( ) ) ;
1585
1619
fields = Fields :: empty ( ) ;
1586
1620
}
1587
1621
}
@@ -1768,7 +1802,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
1768
1802
F32Range ( lo, hi, end) => write ! ( f, "{lo}{end}{hi}" ) ,
1769
1803
F64Range ( lo, hi, end) => write ! ( f, "{lo}{end}{hi}" ) ,
1770
1804
Str ( value) => write ! ( f, "{value}" ) ,
1771
- Opaque => write ! ( f, "<constant pattern>" ) ,
1805
+ Opaque ( .. ) => write ! ( f, "<constant pattern>" ) ,
1772
1806
Or => {
1773
1807
for pat in self . iter_fields ( ) {
1774
1808
write ! ( f, "{}{:?}" , start_or_continue( " | " ) , pat) ?;
@@ -1898,7 +1932,7 @@ impl<'tcx> WitnessPat<'tcx> {
1898
1932
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
1899
1933
`Missing` should have been processed in `apply_constructors`"
1900
1934
) ,
1901
- F32Range ( ..) | F64Range ( ..) | Opaque | Or => {
1935
+ F32Range ( ..) | F64Range ( ..) | Opaque ( .. ) | Or => {
1902
1936
bug ! ( "can't convert to pattern: {:?}" , self )
1903
1937
}
1904
1938
} ;
0 commit comments