@@ -597,6 +597,14 @@ enum Constructor<'tcx> {
597597 FloatRange ( & ' tcx ty:: Const < ' tcx > , & ' tcx ty:: Const < ' tcx > , RangeEnd ) ,
598598 /// Array patterns of length `n`.
599599 FixedLenSlice ( u64 ) ,
600+ /// Array patterns of length `len`, but for which we only care about the `prefix` first values
601+ /// and the `suffix` last values. This avoids unnecessarily going through values we know to be
602+ /// uninteresting, which can be a major problem for large arrays.
603+ LazyFixedLenSlice {
604+ len : u64 , // The actual length of the array
605+ prefix : u64 ,
606+ suffix : u64 ,
607+ } ,
600608 /// Slice patterns. Captures any array constructor of `length >= i + j`.
601609 VarLenSlice ( u64 , u64 ) ,
602610 /// Fake extra constructor for enums that aren't allowed to be matched exhaustively.
@@ -606,7 +614,7 @@ enum Constructor<'tcx> {
606614impl < ' tcx > Constructor < ' tcx > {
607615 fn is_slice ( & self ) -> bool {
608616 match self {
609- FixedLenSlice { .. } | VarLenSlice { .. } => true ,
617+ FixedLenSlice { .. } | LazyFixedLenSlice { .. } | VarLenSlice { .. } => true ,
610618 _ => false ,
611619 }
612620 }
@@ -635,9 +643,9 @@ impl<'tcx> Constructor<'tcx> {
635643 Single | Variant ( _) | ConstantValue ( ..) | FloatRange ( ..) => {
636644 if other_ctors. iter ( ) . any ( |c| c == self ) { vec ! [ ] } else { vec ! [ self . clone( ) ] }
637645 }
638- & FixedLenSlice ( self_len) => {
646+ & FixedLenSlice ( self_len) | & LazyFixedLenSlice { len : self_len , .. } => {
639647 let overlaps = |c : & Constructor < ' _ > | match * c {
640- FixedLenSlice ( other_len ) => other_len == self_len,
648+ FixedLenSlice ( len ) | LazyFixedLenSlice { len , .. } => len == self_len,
641649 VarLenSlice ( prefix, suffix) => prefix + suffix <= self_len,
642650 _ => false ,
643651 } ;
@@ -657,7 +665,12 @@ impl<'tcx> Constructor<'tcx> {
657665 // Compute `pos_ctor \ neg_ctor`.
658666 match pos_ctor {
659667 FixedLenSlice ( pos_len) => match * neg_ctor {
660- FixedLenSlice ( neg_len) if neg_len == pos_len => smallvec ! [ ] ,
668+ FixedLenSlice ( neg_len)
669+ | LazyFixedLenSlice { len : neg_len, .. }
670+ if neg_len == pos_len =>
671+ {
672+ smallvec ! [ ]
673+ }
661674 VarLenSlice ( neg_prefix, neg_suffix)
662675 if neg_prefix + neg_suffix <= pos_len =>
663676 {
@@ -668,7 +681,10 @@ impl<'tcx> Constructor<'tcx> {
668681 VarLenSlice ( pos_prefix, pos_suffix) => {
669682 let pos_len = pos_prefix + pos_suffix;
670683 match * neg_ctor {
671- FixedLenSlice ( neg_len) if neg_len >= pos_len => {
684+ FixedLenSlice ( neg_len)
685+ | LazyFixedLenSlice { len : neg_len, .. }
686+ if neg_len >= pos_len =>
687+ {
672688 ( pos_len..neg_len)
673689 . map ( FixedLenSlice )
674690 // We know that `neg_len + 1 >= pos_len >=
@@ -799,7 +815,7 @@ impl<'tcx> Constructor<'tcx> {
799815 }
800816 _ => vec ! [ ] ,
801817 } ,
802- FixedLenSlice ( _) | VarLenSlice ( ..) => match ty. kind {
818+ FixedLenSlice ( _) | LazyFixedLenSlice { .. } | VarLenSlice ( ..) => match ty. kind {
803819 ty:: Slice ( ty) | ty:: Array ( ty, _) => {
804820 let arity = self . arity ( cx, ty) ;
805821 ( 0 ..arity) . map ( |_| Pat :: wildcard_from_ty ( ty) ) . collect ( )
@@ -830,7 +846,9 @@ impl<'tcx> Constructor<'tcx> {
830846 _ => 0 ,
831847 } ,
832848 FixedLenSlice ( length) => * length,
833- VarLenSlice ( prefix, suffix) => prefix + suffix,
849+ VarLenSlice ( prefix, suffix) | LazyFixedLenSlice { prefix, suffix, .. } => {
850+ prefix + suffix
851+ }
834852 ConstantValue ( ..) | FloatRange ( ..) | IntRange ( ..) | NonExhaustive => 0 ,
835853 }
836854 }
@@ -888,8 +906,11 @@ impl<'tcx> Constructor<'tcx> {
888906 FixedLenSlice ( _) => {
889907 PatKind :: Slice { prefix : subpatterns. collect ( ) , slice : None , suffix : vec ! [ ] }
890908 }
891- & VarLenSlice ( prefix_len, _) => {
892- let prefix = subpatterns. by_ref ( ) . take ( prefix_len as usize ) . collect ( ) ;
909+ LazyFixedLenSlice { len, prefix, suffix } if prefix + suffix == * len => {
910+ PatKind :: Slice { prefix : subpatterns. collect ( ) , slice : None , suffix : vec ! [ ] }
911+ }
912+ VarLenSlice ( prefix, _) | LazyFixedLenSlice { prefix, .. } => {
913+ let prefix = subpatterns. by_ref ( ) . take ( * prefix as usize ) . collect ( ) ;
893914 let suffix = subpatterns. collect ( ) ;
894915 let wild = Pat :: wildcard_from_ty ( ty) ;
895916 PatKind :: Slice { prefix, slice : Some ( wild) , suffix }
@@ -1106,7 +1127,11 @@ fn all_constructors<'a, 'tcx>(
11061127 }
11071128 ty:: Array ( ref sub_ty, len) if len. try_eval_usize ( cx. tcx , cx. param_env ) . is_some ( ) => {
11081129 let len = len. eval_usize ( cx. tcx , cx. param_env ) ;
1109- if len != 0 && cx. is_uninhabited ( sub_ty) { vec ! [ ] } else { vec ! [ FixedLenSlice ( len) ] }
1130+ if len != 0 && cx. is_uninhabited ( sub_ty) {
1131+ vec ! [ ]
1132+ } else {
1133+ vec ! [ LazyFixedLenSlice { len, prefix: 0 , suffix: 0 } ]
1134+ }
11101135 }
11111136 // Treat arrays of a constant but unknown length like slices.
11121137 ty:: Array ( ref sub_ty, _) | ty:: Slice ( ref sub_ty) => {
@@ -1694,10 +1719,19 @@ fn pat_constructor<'tcx>(
16941719 Some ( FloatRange ( lo, hi, end) )
16951720 }
16961721 }
1697- PatKind :: Array { .. } => match pat. ty . kind {
1698- ty:: Array ( _, length) => Some ( FixedLenSlice ( length. eval_usize ( tcx, param_env) ) ) ,
1699- _ => span_bug ! ( pat. span, "bad ty {:?} for array pattern" , pat. ty) ,
1700- } ,
1722+ PatKind :: Array { ref prefix, ref slice, ref suffix } => {
1723+ let len = match pat. ty . kind {
1724+ ty:: Array ( _, length) => length. eval_usize ( tcx, param_env) ,
1725+ _ => span_bug ! ( pat. span, "bad ty {:?} for array pattern" , pat. ty) ,
1726+ } ;
1727+ let prefix = prefix. len ( ) as u64 ;
1728+ let suffix = suffix. len ( ) as u64 ;
1729+ if slice. is_some ( ) {
1730+ Some ( LazyFixedLenSlice { len, prefix, suffix } )
1731+ } else {
1732+ Some ( FixedLenSlice ( len) )
1733+ }
1734+ }
17011735 PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
17021736 let prefix = prefix. len ( ) as u64 ;
17031737 let suffix = suffix. len ( ) as u64 ;
@@ -1833,6 +1867,7 @@ fn split_grouped_constructors<'p, 'tcx>(
18331867) -> Vec < Constructor < ' tcx > > {
18341868 let ty = pcx. ty ;
18351869 let mut split_ctors = Vec :: with_capacity ( ctors. len ( ) ) ;
1870+ debug ! ( "split_grouped_constructors({:#?}, {:#?})" , matrix, ctors) ;
18361871
18371872 for ctor in ctors. into_iter ( ) {
18381873 match ctor {
@@ -1920,7 +1955,8 @@ fn split_grouped_constructors<'p, 'tcx>(
19201955 . map ( IntRange ) ,
19211956 ) ;
19221957 }
1923- VarLenSlice ( self_prefix, self_suffix) => {
1958+ VarLenSlice ( self_prefix, self_suffix)
1959+ | LazyFixedLenSlice { prefix : self_prefix, suffix : self_suffix, .. } => {
19241960 // The exhaustiveness-checking paper does not include any details on
19251961 // checking variable-length slice patterns. However, they are matched
19261962 // by an infinite collection of fixed-length array patterns.
@@ -2005,11 +2041,13 @@ fn split_grouped_constructors<'p, 'tcx>(
20052041 _ => { }
20062042 }
20072043 }
2008- PatKind :: Slice { ref prefix, slice : None , ref suffix } => {
2044+ PatKind :: Slice { ref prefix, slice : None , ref suffix }
2045+ | PatKind :: Array { ref prefix, slice : None , ref suffix } => {
20092046 let fixed_len = prefix. len ( ) as u64 + suffix. len ( ) as u64 ;
20102047 max_fixed_len = cmp:: max ( max_fixed_len, fixed_len) ;
20112048 }
2012- PatKind :: Slice { ref prefix, slice : Some ( _) , ref suffix } => {
2049+ PatKind :: Slice { ref prefix, slice : Some ( _) , ref suffix }
2050+ | PatKind :: Array { ref prefix, slice : Some ( _) , ref suffix } => {
20132051 max_prefix_len = cmp:: max ( max_prefix_len, prefix. len ( ) as u64 ) ;
20142052 max_suffix_len = cmp:: max ( max_suffix_len, suffix. len ( ) as u64 ) ;
20152053 }
@@ -2027,20 +2065,37 @@ fn split_grouped_constructors<'p, 'tcx>(
20272065 max_prefix_len = max_fixed_len + 1 - max_suffix_len;
20282066 }
20292067
2030- // `ctor` originally covered the range `(self_prefix + self_suffix..infinity)`. We
2031- // now split it into two: lengths smaller than `max_prefix_len + max_suffix_len`
2032- // are treated independently as fixed-lengths slices, and lengths above are
2033- // captured by a final VarLenSlice constructor.
2034- split_ctors. extend (
2035- ( self_prefix + self_suffix..max_prefix_len + max_suffix_len) . map ( FixedLenSlice ) ,
2036- ) ;
2037- split_ctors. push ( VarLenSlice ( max_prefix_len, max_suffix_len) ) ;
2068+ match ctor {
2069+ LazyFixedLenSlice { len, .. } => {
2070+ if max_prefix_len + max_suffix_len < len {
2071+ split_ctors. push ( LazyFixedLenSlice {
2072+ len,
2073+ prefix : max_prefix_len,
2074+ suffix : max_suffix_len,
2075+ } ) ;
2076+ } else {
2077+ split_ctors. push ( FixedLenSlice ( len) ) ;
2078+ }
2079+ }
2080+ _ => {
2081+ // `ctor` originally covered the range `(self_prefix + self_suffix..infinity)`. We
2082+ // now split it into two: lengths smaller than `max_prefix_len + max_suffix_len`
2083+ // are treated independently as fixed-lengths slices, and lengths above are
2084+ // captured by a final VarLenSlice constructor.
2085+ split_ctors. extend (
2086+ ( self_prefix + self_suffix..max_prefix_len + max_suffix_len)
2087+ . map ( FixedLenSlice ) ,
2088+ ) ;
2089+ split_ctors. push ( VarLenSlice ( max_prefix_len, max_suffix_len) ) ;
2090+ }
2091+ }
20382092 }
20392093 // Any other constructor can be used unchanged.
20402094 _ => split_ctors. push ( ctor) ,
20412095 }
20422096 }
20432097
2098+ debug ! ( "split_grouped_constructors(..)={:#?}" , split_ctors) ;
20442099 split_ctors
20452100}
20462101
@@ -2252,7 +2307,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
22522307
22532308 PatKind :: Array { ref prefix, ref slice, ref suffix }
22542309 | PatKind :: Slice { ref prefix, ref slice, ref suffix } => match * constructor {
2255- FixedLenSlice ( ..) | VarLenSlice ( ..) => {
2310+ FixedLenSlice ( ..) | LazyFixedLenSlice { .. } | VarLenSlice ( ..) => {
22562311 let pat_len = prefix. len ( ) + suffix. len ( ) ;
22572312 if let Some ( slice_count) = ctor_wild_subpatterns. len ( ) . checked_sub ( pat_len) {
22582313 if slice_count == 0 || slice. is_some ( ) {
0 commit comments