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 } ;
@@ -27,12 +28,100 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
27
28
. collect ( )
28
29
}
29
30
31
+ // We don't consider an empty subslice as a constant pattern subslice.
32
+ fn is_constant_pattern_subslice ( & self , subslice : & [ Box < Pat < ' tcx > > ] ) -> bool {
33
+ !subslice. is_empty ( ) && subslice. iter ( ) . all ( |p| self . is_constant_pattern ( p) )
34
+ }
35
+
36
+ // TODO: expand beyond u8
37
+ fn is_constant_pattern ( & self , pat : & Pat < ' tcx > ) -> bool {
38
+ if let PatKind :: Constant { value } = pat. kind
39
+ && let Const :: Ty ( _, const_) = value
40
+ && let ty:: ConstKind :: Value ( ty, valtree) = const_. kind ( )
41
+ && self . tcx . types . u8 == ty
42
+ && matches ! ( valtree, ty:: ValTree :: Leaf ( _) )
43
+ {
44
+ true
45
+ } else {
46
+ false
47
+ }
48
+ }
49
+
50
+ fn extract_leaf ( & self , pat : & Pat < ' tcx > ) -> ty:: ValTree < ' tcx > {
51
+ if let PatKind :: Constant { value } = pat. kind
52
+ && let Const :: Ty ( _, const_) = value
53
+ && let ty:: ConstKind :: Value ( _, valtree) = const_. kind ( )
54
+ && matches ! ( valtree, ty:: ValTree :: Leaf ( _) )
55
+ {
56
+ valtree
57
+ } else {
58
+ unreachable ! ( )
59
+ }
60
+ }
61
+
62
+ // This must only be called after ensuring that the subslice consists of only constant
63
+ // patterns, or it will panic.
64
+ fn simplify_const_pattern_slice_into_valtree (
65
+ & self ,
66
+ subslice : & [ Box < Pat < ' tcx > > ] ,
67
+ ) -> ty:: ValTree < ' tcx > {
68
+ let leaves = subslice. iter ( ) . map ( |p| self . extract_leaf ( p) ) ;
69
+ let interned = self . tcx . arena . alloc_from_iter ( leaves) ;
70
+ ty:: ValTree :: Branch ( interned)
71
+ }
72
+
73
+ fn valtree_to_match_pair < ' pat > (
74
+ & mut self ,
75
+ base_pat_ty : Ty < ' tcx > ,
76
+ span : Span ,
77
+ subslice_len : u64 ,
78
+ valtree : ty:: ValTree < ' tcx > ,
79
+ place : PlaceBuilder < ' tcx > ,
80
+ elem_ty : Ty < ' tcx > ,
81
+ ) -> MatchPairTree < ' pat , ' tcx > {
82
+ let tcx = self . tcx ;
83
+ let ( const_ty, pat_ty) = if base_pat_ty. is_slice ( ) {
84
+ (
85
+ Ty :: new_imm_ref (
86
+ tcx,
87
+ tcx. lifetimes . re_erased ,
88
+ Ty :: new_array ( tcx, elem_ty, subslice_len) ,
89
+ ) ,
90
+ Ty :: new_imm_ref ( tcx, tcx. lifetimes . re_erased , Ty :: new_slice ( tcx, elem_ty) ) ,
91
+ )
92
+ } else {
93
+ //let arr_ty = Ty::new_array(tcx, elem_ty, subslice_len);
94
+ let arr_ty = Ty :: new_slice ( tcx, elem_ty) ;
95
+ let pat_ty = Ty :: new_imm_ref ( tcx, tcx. lifetimes . re_erased , arr_ty) ;
96
+ ( arr_ty, arr_ty)
97
+ } ;
98
+
99
+ let r#const = ty:: Const :: new ( tcx, ty:: ConstKind :: Value ( const_ty, valtree) ) ;
100
+ let r#const2 = Const :: Ty ( const_ty, r#const) ;
101
+
102
+ let pattern = tcx. arena . alloc ( Pat {
103
+ ty : pat_ty,
104
+ span,
105
+ kind : PatKind :: Constant { value : Const :: Ty ( const_ty, r#const) } ,
106
+ } ) ;
107
+
108
+ let test_case = TestCase :: Constant { value : r#const2 } ;
109
+
110
+ MatchPairTree {
111
+ place : Some ( place. to_place ( self ) ) ,
112
+ test_case,
113
+ subpairs : Vec :: new ( ) ,
114
+ pattern,
115
+ }
116
+ }
117
+
30
118
/// Builds [`MatchPairTree`] subtrees for the prefix/middle/suffix parts of an
31
119
/// array pattern or slice pattern, and adds those trees to `match_pairs`.
32
120
///
33
121
/// Used internally by [`MatchPairTree::for_pattern`].
34
122
fn prefix_slice_suffix < ' pat > (
35
123
& mut self ,
124
+ base_pat : & ' pat Pat < ' tcx > ,
36
125
match_pairs : & mut Vec < MatchPairTree < ' pat , ' tcx > > ,
37
126
place : & PlaceBuilder < ' tcx > ,
38
127
prefix : & ' pat [ Box < Pat < ' tcx > > ] ,
@@ -54,11 +143,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
54
143
( ( prefix. len ( ) + suffix. len ( ) ) . try_into ( ) . unwrap ( ) , false )
55
144
} ;
56
145
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
- } ) ) ;
146
+ // Here we try to special-case constant pattern subslices into valtrees to generate
147
+ // nicer MIR.
148
+ // Try to perform simplification of a constant pattern slice `prefix` sequence into
149
+ // a valtree.
150
+ if self . is_constant_pattern_subslice ( prefix) {
151
+ let elem_ty = prefix[ 0 ] . ty ;
152
+ let prefix_valtree = self . simplify_const_pattern_slice_into_valtree ( prefix) ;
153
+ // FIXME(jieyouxu): triple check these place calculations!
154
+ let match_pair = self . valtree_to_match_pair (
155
+ base_pat. ty ,
156
+ base_pat. span ,
157
+ prefix. len ( ) as u64 ,
158
+ prefix_valtree,
159
+ place. base ( ) . into ( ) ,
160
+ elem_ty,
161
+ ) ;
162
+ match_pairs. push ( match_pair) ;
163
+ } else {
164
+ match_pairs. extend ( prefix. iter ( ) . enumerate ( ) . map ( |( idx, subpattern) | {
165
+ let elem =
166
+ ProjectionElem :: ConstantIndex { offset : idx as u64 , min_length, from_end : false } ;
167
+ MatchPairTree :: for_pattern ( place. clone_project ( elem) , subpattern, self )
168
+ } ) ) ;
169
+ }
62
170
63
171
if let Some ( subslice_pat) = opt_slice {
64
172
let suffix_len = suffix. len ( ) as u64 ;
@@ -192,11 +300,11 @@ 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 ( pattern , & mut subpairs, & place_builder, prefix, slice, suffix) ;
196
304
default_irrefutable ( )
197
305
}
198
306
PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
199
- cx. prefix_slice_suffix ( & mut subpairs, & place_builder, prefix, slice, suffix) ;
307
+ cx. prefix_slice_suffix ( pattern , & mut subpairs, & place_builder, prefix, slice, suffix) ;
200
308
201
309
if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
202
310
default_irrefutable ( )
0 commit comments