@@ -597,6 +597,14 @@ enum Constructor<'tcx> {
597
597
FloatRange ( & ' tcx ty:: Const < ' tcx > , & ' tcx ty:: Const < ' tcx > , RangeEnd ) ,
598
598
/// Array patterns of length `n`.
599
599
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
+ } ,
600
608
/// Slice patterns. Captures any array constructor of `length >= i + j`.
601
609
VarLenSlice ( u64 , u64 ) ,
602
610
/// Fake extra constructor for enums that aren't allowed to be matched exhaustively.
@@ -606,7 +614,7 @@ enum Constructor<'tcx> {
606
614
impl < ' tcx > Constructor < ' tcx > {
607
615
fn is_slice ( & self ) -> bool {
608
616
match self {
609
- FixedLenSlice { .. } | VarLenSlice { .. } => true ,
617
+ FixedLenSlice { .. } | LazyFixedLenSlice { .. } | VarLenSlice { .. } => true ,
610
618
_ => false ,
611
619
}
612
620
}
@@ -635,9 +643,9 @@ impl<'tcx> Constructor<'tcx> {
635
643
Single | Variant ( _) | ConstantValue ( ..) | FloatRange ( ..) => {
636
644
if other_ctors. iter ( ) . any ( |c| c == self ) { vec ! [ ] } else { vec ! [ self . clone( ) ] }
637
645
}
638
- & FixedLenSlice ( self_len) => {
646
+ & FixedLenSlice ( self_len) | & LazyFixedLenSlice { len : self_len , .. } => {
639
647
let overlaps = |c : & Constructor < ' _ > | match * c {
640
- FixedLenSlice ( other_len ) => other_len == self_len,
648
+ FixedLenSlice ( len ) | LazyFixedLenSlice { len , .. } => len == self_len,
641
649
VarLenSlice ( prefix, suffix) => prefix + suffix <= self_len,
642
650
_ => false ,
643
651
} ;
@@ -657,7 +665,12 @@ impl<'tcx> Constructor<'tcx> {
657
665
// Compute `pos_ctor \ neg_ctor`.
658
666
match pos_ctor {
659
667
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
+ }
661
674
VarLenSlice ( neg_prefix, neg_suffix)
662
675
if neg_prefix + neg_suffix <= pos_len =>
663
676
{
@@ -668,7 +681,10 @@ impl<'tcx> Constructor<'tcx> {
668
681
VarLenSlice ( pos_prefix, pos_suffix) => {
669
682
let pos_len = pos_prefix + pos_suffix;
670
683
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
+ {
672
688
( pos_len..neg_len)
673
689
. map ( FixedLenSlice )
674
690
// We know that `neg_len + 1 >= pos_len >=
@@ -799,7 +815,7 @@ impl<'tcx> Constructor<'tcx> {
799
815
}
800
816
_ => vec ! [ ] ,
801
817
} ,
802
- FixedLenSlice ( _) | VarLenSlice ( ..) => match ty. kind {
818
+ FixedLenSlice ( _) | LazyFixedLenSlice { .. } | VarLenSlice ( ..) => match ty. kind {
803
819
ty:: Slice ( ty) | ty:: Array ( ty, _) => {
804
820
let arity = self . arity ( cx, ty) ;
805
821
( 0 ..arity) . map ( |_| Pat :: wildcard_from_ty ( ty) ) . collect ( )
@@ -830,7 +846,9 @@ impl<'tcx> Constructor<'tcx> {
830
846
_ => 0 ,
831
847
} ,
832
848
FixedLenSlice ( length) => * length,
833
- VarLenSlice ( prefix, suffix) => prefix + suffix,
849
+ VarLenSlice ( prefix, suffix) | LazyFixedLenSlice { prefix, suffix, .. } => {
850
+ prefix + suffix
851
+ }
834
852
ConstantValue ( ..) | FloatRange ( ..) | IntRange ( ..) | NonExhaustive => 0 ,
835
853
}
836
854
}
@@ -888,8 +906,11 @@ impl<'tcx> Constructor<'tcx> {
888
906
FixedLenSlice ( _) => {
889
907
PatKind :: Slice { prefix : subpatterns. collect ( ) , slice : None , suffix : vec ! [ ] }
890
908
}
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 ( ) ;
893
914
let suffix = subpatterns. collect ( ) ;
894
915
let wild = Pat :: wildcard_from_ty ( ty) ;
895
916
PatKind :: Slice { prefix, slice : Some ( wild) , suffix }
@@ -1106,7 +1127,11 @@ fn all_constructors<'a, 'tcx>(
1106
1127
}
1107
1128
ty:: Array ( ref sub_ty, len) if len. try_eval_usize ( cx. tcx , cx. param_env ) . is_some ( ) => {
1108
1129
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
+ }
1110
1135
}
1111
1136
// Treat arrays of a constant but unknown length like slices.
1112
1137
ty:: Array ( ref sub_ty, _) | ty:: Slice ( ref sub_ty) => {
@@ -1694,10 +1719,19 @@ fn pat_constructor<'tcx>(
1694
1719
Some ( FloatRange ( lo, hi, end) )
1695
1720
}
1696
1721
}
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
+ }
1701
1735
PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
1702
1736
let prefix = prefix. len ( ) as u64 ;
1703
1737
let suffix = suffix. len ( ) as u64 ;
@@ -1833,6 +1867,7 @@ fn split_grouped_constructors<'p, 'tcx>(
1833
1867
) -> Vec < Constructor < ' tcx > > {
1834
1868
let ty = pcx. ty ;
1835
1869
let mut split_ctors = Vec :: with_capacity ( ctors. len ( ) ) ;
1870
+ debug ! ( "split_grouped_constructors({:#?}, {:#?})" , matrix, ctors) ;
1836
1871
1837
1872
for ctor in ctors. into_iter ( ) {
1838
1873
match ctor {
@@ -1920,7 +1955,8 @@ fn split_grouped_constructors<'p, 'tcx>(
1920
1955
. map ( IntRange ) ,
1921
1956
) ;
1922
1957
}
1923
- VarLenSlice ( self_prefix, self_suffix) => {
1958
+ VarLenSlice ( self_prefix, self_suffix)
1959
+ | LazyFixedLenSlice { prefix : self_prefix, suffix : self_suffix, .. } => {
1924
1960
// The exhaustiveness-checking paper does not include any details on
1925
1961
// checking variable-length slice patterns. However, they are matched
1926
1962
// by an infinite collection of fixed-length array patterns.
@@ -2005,11 +2041,13 @@ fn split_grouped_constructors<'p, 'tcx>(
2005
2041
_ => { }
2006
2042
}
2007
2043
}
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 } => {
2009
2046
let fixed_len = prefix. len ( ) as u64 + suffix. len ( ) as u64 ;
2010
2047
max_fixed_len = cmp:: max ( max_fixed_len, fixed_len) ;
2011
2048
}
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 } => {
2013
2051
max_prefix_len = cmp:: max ( max_prefix_len, prefix. len ( ) as u64 ) ;
2014
2052
max_suffix_len = cmp:: max ( max_suffix_len, suffix. len ( ) as u64 ) ;
2015
2053
}
@@ -2027,20 +2065,37 @@ fn split_grouped_constructors<'p, 'tcx>(
2027
2065
max_prefix_len = max_fixed_len + 1 - max_suffix_len;
2028
2066
}
2029
2067
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
+ }
2038
2092
}
2039
2093
// Any other constructor can be used unchanged.
2040
2094
_ => split_ctors. push ( ctor) ,
2041
2095
}
2042
2096
}
2043
2097
2098
+ debug ! ( "split_grouped_constructors(..)={:#?}" , split_ctors) ;
2044
2099
split_ctors
2045
2100
}
2046
2101
@@ -2252,7 +2307,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
2252
2307
2253
2308
PatKind :: Array { ref prefix, ref slice, ref suffix }
2254
2309
| PatKind :: Slice { ref prefix, ref slice, ref suffix } => match * constructor {
2255
- FixedLenSlice ( ..) | VarLenSlice ( ..) => {
2310
+ FixedLenSlice ( ..) | LazyFixedLenSlice { .. } | VarLenSlice ( ..) => {
2256
2311
let pat_len = prefix. len ( ) + suffix. len ( ) ;
2257
2312
if let Some ( slice_count) = ctor_wild_subpatterns. len ( ) . checked_sub ( pat_len) {
2258
2313
if slice_count == 0 || slice. is_some ( ) {
0 commit comments