@@ -1132,6 +1132,66 @@ impl<'tcx> Constructor<'tcx> {
1132
1132
}
1133
1133
}
1134
1134
1135
+ /// Returns whether `self` is covered by `other`, ie whether `self` is a subset of `other`. For
1136
+ /// the simple cases, this is simply checking for equality. For the "grouped" constructors,
1137
+ /// this checks for inclusion.
1138
+ fn is_covered_by < ' p > (
1139
+ & self ,
1140
+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
1141
+ other : & Constructor < ' tcx > ,
1142
+ ty : Ty < ' tcx > ,
1143
+ ) -> bool {
1144
+ match ( self , other) {
1145
+ ( Single , Single ) => true ,
1146
+ ( Variant ( self_id) , Variant ( other_id) ) => self_id == other_id,
1147
+
1148
+ ( IntRange ( self_range) , IntRange ( other_range) ) => {
1149
+ if self_range. intersection ( cx. tcx , other_range) . is_some ( ) {
1150
+ // Constructor splitting should ensure that all intersections we encounter
1151
+ // are actually inclusions.
1152
+ assert ! ( self_range. is_subrange( other_range) ) ;
1153
+ true
1154
+ } else {
1155
+ false
1156
+ }
1157
+ }
1158
+ (
1159
+ FloatRange ( self_from, self_to, self_end) ,
1160
+ FloatRange ( other_from, other_to, other_end) ,
1161
+ ) => {
1162
+ match (
1163
+ compare_const_vals ( cx. tcx , self_to, other_to, cx. param_env , ty) ,
1164
+ compare_const_vals ( cx. tcx , self_from, other_from, cx. param_env , ty) ,
1165
+ ) {
1166
+ ( Some ( to) , Some ( from) ) => {
1167
+ ( from == Ordering :: Greater || from == Ordering :: Equal )
1168
+ && ( to == Ordering :: Less
1169
+ || ( other_end == self_end && to == Ordering :: Equal ) )
1170
+ }
1171
+ _ => false ,
1172
+ }
1173
+ }
1174
+ ( Str ( self_val) , Str ( other_val) ) => {
1175
+ // FIXME: there's probably a more direct way of comparing for equality
1176
+ match compare_const_vals ( cx. tcx , self_val, other_val, cx. param_env , ty) {
1177
+ Some ( comparison) => comparison == Ordering :: Equal ,
1178
+ None => false ,
1179
+ }
1180
+ }
1181
+
1182
+ ( Slice ( self_slice) , Slice ( other_slice) ) => {
1183
+ other_slice. pattern_kind ( ) . covers_length ( self_slice. arity ( ) )
1184
+ }
1185
+
1186
+ // We are trying to inspect an opaque constant. Thus we skip the row.
1187
+ ( Opaque , _) | ( _, Opaque ) => false ,
1188
+ // Only a wildcard pattern can match the special extra constructor.
1189
+ ( NonExhaustive , _) => false ,
1190
+
1191
+ _ => bug ! ( "trying to compare incompatible constructors {:?} and {:?}" , self , other) ,
1192
+ }
1193
+ }
1194
+
1135
1195
/// Apply a constructor to a list of patterns, yielding a new pattern. `pats`
1136
1196
/// must have as many elements as this constructor's arity.
1137
1197
///
@@ -1461,6 +1521,41 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1461
1521
}
1462
1522
}
1463
1523
1524
+ /// Replaces contained fields with the arguments of the given pattern. Only use on a pattern
1525
+ /// that is compatible with the constructor used to build `self`.
1526
+ /// This is meant to be used on the result of `Fields::wildcards()`. The idea is that
1527
+ /// `wildcards` constructs a list of fields where all entries are wildcards, and the pattern
1528
+ /// provided to this function fills some of the fields with non-wildcards.
1529
+ /// In the following example `Fields::wildcards` would return `[_, _, _, _]`. If we call
1530
+ /// `replace_with_pattern_arguments` on it with the pattern, the result will be `[Some(0), _,
1531
+ /// _, _]`.
1532
+ /// ```rust
1533
+ /// let x: [Option<u8>; 4] = foo();
1534
+ /// match x {
1535
+ /// [Some(0), ..] => {}
1536
+ /// }
1537
+ /// ```
1538
+ fn replace_with_pattern_arguments ( & self , pat : & ' p Pat < ' tcx > ) -> Self {
1539
+ match pat. kind . as_ref ( ) {
1540
+ PatKind :: Deref { subpattern } => Self :: from_single_pattern ( subpattern) ,
1541
+ PatKind :: Leaf { subpatterns } | PatKind :: Variant { subpatterns, .. } => {
1542
+ self . replace_with_fieldpats ( subpatterns)
1543
+ }
1544
+ PatKind :: Array { prefix, suffix, .. } | PatKind :: Slice { prefix, suffix, .. } => {
1545
+ // Number of subpatterns for the constructor
1546
+ let ctor_arity = self . len ( ) ;
1547
+
1548
+ // Replace the prefix and the suffix with the given patterns, leaving wildcards in
1549
+ // the middle if there was a subslice pattern `..`.
1550
+ let prefix = prefix. iter ( ) . enumerate ( ) ;
1551
+ let suffix =
1552
+ suffix. iter ( ) . enumerate ( ) . map ( |( i, p) | ( ctor_arity - suffix. len ( ) + i, p) ) ;
1553
+ self . replace_fields_indexed ( prefix. chain ( suffix) )
1554
+ }
1555
+ _ => self . clone ( ) ,
1556
+ }
1557
+ }
1558
+
1464
1559
fn push_on_patstack ( self , stack : & [ & ' p Pat < ' tcx > ] ) -> PatStack < ' p , ' tcx > {
1465
1560
let pats: SmallVec < _ > = match self {
1466
1561
Fields :: Slice ( pats) => pats. iter ( ) . chain ( stack. iter ( ) . copied ( ) ) . collect ( ) ,
@@ -2535,89 +2630,21 @@ fn specialize_one_pattern<'p, 'tcx>(
2535
2630
return Some ( ctor_wild_subpatterns. clone ( ) ) ;
2536
2631
}
2537
2632
2538
- let ty = pat. ty ;
2539
- // `unwrap` is safe because `pat` is not a wildcard.
2540
- let pat_ctor = pat_constructor ( cx. tcx , cx. param_env , pat) . unwrap ( ) ;
2541
-
2542
- let ctor_covered_by_pat = match ( ctor, & pat_ctor) {
2543
- ( Single , Single ) => true ,
2544
- ( Variant ( ctor_id) , Variant ( pat_id) ) => ctor_id == pat_id,
2545
-
2546
- ( IntRange ( ctor_range) , IntRange ( pat_range) ) => {
2547
- if ctor_range. intersection ( cx. tcx , pat_range) . is_some ( ) {
2548
- // Constructor splitting should ensure that all intersections we encounter
2549
- // are actually inclusions.
2550
- assert ! ( ctor_range. is_subrange( pat_range) ) ;
2551
- true
2552
- } else {
2553
- false
2554
- }
2633
+ // We return `None` if `ctor` is not covered by `pat`. If `ctor` is known to be derived from
2634
+ // `pat` then we don't need to check; otherwise, we compute the constructor of `pat` and check
2635
+ // for constructor inclusion.
2636
+ // Note that this shortcut is also necessary for correctness: a pattern should always be
2637
+ // specializable with its own constructor, even in cases where we refuse to inspect values like
2638
+ // opaque constants.
2639
+ if !is_its_own_ctor {
2640
+ // `unwrap` is safe because `pat` is not a wildcard.
2641
+ let pat_ctor = pat_constructor ( cx. tcx , cx. param_env , pat) . unwrap ( ) ;
2642
+ if !ctor. is_covered_by ( cx, & pat_ctor, pat. ty ) {
2643
+ return None ;
2555
2644
}
2556
- ( FloatRange ( ctor_from, ctor_to, ctor_end) , FloatRange ( pat_from, pat_to, pat_end) ) => {
2557
- let to = compare_const_vals ( cx. tcx , ctor_to, pat_to, cx. param_env , ty) ?;
2558
- let from = compare_const_vals ( cx. tcx , ctor_from, pat_from, cx. param_env , ty) ?;
2559
- ( from == Ordering :: Greater || from == Ordering :: Equal )
2560
- && ( to == Ordering :: Less || ( pat_end == ctor_end && to == Ordering :: Equal ) )
2561
- }
2562
- ( Str ( ctor_val) , Str ( pat_val) ) => {
2563
- // FIXME: there's probably a more direct way of comparing for equality
2564
- let comparison = compare_const_vals ( cx. tcx , ctor_val, pat_val, cx. param_env , ty) ?;
2565
- comparison == Ordering :: Equal
2566
- }
2567
-
2568
- ( Slice ( ctor_slice) , Slice ( pat_slice) ) => {
2569
- pat_slice. pattern_kind ( ) . covers_length ( ctor_slice. arity ( ) )
2570
- }
2571
-
2572
- // Only a wildcard pattern can match an opaque constant, unless we're specializing the
2573
- // value against its own constructor. That happens when we call
2574
- // `v.specialize_constructor(ctor)` with `ctor` obtained from `pat_constructor(v.head())`.
2575
- // For example, in the following match, when we are dealing with the third branch, we will
2576
- // specialize with an `Opaque` ctor. We want to ignore the second branch because opaque
2577
- // constants should not be inspected, but we don't want to ignore the current (third)
2578
- // branch, as that would cause us to always conclude that such a branch is unreachable.
2579
- // ```rust
2580
- // #[derive(PartialEq)]
2581
- // struct Foo(i32);
2582
- // impl Eq for Foo {}
2583
- // const FOO: Foo = Foo(42);
2584
- //
2585
- // match (Foo(0), true) {
2586
- // (_, true) => {}
2587
- // (FOO, true) => {}
2588
- // (FOO, false) => {}
2589
- // }
2590
- // ```
2591
- ( Opaque , Opaque ) if is_its_own_ctor => true ,
2592
- // We are trying to inspect an opaque constant. Thus we skip the row.
2593
- ( Opaque , _) | ( _, Opaque ) => false ,
2594
- // Only a wildcard pattern can match the special extra constructor.
2595
- ( NonExhaustive , _) => false ,
2596
-
2597
- _ => bug ! ( "trying to specialize pattern {:?} with constructor {:?}" , pat, ctor) ,
2598
- } ;
2599
-
2600
- if !ctor_covered_by_pat {
2601
- return None ;
2602
2645
}
2603
2646
2604
- let fields = match pat. kind . as_ref ( ) {
2605
- PatKind :: Deref { subpattern } => Fields :: from_single_pattern ( subpattern) ,
2606
- PatKind :: Leaf { subpatterns } | PatKind :: Variant { subpatterns, .. } => {
2607
- ctor_wild_subpatterns. replace_with_fieldpats ( subpatterns)
2608
- }
2609
- PatKind :: Array { prefix, suffix, .. } | PatKind :: Slice { prefix, suffix, .. } => {
2610
- // Number of subpatterns for the constructor
2611
- let ctor_arity = ctor_wild_subpatterns. len ( ) ;
2612
-
2613
- // Replace the prefix and the suffix with the given patterns, leaving wildcards in
2614
- // the middle if there was a subslice pattern `..`.
2615
- let prefix = prefix. iter ( ) . enumerate ( ) ;
2616
- let suffix = suffix. iter ( ) . enumerate ( ) . map ( |( i, p) | ( ctor_arity - suffix. len ( ) + i, p) ) ;
2617
- ctor_wild_subpatterns. replace_fields_indexed ( prefix. chain ( suffix) )
2618
- }
2619
- _ => ctor_wild_subpatterns. clone ( ) ,
2620
- } ;
2647
+ let fields = ctor_wild_subpatterns. replace_with_pattern_arguments ( pat) ;
2621
2648
2622
2649
debug ! ( "specialize({:#?}, {:#?}, {:#?}) = {:#?}" , pat, ctor, ctor_wild_subpatterns, fields) ;
2623
2650
0 commit comments