@@ -4,6 +4,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt};
44
55use crate :: builder:: Builder ;
66use crate :: builder:: expr:: as_place:: { PlaceBase , PlaceBuilder } ;
7+ use crate :: builder:: matches:: util:: Range ;
78use crate :: builder:: matches:: { FlatPat , MatchPairTree , TestCase } ;
89
910impl < ' a , ' tcx > Builder < ' a , ' tcx > {
@@ -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,29 @@ 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+ if self . should_optimize_subslice ( prefix) {
60+ let elem_ty = prefix[ 0 ] . ty ;
61+ let prefix_valtree = self . simplify_const_pattern_slice_into_valtree ( prefix) ;
62+ let match_pair = self . valtree_to_match_pair (
63+ src_path,
64+ prefix_valtree,
65+ place. clone ( ) ,
66+ elem_ty,
67+ Range :: from_start ( 0 ..prefix. len ( ) as u64 ) ,
68+ opt_slice. is_some ( ) || !suffix. is_empty ( ) ,
69+ ) ;
70+
71+ match_pairs. push ( match_pair) ;
72+ } else {
73+ match_pairs. extend ( prefix. iter ( ) . enumerate ( ) . map ( |( idx, subpattern) | {
74+ let elem = ProjectionElem :: ConstantIndex {
75+ offset : idx as u64 ,
76+ min_length,
77+ from_end : false ,
78+ } ;
79+ MatchPairTree :: for_pattern ( place. clone_project ( elem) , subpattern, self )
80+ } ) ) ;
81+ }
6282
6383 if let Some ( subslice_pat) = opt_slice {
6484 let suffix_len = suffix. len ( ) as u64 ;
@@ -70,16 +90,99 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
7090 match_pairs. push ( MatchPairTree :: for_pattern ( subslice, subslice_pat, self ) ) ;
7191 }
7292
73- match_pairs. extend ( suffix. iter ( ) . rev ( ) . enumerate ( ) . map ( |( idx, subpattern) | {
74- let end_offset = ( idx + 1 ) as u64 ;
75- let elem = ProjectionElem :: ConstantIndex {
76- offset : if exact_size { min_length - end_offset } else { end_offset } ,
77- min_length,
78- from_end : !exact_size,
79- } ;
80- let place = place. clone_project ( elem) ;
81- MatchPairTree :: for_pattern ( place, subpattern, self )
82- } ) ) ;
93+ if self . should_optimize_subslice ( suffix) {
94+ let elem_ty = suffix[ 0 ] . ty ;
95+ let suffix_valtree = self . simplify_const_pattern_slice_into_valtree ( suffix) ;
96+ let match_pair = self . valtree_to_match_pair (
97+ src_path,
98+ suffix_valtree,
99+ place. clone ( ) ,
100+ elem_ty,
101+ Range :: from_end ( 0 ..suffix. len ( ) as u64 ) ,
102+ true ,
103+ ) ;
104+
105+ match_pairs. push ( match_pair) ;
106+ } else {
107+ match_pairs. extend ( suffix. iter ( ) . rev ( ) . enumerate ( ) . map ( |( idx, subpattern) | {
108+ let end_offset = ( idx + 1 ) as u64 ;
109+ let elem = ProjectionElem :: ConstantIndex {
110+ offset : if exact_size { min_length - end_offset } else { end_offset } ,
111+ min_length,
112+ from_end : !exact_size,
113+ } ;
114+ let place = place. clone_project ( elem) ;
115+ MatchPairTree :: for_pattern ( place, subpattern, self )
116+ } ) ) ;
117+ }
118+ }
119+
120+ fn should_optimize_subslice ( & self , subslice : & [ Box < Pat < ' tcx > > ] ) -> bool {
121+ subslice. len ( ) > 1 && subslice. iter ( ) . all ( |p| self . is_constant_pattern ( p) )
122+ }
123+
124+ fn is_constant_pattern ( & self , pat : & Pat < ' tcx > ) -> bool {
125+ if let PatKind :: Constant { value } = pat. kind
126+ && let Const :: Ty ( _, const_) = value
127+ && let ty:: ConstKind :: Value ( _, valtree) = const_. kind ( )
128+ && let ty:: ValTree :: Leaf ( _) = valtree
129+ {
130+ true
131+ } else {
132+ false
133+ }
134+ }
135+
136+ fn extract_leaf ( & self , pat : & Pat < ' tcx > ) -> ty:: ValTree < ' tcx > {
137+ if let PatKind :: Constant { value } = pat. kind
138+ && let Const :: Ty ( _, const_) = value
139+ && let ty:: ConstKind :: Value ( _, valtree) = const_. kind ( )
140+ && matches ! ( valtree, ty:: ValTree :: Leaf ( _) )
141+ {
142+ valtree
143+ } else {
144+ unreachable ! ( )
145+ }
146+ }
147+
148+ fn simplify_const_pattern_slice_into_valtree (
149+ & self ,
150+ subslice : & [ Box < Pat < ' tcx > > ] ,
151+ ) -> ty:: ValTree < ' tcx > {
152+ let leaves = subslice. iter ( ) . map ( |p| self . extract_leaf ( p) ) ;
153+ let interned = self . tcx . arena . alloc_from_iter ( leaves) ;
154+ ty:: ValTree :: Branch ( interned)
155+ }
156+
157+ fn valtree_to_match_pair < ' pat > (
158+ & mut self ,
159+ source_pattern : & ' pat Pat < ' tcx > ,
160+ valtree : ty:: ValTree < ' tcx > ,
161+ place : PlaceBuilder < ' tcx > ,
162+ elem_ty : Ty < ' tcx > ,
163+ range : Range ,
164+ subsliced : bool ,
165+ ) -> MatchPairTree < ' pat , ' tcx > {
166+ let tcx = self . tcx ;
167+ let const_ty =
168+ Ty :: new_imm_ref ( tcx, tcx. lifetimes . re_erased , Ty :: new_array ( tcx, elem_ty, range. len ( ) ) ) ;
169+
170+ let pat_ty = if subsliced { Ty :: new_slice ( tcx, elem_ty) } else { source_pattern. ty } ;
171+ let ty_const = ty:: Const :: new ( tcx, ty:: ConstKind :: Value ( const_ty, valtree) ) ;
172+ let value = Const :: Ty ( const_ty, ty_const) ;
173+ let test_case = TestCase :: Constant { value, range : subsliced. then_some ( range) } ;
174+ let pattern = tcx. arena . alloc ( Pat {
175+ ty : pat_ty,
176+ span : source_pattern. span ,
177+ kind : PatKind :: Constant { value } ,
178+ } ) ;
179+
180+ MatchPairTree {
181+ place : Some ( place. to_place ( self ) ) ,
182+ test_case,
183+ subpairs : Vec :: new ( ) ,
184+ pattern,
185+ }
83186 }
84187}
85188
@@ -129,7 +232,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
129232 }
130233 }
131234
132- PatKind :: Constant { value } => TestCase :: Constant { value } ,
235+ PatKind :: Constant { value } => TestCase :: Constant { value, range : None } ,
133236
134237 PatKind :: AscribeUserType {
135238 ascription : thir:: Ascription { ref annotation, variance } ,
@@ -192,11 +295,25 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
192295 }
193296
194297 PatKind :: Array { ref prefix, ref slice, ref suffix } => {
195- cx. prefix_slice_suffix ( & mut subpairs, & place_builder, prefix, slice, suffix) ;
298+ cx. prefix_slice_suffix (
299+ pattern,
300+ & mut subpairs,
301+ & place_builder,
302+ prefix,
303+ slice,
304+ suffix,
305+ ) ;
196306 default_irrefutable ( )
197307 }
198308 PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
199- cx. prefix_slice_suffix ( & mut subpairs, & place_builder, prefix, slice, suffix) ;
309+ cx. prefix_slice_suffix (
310+ pattern,
311+ & mut subpairs,
312+ & place_builder,
313+ prefix,
314+ slice,
315+ suffix,
316+ ) ;
200317
201318 if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
202319 default_irrefutable ( )
0 commit comments