4141//! or-patterns; instead we just try the alternatives one-by-one. For details on splitting
4242//! wildcards, see [`Constructor::split`]; for integer ranges, see
4343//! [`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.
4451
4552use std:: cell:: Cell ;
4653use std:: cmp:: { self , max, min, Ordering } ;
@@ -617,6 +624,18 @@ impl Slice {
617624 }
618625}
619626
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+
620639/// A value can be decomposed into a constructor applied to some fields. This struct represents
621640/// the constructor. See also `Fields`.
622641///
@@ -642,10 +661,12 @@ pub(super) enum Constructor<'tcx> {
642661 Str ( mir:: Const < ' tcx > ) ,
643662 /// Array and slice patterns.
644663 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 ) ,
649670 /// Or-pattern.
650671 Or ,
651672 /// Wildcard pattern.
@@ -663,6 +684,9 @@ pub(super) enum Constructor<'tcx> {
663684}
664685
665686impl < ' tcx > Constructor < ' tcx > {
687+ pub ( super ) fn is_wildcard ( & self ) -> bool {
688+ matches ! ( self , Wildcard )
689+ }
666690 pub ( super ) fn is_non_exhaustive ( & self ) -> bool {
667691 matches ! ( self , NonExhaustive )
668692 }
@@ -728,7 +752,7 @@ impl<'tcx> Constructor<'tcx> {
728752 | F32Range ( ..)
729753 | F64Range ( ..)
730754 | Str ( ..)
731- | Opaque
755+ | Opaque ( .. )
732756 | NonExhaustive
733757 | Hidden
734758 | Missing { .. }
@@ -869,8 +893,10 @@ impl<'tcx> Constructor<'tcx> {
869893 }
870894 ( Slice ( self_slice) , Slice ( other_slice) ) => self_slice. is_covered_by ( * other_slice) ,
871895
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 ,
874900
875901 _ => span_bug ! (
876902 pcx. span,
@@ -1083,18 +1109,26 @@ impl ConstructorSet {
10831109 {
10841110 let mut present: SmallVec < [ _ ; 1 ] > = SmallVec :: new ( ) ;
10851111 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+
10881122 match self {
10891123 ConstructorSet :: Single => {
1090- if seen. next ( ) . is_none ( ) {
1124+ if seen. is_empty ( ) {
10911125 missing. push ( Single ) ;
10921126 } else {
10931127 present. push ( Single ) ;
10941128 }
10951129 }
10961130 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 ( ) ;
10981132 let mut skipped_a_hidden_variant = false ;
10991133
11001134 for variant in visible_variants {
@@ -1125,7 +1159,7 @@ impl ConstructorSet {
11251159 ConstructorSet :: Bool => {
11261160 let mut seen_false = false ;
11271161 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 ( ) ) {
11291163 if b {
11301164 seen_true = true ;
11311165 } else {
@@ -1145,7 +1179,7 @@ impl ConstructorSet {
11451179 }
11461180 ConstructorSet :: Integers { range_1, range_2 } => {
11471181 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 ( ) ;
11491183 for ( seen, splitted_range) in range_1. split ( seen_ranges. iter ( ) . cloned ( ) ) {
11501184 match seen {
11511185 Presence :: Unseen => missing. push ( IntRange ( splitted_range) ) ,
@@ -1162,7 +1196,7 @@ impl ConstructorSet {
11621196 }
11631197 }
11641198 & 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 ( ) ) ;
11661200 let base_slice = Slice :: new ( array_len, VarLen ( 0 , 0 ) ) ;
11671201 for ( seen, splitted_slice) in base_slice. split ( seen_slices) {
11681202 let ctor = Slice ( splitted_slice) ;
@@ -1178,7 +1212,7 @@ impl ConstructorSet {
11781212 // unreachable if length != 0.
11791213 // We still gather the seen constructors in `present`, but the only slice that can
11801214 // 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 ( ) ) ;
11821216 let base_slice = Slice :: new ( None , VarLen ( 0 , 0 ) ) ;
11831217 for ( seen, splitted_slice) in base_slice. split ( seen_slices) {
11841218 let ctor = Slice ( splitted_slice) ;
@@ -1194,7 +1228,7 @@ impl ConstructorSet {
11941228 ConstructorSet :: Unlistable => {
11951229 // Since we can't list constructors, we take the ones in the column. This might list
11961230 // some constructors several times but there's not much we can do.
1197- present. extend ( seen. cloned ( ) ) ;
1231+ present. extend ( seen) ;
11981232 missing. push ( NonExhaustive ) ;
11991233 }
12001234 // If `exhaustive_patterns` is disabled and our scrutinee is an empty type, we cannot
@@ -1339,7 +1373,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
13391373 | F32Range ( ..)
13401374 | F64Range ( ..)
13411375 | Str ( ..)
1342- | Opaque
1376+ | Opaque ( .. )
13431377 | NonExhaustive
13441378 | Hidden
13451379 | Missing { .. }
@@ -1470,14 +1504,14 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
14701504 ty:: Bool => {
14711505 ctor = match value. try_eval_bool ( cx. tcx , cx. param_env ) {
14721506 Some ( b) => Bool ( b) ,
1473- None => Opaque ,
1507+ None => Opaque ( OpaqueId :: new ( ) ) ,
14741508 } ;
14751509 fields = Fields :: empty ( ) ;
14761510 }
14771511 ty:: Char | ty:: Int ( _) | ty:: Uint ( _) => {
14781512 ctor = match value. try_eval_bits ( cx. tcx , cx. param_env ) {
14791513 Some ( bits) => IntRange ( IntRange :: from_bits ( cx. tcx , pat. ty , bits) ) ,
1480- None => Opaque ,
1514+ None => Opaque ( OpaqueId :: new ( ) ) ,
14811515 } ;
14821516 fields = Fields :: empty ( ) ;
14831517 }
@@ -1488,7 +1522,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
14881522 let value = rustc_apfloat:: ieee:: Single :: from_bits ( bits) ;
14891523 F32Range ( value, value, RangeEnd :: Included )
14901524 }
1491- None => Opaque ,
1525+ None => Opaque ( OpaqueId :: new ( ) ) ,
14921526 } ;
14931527 fields = Fields :: empty ( ) ;
14941528 }
@@ -1499,7 +1533,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
14991533 let value = rustc_apfloat:: ieee:: Double :: from_bits ( bits) ;
15001534 F64Range ( value, value, RangeEnd :: Included )
15011535 }
1502- None => Opaque ,
1536+ None => Opaque ( OpaqueId :: new ( ) ) ,
15031537 } ;
15041538 fields = Fields :: empty ( ) ;
15051539 }
@@ -1520,7 +1554,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
15201554 // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
15211555 // opaque.
15221556 _ => {
1523- ctor = Opaque ;
1557+ ctor = Opaque ( OpaqueId :: new ( ) ) ;
15241558 fields = Fields :: empty ( ) ;
15251559 }
15261560 }
@@ -1581,7 +1615,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
15811615 fields = Fields :: from_iter ( cx, pats. into_iter ( ) . map ( mkpat) ) ;
15821616 }
15831617 PatKind :: Error ( _) => {
1584- ctor = Opaque ;
1618+ ctor = Opaque ( OpaqueId :: new ( ) ) ;
15851619 fields = Fields :: empty ( ) ;
15861620 }
15871621 }
@@ -1768,7 +1802,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
17681802 F32Range ( lo, hi, end) => write ! ( f, "{lo}{end}{hi}" ) ,
17691803 F64Range ( lo, hi, end) => write ! ( f, "{lo}{end}{hi}" ) ,
17701804 Str ( value) => write ! ( f, "{value}" ) ,
1771- Opaque => write ! ( f, "<constant pattern>" ) ,
1805+ Opaque ( .. ) => write ! ( f, "<constant pattern>" ) ,
17721806 Or => {
17731807 for pat in self . iter_fields ( ) {
17741808 write ! ( f, "{}{:?}" , start_or_continue( " | " ) , pat) ?;
@@ -1898,7 +1932,7 @@ impl<'tcx> WitnessPat<'tcx> {
18981932 "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
18991933 `Missing` should have been processed in `apply_constructors`"
19001934 ) ,
1901- F32Range ( ..) | F64Range ( ..) | Opaque | Or => {
1935+ F32Range ( ..) | F64Range ( ..) | Opaque ( .. ) | Or => {
19021936 bug ! ( "can't convert to pattern: {:?}" , self )
19031937 }
19041938 } ;
0 commit comments