@@ -1132,6 +1132,66 @@ impl<'tcx> Constructor<'tcx> {
11321132 }
11331133 }
11341134
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+
11351195 /// Apply a constructor to a list of patterns, yielding a new pattern. `pats`
11361196 /// must have as many elements as this constructor's arity.
11371197 ///
@@ -1461,6 +1521,41 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
14611521 }
14621522 }
14631523
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+
14641559 fn push_on_patstack ( self , stack : & [ & ' p Pat < ' tcx > ] ) -> PatStack < ' p , ' tcx > {
14651560 let pats: SmallVec < _ > = match self {
14661561 Fields :: Slice ( pats) => pats. iter ( ) . chain ( stack. iter ( ) . copied ( ) ) . collect ( ) ,
@@ -2535,89 +2630,21 @@ fn specialize_one_pattern<'p, 'tcx>(
25352630 return Some ( ctor_wild_subpatterns. clone ( ) ) ;
25362631 }
25372632
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 ;
25552644 }
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 ;
26022645 }
26032646
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) ;
26212648
26222649 debug ! ( "specialize({:#?}, {:#?}, {:#?}) = {:#?}" , pat, ctor, ctor_wild_subpatterns, fields) ;
26232650
0 commit comments