11use rustc_middle:: mir:: * ;
22use rustc_middle:: thir:: { self , * } ;
33use rustc_middle:: ty:: { self , Ty , TypeVisitableExt } ;
4+ use rustc_span:: Span ;
45
56use crate :: builder:: Builder ;
67use crate :: builder:: expr:: as_place:: { PlaceBase , PlaceBuilder } ;
@@ -27,12 +28,100 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2728 . collect ( )
2829 }
2930
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+
30118 /// Builds [`MatchPairTree`] subtrees for the prefix/middle/suffix parts of an
31119 /// array pattern or slice pattern, and adds those trees to `match_pairs`.
32120 ///
33121 /// Used internally by [`MatchPairTree::for_pattern`].
34122 fn prefix_slice_suffix < ' pat > (
35123 & mut self ,
124+ base_pat : & ' pat Pat < ' tcx > ,
36125 match_pairs : & mut Vec < MatchPairTree < ' pat , ' tcx > > ,
37126 place : & PlaceBuilder < ' tcx > ,
38127 prefix : & ' pat [ Box < Pat < ' tcx > > ] ,
@@ -54,11 +143,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
54143 ( ( prefix. len ( ) + suffix. len ( ) ) . try_into ( ) . unwrap ( ) , false )
55144 } ;
56145
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+ }
62170
63171 if let Some ( subslice_pat) = opt_slice {
64172 let suffix_len = suffix. len ( ) as u64 ;
@@ -192,11 +300,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
192300 }
193301
194302 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) ;
196304 default_irrefutable ( )
197305 }
198306 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) ;
200308
201309 if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
202310 default_irrefutable ( )
0 commit comments