15
15
use crate :: build:: expr:: as_place:: PlaceBuilder ;
16
16
use crate :: build:: matches:: { Ascription , Binding , Candidate , MatchPair } ;
17
17
use crate :: build:: Builder ;
18
+ use rustc_data_structures:: intern:: Interned ;
18
19
use rustc_hir:: RangeEnd ;
20
+ use rustc_middle:: mir:: ConstantKind ;
19
21
use rustc_middle:: thir:: { self , * } ;
20
- use rustc_middle:: ty;
21
22
use rustc_middle:: ty:: layout:: IntegerExt ;
23
+ use rustc_middle:: ty:: Const ;
24
+ use rustc_middle:: ty:: { self , Ty , ValTree } ;
22
25
use rustc_target:: abi:: { Integer , Size } ;
23
26
24
27
use std:: mem;
@@ -120,6 +123,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
120
123
}
121
124
}
122
125
126
+ fn try_build_valtree ( & self , elements : & Box < [ Box < Pat < ' tcx > > ] > ) -> Option < ValTree < ' tcx > > {
127
+ if elements. iter ( ) . all ( |p| {
128
+ matches ! (
129
+ p. kind,
130
+ PatKind :: Constant {
131
+ value: ConstantKind :: Ty ( ty:: Const ( Interned (
132
+ ty:: ConstData { kind: ty:: ConstKind :: Value ( ty:: ValTree :: Leaf ( _) ) , .. } ,
133
+ _
134
+ ) ) )
135
+ }
136
+ )
137
+ } ) {
138
+ // This ValTree represents the content of the simple array.
139
+ // We then create a new pattern that matches against this ValTree.
140
+ // This reduces a match against `[1, 2, 3, 4]` from 4 basic-blocks in the MIR to just 1
141
+ Some ( ValTree :: from_scalars (
142
+ self . tcx ,
143
+ & elements
144
+ . iter ( )
145
+ . map ( |p| match p. kind {
146
+ PatKind :: Constant { value : ConstantKind :: Ty ( c) } => {
147
+ c. to_valtree ( ) . unwrap_leaf ( )
148
+ }
149
+ _ => unreachable ! ( ) ,
150
+ } )
151
+ . collect :: < Vec < _ > > ( ) ,
152
+ ) )
153
+ } else {
154
+ None
155
+ }
156
+ }
157
+
123
158
/// Given `candidate` that has a single or-pattern for its match-pairs,
124
159
/// creates a fresh candidate for each of its input subpatterns passed via
125
160
/// `pats`.
@@ -243,22 +278,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
243
278
Err ( match_pair)
244
279
}
245
280
246
- PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
247
- if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
248
- // irrefutable
249
- self . prefix_slice_suffix (
250
- & mut candidate. match_pairs ,
251
- & match_pair. place ,
252
- prefix,
253
- slice,
254
- suffix,
255
- ) ;
256
- Ok ( ( ) )
257
- } else {
258
- Err ( match_pair)
259
- }
260
- }
261
-
262
281
PatKind :: Variant { adt_def, args, variant_index, ref subpatterns } => {
263
282
let irrefutable = adt_def. variants ( ) . iter_enumerated ( ) . all ( |( i, v) | {
264
283
i == variant_index || {
@@ -281,6 +300,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
281
300
}
282
301
}
283
302
303
+ // Looks for simple array patterns such as `[1, 2, 3]`
304
+ // They cannot have slices (e.g `[1, .., 3, 4]` is not simple), and
305
+ // all the elements of the array must be leaf constants (so no strings!)
306
+ PatKind :: Array { ref prefix, slice : None , ref suffix }
307
+ | PatKind :: Slice { ref prefix, slice : None , ref suffix }
308
+ if let Some ( _val) = self . try_build_valtree ( prefix)
309
+ && !prefix. is_empty ( )
310
+ && suffix. is_empty ( ) =>
311
+ {
312
+ // This ValTree represents the content of the simple array.
313
+ // We then create a new pattern that matches against this ValTree.
314
+ // This reduces a match against `[1, 2, 3, 4]` from 4 basic-blocks in the MIR to just 1
315
+ let val = self . try_build_valtree ( prefix) . unwrap ( ) ; // FIXME: false positive
316
+
317
+ let el_ty = prefix. iter ( ) . next ( ) . unwrap ( ) . ty ;
318
+ let ( place, cnst_ty, pat_ty) =
319
+ if match_pair. pattern . ty . is_slice ( ) {
320
+ (
321
+ PlaceBuilder :: from ( match_pair. place . base ( ) ) ,
322
+ Ty :: new_imm_ref ( tcx, tcx. lifetimes . re_erased , Ty :: new_array ( tcx, el_ty, prefix. len ( ) as u64 ) ) ,
323
+ Ty :: new_imm_ref ( tcx, tcx. lifetimes . re_erased , Ty :: new_slice ( tcx, el_ty) )
324
+ )
325
+ } else {
326
+ let arr_ty = Ty :: new_array ( tcx, el_ty, prefix. len ( ) as u64 ) ;
327
+ (
328
+ match_pair. place ,
329
+ arr_ty,
330
+ arr_ty
331
+ )
332
+ } ;
333
+
334
+ let cnst = Const :: new ( tcx, ty:: ConstKind :: Value ( val) , cnst_ty) ;
335
+ let new_pat = Pat {
336
+ ty : pat_ty,
337
+ span : match_pair. pattern . span ,
338
+ kind : PatKind :: Constant { value : ConstantKind :: Ty ( cnst) } ,
339
+ } ;
340
+
341
+ let pat = tcx. arena . alloc ( new_pat) ;
342
+
343
+ candidate. match_pairs . push ( MatchPair :: new ( place, pat, self ) ) ;
344
+
345
+ Ok ( ( ) )
346
+ }
347
+
284
348
PatKind :: Array { ref prefix, ref slice, ref suffix } => {
285
349
self . prefix_slice_suffix (
286
350
& mut candidate. match_pairs ,
@@ -292,6 +356,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
292
356
Ok ( ( ) )
293
357
}
294
358
359
+ PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
360
+ if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
361
+ // irrefutable
362
+ self . prefix_slice_suffix (
363
+ & mut candidate. match_pairs ,
364
+ & match_pair. place ,
365
+ prefix,
366
+ slice,
367
+ suffix,
368
+ ) ;
369
+ Ok ( ( ) )
370
+ } else {
371
+ Err ( match_pair)
372
+ }
373
+ }
374
+
295
375
PatKind :: Leaf { ref subpatterns } => {
296
376
// tuple struct, match subpats (if any)
297
377
candidate. match_pairs . extend ( self . field_match_pairs ( match_pair. place , subpatterns) ) ;
0 commit comments