@@ -4,6 +4,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt};
4
4
5
5
use crate :: builder:: Builder ;
6
6
use crate :: builder:: expr:: as_place:: { PlaceBase , PlaceBuilder } ;
7
+ use crate :: builder:: matches:: util:: Range ;
7
8
use crate :: builder:: matches:: { FlatPat , MatchPairTree , TestCase } ;
8
9
9
10
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
@@ -33,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
33
34
/// Used internally by [`MatchPairTree::for_pattern`].
34
35
fn prefix_slice_suffix < ' pat > (
35
36
& mut self ,
37
+ src_path : & ' pat Pat < ' tcx > ,
36
38
match_pairs : & mut Vec < MatchPairTree < ' pat , ' tcx > > ,
37
39
place : & PlaceBuilder < ' tcx > ,
38
40
prefix : & ' pat [ Box < Pat < ' tcx > > ] ,
@@ -54,11 +56,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
54
56
( ( prefix. len ( ) + suffix. len ( ) ) . try_into ( ) . unwrap ( ) , false )
55
57
} ;
56
58
57
- match_pairs. extend ( prefix. iter ( ) . enumerate ( ) . map ( |( idx, subpattern) | {
58
- let elem =
59
- ProjectionElem :: ConstantIndex { offset : idx as u64 , min_length, from_end : false } ;
60
- MatchPairTree :: for_pattern ( place. clone_project ( elem) , subpattern, self )
61
- } ) ) ;
59
+ if self . should_optimize_subslice ( prefix) {
60
+ let elem_ty = prefix[ 0 ] . ty ;
61
+ let prefix_valtree = self . simplify_const_pattern_slice_into_valtree ( prefix) ;
62
+ let match_pair = self . valtree_to_match_pair (
63
+ src_path,
64
+ prefix_valtree,
65
+ place. clone ( ) ,
66
+ elem_ty,
67
+ Range :: from_start ( 0 ..prefix. len ( ) as u64 ) ,
68
+ opt_slice. is_some ( ) || !suffix. is_empty ( ) ,
69
+ ) ;
70
+
71
+ match_pairs. push ( match_pair) ;
72
+ } else {
73
+ match_pairs. extend ( prefix. iter ( ) . enumerate ( ) . map ( |( idx, subpattern) | {
74
+ let elem = ProjectionElem :: ConstantIndex {
75
+ offset : idx as u64 ,
76
+ min_length,
77
+ from_end : false ,
78
+ } ;
79
+ MatchPairTree :: for_pattern ( place. clone_project ( elem) , subpattern, self )
80
+ } ) ) ;
81
+ }
62
82
63
83
if let Some ( subslice_pat) = opt_slice {
64
84
let suffix_len = suffix. len ( ) as u64 ;
@@ -70,16 +90,99 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
70
90
match_pairs. push ( MatchPairTree :: for_pattern ( subslice, subslice_pat, self ) ) ;
71
91
}
72
92
73
- match_pairs. extend ( suffix. iter ( ) . rev ( ) . enumerate ( ) . map ( |( idx, subpattern) | {
74
- let end_offset = ( idx + 1 ) as u64 ;
75
- let elem = ProjectionElem :: ConstantIndex {
76
- offset : if exact_size { min_length - end_offset } else { end_offset } ,
77
- min_length,
78
- from_end : !exact_size,
79
- } ;
80
- let place = place. clone_project ( elem) ;
81
- MatchPairTree :: for_pattern ( place, subpattern, self )
82
- } ) ) ;
93
+ if self . should_optimize_subslice ( suffix) {
94
+ let elem_ty = suffix[ 0 ] . ty ;
95
+ let suffix_valtree = self . simplify_const_pattern_slice_into_valtree ( suffix) ;
96
+ let match_pair = self . valtree_to_match_pair (
97
+ src_path,
98
+ suffix_valtree,
99
+ place. clone ( ) ,
100
+ elem_ty,
101
+ Range :: from_end ( 0 ..suffix. len ( ) as u64 ) ,
102
+ true ,
103
+ ) ;
104
+
105
+ match_pairs. push ( match_pair) ;
106
+ } else {
107
+ match_pairs. extend ( suffix. iter ( ) . rev ( ) . enumerate ( ) . map ( |( idx, subpattern) | {
108
+ let end_offset = ( idx + 1 ) as u64 ;
109
+ let elem = ProjectionElem :: ConstantIndex {
110
+ offset : if exact_size { min_length - end_offset } else { end_offset } ,
111
+ min_length,
112
+ from_end : !exact_size,
113
+ } ;
114
+ let place = place. clone_project ( elem) ;
115
+ MatchPairTree :: for_pattern ( place, subpattern, self )
116
+ } ) ) ;
117
+ }
118
+ }
119
+
120
+ fn should_optimize_subslice ( & self , subslice : & [ Box < Pat < ' tcx > > ] ) -> bool {
121
+ subslice. len ( ) > 1 && subslice. iter ( ) . all ( |p| self . is_constant_pattern ( p) )
122
+ }
123
+
124
+ fn is_constant_pattern ( & self , pat : & Pat < ' tcx > ) -> bool {
125
+ if let PatKind :: Constant { value } = pat. kind
126
+ && let Const :: Ty ( _, const_) = value
127
+ && let ty:: ConstKind :: Value ( _, valtree) = const_. kind ( )
128
+ && let ty:: ValTree :: Leaf ( _) = valtree
129
+ {
130
+ true
131
+ } else {
132
+ false
133
+ }
134
+ }
135
+
136
+ fn extract_leaf ( & self , pat : & Pat < ' tcx > ) -> ty:: ValTree < ' tcx > {
137
+ if let PatKind :: Constant { value } = pat. kind
138
+ && let Const :: Ty ( _, const_) = value
139
+ && let ty:: ConstKind :: Value ( _, valtree) = const_. kind ( )
140
+ && matches ! ( valtree, ty:: ValTree :: Leaf ( _) )
141
+ {
142
+ valtree
143
+ } else {
144
+ unreachable ! ( )
145
+ }
146
+ }
147
+
148
+ fn simplify_const_pattern_slice_into_valtree (
149
+ & self ,
150
+ subslice : & [ Box < Pat < ' tcx > > ] ,
151
+ ) -> ty:: ValTree < ' tcx > {
152
+ let leaves = subslice. iter ( ) . map ( |p| self . extract_leaf ( p) ) ;
153
+ let interned = self . tcx . arena . alloc_from_iter ( leaves) ;
154
+ ty:: ValTree :: Branch ( interned)
155
+ }
156
+
157
+ fn valtree_to_match_pair < ' pat > (
158
+ & mut self ,
159
+ source_pattern : & ' pat Pat < ' tcx > ,
160
+ valtree : ty:: ValTree < ' tcx > ,
161
+ place : PlaceBuilder < ' tcx > ,
162
+ elem_ty : Ty < ' tcx > ,
163
+ range : Range ,
164
+ subsliced : bool ,
165
+ ) -> MatchPairTree < ' pat , ' tcx > {
166
+ let tcx = self . tcx ;
167
+ let const_ty =
168
+ Ty :: new_imm_ref ( tcx, tcx. lifetimes . re_erased , Ty :: new_array ( tcx, elem_ty, range. len ( ) ) ) ;
169
+
170
+ let pat_ty = if subsliced { Ty :: new_slice ( tcx, elem_ty) } else { source_pattern. ty } ;
171
+ let ty_const = ty:: Const :: new ( tcx, ty:: ConstKind :: Value ( const_ty, valtree) ) ;
172
+ let value = Const :: Ty ( const_ty, ty_const) ;
173
+ let test_case = TestCase :: Constant { value, range : subsliced. then_some ( range) } ;
174
+ let pattern = tcx. arena . alloc ( Pat {
175
+ ty : pat_ty,
176
+ span : source_pattern. span ,
177
+ kind : PatKind :: Constant { value } ,
178
+ } ) ;
179
+
180
+ MatchPairTree {
181
+ place : Some ( place. to_place ( self ) ) ,
182
+ test_case,
183
+ subpairs : Vec :: new ( ) ,
184
+ pattern,
185
+ }
83
186
}
84
187
}
85
188
@@ -129,7 +232,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
129
232
}
130
233
}
131
234
132
- PatKind :: Constant { value } => TestCase :: Constant { value } ,
235
+ PatKind :: Constant { value } => TestCase :: Constant { value, range : None } ,
133
236
134
237
PatKind :: AscribeUserType {
135
238
ascription : thir:: Ascription { ref annotation, variance } ,
@@ -192,11 +295,25 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
192
295
}
193
296
194
297
PatKind :: Array { ref prefix, ref slice, ref suffix } => {
195
- cx. prefix_slice_suffix ( & mut subpairs, & place_builder, prefix, slice, suffix) ;
298
+ cx. prefix_slice_suffix (
299
+ pattern,
300
+ & mut subpairs,
301
+ & place_builder,
302
+ prefix,
303
+ slice,
304
+ suffix,
305
+ ) ;
196
306
default_irrefutable ( )
197
307
}
198
308
PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
199
- cx. prefix_slice_suffix ( & mut subpairs, & place_builder, prefix, slice, suffix) ;
309
+ cx. prefix_slice_suffix (
310
+ pattern,
311
+ & mut subpairs,
312
+ & place_builder,
313
+ prefix,
314
+ slice,
315
+ suffix,
316
+ ) ;
200
317
201
318
if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
202
319
default_irrefutable ( )
0 commit comments