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 } ;
@@ -33,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3334 /// Used internally by [`MatchPairTree::for_pattern`].
3435 fn prefix_slice_suffix < ' pat > (
3536 & mut self ,
37+ src_path : & ' pat Pat < ' tcx > ,
3638 match_pairs : & mut Vec < MatchPairTree < ' pat , ' tcx > > ,
3739 place : & PlaceBuilder < ' tcx > ,
3840 prefix : & ' pat [ Box < Pat < ' tcx > > ] ,
@@ -54,11 +56,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
5456 ( ( prefix. len ( ) + suffix. len ( ) ) . try_into ( ) . unwrap ( ) , false )
5557 } ;
5658
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+ }
6288
6389 if let Some ( subslice_pat) = opt_slice {
6490 let suffix_len = suffix. len ( ) as u64 ;
@@ -81,6 +107,88 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
81107 MatchPairTree :: for_pattern ( place, subpattern, self )
82108 } ) ) ;
83109 }
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+ }
84192}
85193
86194impl < ' pat , ' tcx > MatchPairTree < ' pat , ' tcx > {
@@ -192,11 +300,25 @@ 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 (
304+ pattern,
305+ & mut subpairs,
306+ & place_builder,
307+ prefix,
308+ slice,
309+ suffix,
310+ ) ;
196311 default_irrefutable ( )
197312 }
198313 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+ ) ;
200322
201323 if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
202324 default_irrefutable ( )
0 commit comments