1
1
use rustc_middle:: mir:: * ;
2
2
use rustc_middle:: thir:: { self , * } ;
3
3
use rustc_middle:: ty:: { self , Ty , TypeVisitableExt } ;
4
+ use rustc_span:: Span ;
4
5
5
6
use crate :: builder:: Builder ;
6
7
use crate :: builder:: expr:: as_place:: { PlaceBase , PlaceBuilder } ;
@@ -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,35 @@ 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
+ let mut prefix_opt = false ;
60
+
61
+ if self . is_constant_pattern_subslice ( prefix) && opt_slice. is_none ( ) && suffix. len ( ) == 0 {
62
+ let elem_ty = prefix[ 0 ] . ty ;
63
+ let prefix_valtree = self . simplify_const_pattern_slice_into_valtree ( prefix) ;
64
+
65
+ if let Some ( match_pair) = self . valtree_to_match_pair (
66
+ src_path. ty ,
67
+ src_path. span ,
68
+ prefix. len ( ) as u64 ,
69
+ prefix_valtree,
70
+ place. clone ( ) ,
71
+ elem_ty,
72
+ ) {
73
+ match_pairs. push ( match_pair) ;
74
+ prefix_opt = true ;
75
+ }
76
+ }
77
+
78
+ if !prefix_opt {
79
+ match_pairs. extend ( prefix. iter ( ) . enumerate ( ) . map ( |( idx, subpattern) | {
80
+ let elem = ProjectionElem :: ConstantIndex {
81
+ offset : idx as u64 ,
82
+ min_length,
83
+ from_end : false ,
84
+ } ;
85
+ MatchPairTree :: for_pattern ( place. clone_project ( elem) , subpattern, self )
86
+ } ) ) ;
87
+ }
62
88
63
89
if let Some ( subslice_pat) = opt_slice {
64
90
let suffix_len = suffix. len ( ) as u64 ;
@@ -81,6 +107,88 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
81
107
MatchPairTree :: for_pattern ( place, subpattern, self )
82
108
} ) ) ;
83
109
}
110
+
111
+ fn is_constant_pattern_subslice ( & self , subslice : & [ Box < Pat < ' tcx > > ] ) -> bool {
112
+ subslice. len ( ) > 1 && subslice. iter ( ) . all ( |p| self . is_constant_pattern ( p) )
113
+ }
114
+
115
+ fn is_constant_pattern ( & self , pat : & Pat < ' tcx > ) -> bool {
116
+ if let PatKind :: Constant { value } = pat. kind
117
+ && let Const :: Ty ( _, const_) = value
118
+ && let ty:: ConstKind :: Value ( ty, valtree) = const_. kind ( )
119
+ && let ty:: ValTree :: Leaf ( scalar) = valtree
120
+ && self . tcx . types . u8 == ty
121
+ && scalar. to_u8 ( ) != b'_'
122
+ {
123
+ true
124
+ } else {
125
+ false
126
+ }
127
+ }
128
+
129
+ fn extract_leaf ( & self , pat : & Pat < ' tcx > ) -> ty:: ValTree < ' tcx > {
130
+ if let PatKind :: Constant { value } = pat. kind
131
+ && let Const :: Ty ( _, const_) = value
132
+ && let ty:: ConstKind :: Value ( _, valtree) = const_. kind ( )
133
+ && matches ! ( valtree, ty:: ValTree :: Leaf ( _) )
134
+ {
135
+ valtree
136
+ } else {
137
+ unreachable ! ( )
138
+ }
139
+ }
140
+
141
+ fn simplify_const_pattern_slice_into_valtree (
142
+ & self ,
143
+ subslice : & [ Box < Pat < ' tcx > > ] ,
144
+ ) -> ty:: ValTree < ' tcx > {
145
+ let leaves = subslice. iter ( ) . map ( |p| self . extract_leaf ( p) ) ;
146
+ let interned = self . tcx . arena . alloc_from_iter ( leaves) ;
147
+ ty:: ValTree :: Branch ( interned)
148
+ }
149
+
150
+ fn valtree_to_match_pair < ' pat > (
151
+ & mut self ,
152
+ src_pat_ty : Ty < ' tcx > ,
153
+ span : Span ,
154
+ subslice_len : u64 ,
155
+ valtree : ty:: ValTree < ' tcx > ,
156
+ place : PlaceBuilder < ' tcx > ,
157
+ elem_ty : Ty < ' tcx > ,
158
+ ) -> Option < MatchPairTree < ' pat , ' tcx > > {
159
+ let tcx = self . tcx ;
160
+ let ( const_ty, pat_ty) = if src_pat_ty. is_slice ( ) {
161
+ (
162
+ Ty :: new_imm_ref (
163
+ tcx,
164
+ tcx. lifetimes . re_erased ,
165
+ Ty :: new_array ( tcx, elem_ty, subslice_len) ,
166
+ ) ,
167
+ Ty :: new_imm_ref ( tcx, tcx. lifetimes . re_erased , Ty :: new_slice ( tcx, elem_ty) ) ,
168
+ )
169
+ } else {
170
+ let arr_ty = Ty :: new_array ( tcx, elem_ty, subslice_len) ;
171
+ ( arr_ty, arr_ty)
172
+ } ;
173
+
174
+ let r#const = ty:: Const :: new ( tcx, ty:: ConstKind :: Value ( const_ty, valtree) ) ;
175
+ let r#const2 = Const :: Ty ( const_ty, r#const) ;
176
+
177
+ let pattern = tcx. arena . alloc ( Pat {
178
+ ty : pat_ty,
179
+ span,
180
+ kind : PatKind :: Constant { value : Const :: Ty ( const_ty, r#const) } ,
181
+ } ) ;
182
+
183
+ let test_case = TestCase :: Constant { value : r#const2 } ;
184
+
185
+ Some ( MatchPairTree {
186
+ place : Some ( place. to_place ( self ) ) ,
187
+ test_case,
188
+ subpairs : Vec :: new ( ) ,
189
+ pattern,
190
+ } )
191
+ }
84
192
}
85
193
86
194
impl < ' pat , ' tcx > MatchPairTree < ' pat , ' tcx > {
@@ -192,11 +300,25 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
192
300
}
193
301
194
302
PatKind :: Array { ref prefix, ref slice, ref suffix } => {
195
- cx. prefix_slice_suffix ( & mut subpairs, & place_builder, prefix, slice, suffix) ;
303
+ cx. prefix_slice_suffix (
304
+ pattern,
305
+ & mut subpairs,
306
+ & place_builder,
307
+ prefix,
308
+ slice,
309
+ suffix,
310
+ ) ;
196
311
default_irrefutable ( )
197
312
}
198
313
PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
199
- cx. prefix_slice_suffix ( & mut subpairs, & place_builder, prefix, slice, suffix) ;
314
+ cx. prefix_slice_suffix (
315
+ pattern,
316
+ & mut subpairs,
317
+ & place_builder,
318
+ prefix,
319
+ slice,
320
+ suffix,
321
+ ) ;
200
322
201
323
if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
202
324
default_irrefutable ( )
0 commit comments