1515use crate :: build:: expr:: as_place:: PlaceBuilder ;
1616use crate :: build:: matches:: { Ascription , Binding , Candidate , MatchPair } ;
1717use crate :: build:: Builder ;
18+ use rustc_middle:: mir:: PlaceElem ;
1819use rustc_middle:: thir:: { self , * } ;
19-
2020use std:: mem;
2121
2222impl < ' a , ' tcx > Builder < ' a , ' tcx > {
2323 /// Simplify a candidate so that all match pairs require a test.
24- ///
25- /// This method will also split a candidate, in which the only
26- /// match-pair is an or-pattern, into multiple candidates.
27- /// This is so that
28- ///
29- /// match x {
30- /// 0 | 1 => { ... },
31- /// 2 | 3 => { ... },
32- /// }
33- ///
34- /// only generates a single switch. If this happens this method returns
35- /// `true`.
36- #[ instrument( skip( self , candidate) , level = "debug" ) ]
24+ #[ instrument( skip( self ) , level = "debug" ) ]
3725 pub ( super ) fn simplify_candidate < ' pat > (
3826 & mut self ,
39- candidate : & mut Candidate < ' pat , ' tcx > ,
40- ) -> bool {
27+ candidate_bindings : & mut Vec < Binding < ' tcx > > ,
28+ candidate_ascriptions : & mut Vec < Ascription < ' tcx > > ,
29+ candidate_match_pairs : & mut Vec < MatchPair < ' pat , ' tcx > > ,
30+ ) {
4131 // repeatedly simplify match pairs until fixed point is reached
42- debug ! ( "{candidate:#?}" ) ;
4332
4433 // existing_bindings and new_bindings exists to keep the semantics in order.
4534 // Reversing the binding order for bindings after `@` changes the binding order in places
@@ -59,28 +48,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
5948 // binding in iter 2: [6, 7]
6049 //
6150 // final binding: [1, 2, 3, 6, 7, 4, 5]
62- let mut existing_bindings = mem:: take ( & mut candidate . bindings ) ;
51+ let mut existing_bindings = mem:: take ( candidate_bindings ) ;
6352 let mut new_bindings = Vec :: new ( ) ;
6453 loop {
65- let match_pairs = mem:: take ( & mut candidate . match_pairs ) ;
54+ let mut match_pairs = mem:: take ( candidate_match_pairs ) ;
6655
67- if let [ MatchPair { pattern : Pat { kind : PatKind :: Or { pats } , .. } , place } ] =
68- & * match_pairs
56+ if let [ MatchPair { pattern : Pat { kind : PatKind :: Or { .. } , .. } , .. } ] = & * match_pairs
6957 {
7058 existing_bindings. extend_from_slice ( & new_bindings) ;
71- mem:: swap ( & mut candidate . bindings , & mut existing_bindings) ;
72- candidate . subcandidates = self . create_or_subcandidates ( candidate , place , pats ) ;
73- return true ;
59+ mem:: swap ( candidate_bindings , & mut existing_bindings) ;
60+ mem :: swap ( candidate_match_pairs , & mut match_pairs ) ;
61+ return ;
7462 }
7563
7664 let mut changed = false ;
7765 for match_pair in match_pairs {
78- match self . simplify_match_pair ( match_pair, candidate) {
66+ match self . simplify_match_pair (
67+ match_pair,
68+ candidate_bindings,
69+ candidate_ascriptions,
70+ candidate_match_pairs,
71+ ) {
7972 Ok ( ( ) ) => {
8073 changed = true ;
8174 }
8275 Err ( match_pair) => {
83- candidate . match_pairs . push ( match_pair) ;
76+ candidate_match_pairs . push ( match_pair) ;
8477 }
8578 }
8679 }
@@ -97,38 +90,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
9790 // let z = x.copy_field;
9891 // let y = x;
9992 // }
100- candidate . bindings . extend_from_slice ( & new_bindings) ;
101- mem:: swap ( & mut candidate . bindings , & mut new_bindings) ;
102- candidate . bindings . clear ( ) ;
93+ candidate_bindings . extend_from_slice ( & new_bindings) ;
94+ mem:: swap ( candidate_bindings , & mut new_bindings) ;
95+ candidate_bindings . clear ( ) ;
10396
10497 if !changed {
10598 existing_bindings. extend_from_slice ( & new_bindings) ;
106- mem:: swap ( & mut candidate . bindings , & mut existing_bindings) ;
99+ mem:: swap ( candidate_bindings , & mut existing_bindings) ;
107100 // Move or-patterns to the end, because they can result in us
108101 // creating additional candidates, so we want to test them as
109102 // late as possible.
110- candidate
111- . match_pairs
103+ candidate_match_pairs
112104 . sort_by_key ( |pair| matches ! ( pair. pattern. kind, PatKind :: Or { .. } ) ) ;
113- debug ! ( simplified = ?candidate , "simplify_candidate" ) ;
114- return false ; // if we were not able to simplify any, done.
105+ debug ! ( simplified = ?candidate_match_pairs , "simplify_candidate" ) ;
106+ return ; // if we were not able to simplify any, done.
115107 }
116108 }
117109 }
118110
119111 /// Given `candidate` that has a single or-pattern for its match-pairs,
120112 /// creates a fresh candidate for each of its input subpatterns passed via
121113 /// `pats`.
122- fn create_or_subcandidates < ' pat > (
114+ pub ( super ) fn create_or_subcandidates < ' pat > (
123115 & mut self ,
124- candidate : & Candidate < ' pat , ' tcx > ,
125116 place : & PlaceBuilder < ' tcx > ,
126117 pats : & ' pat [ Box < Pat < ' tcx > > ] ,
118+ has_guard : bool ,
127119 ) -> Vec < Candidate < ' pat , ' tcx > > {
128120 pats. iter ( )
129121 . map ( |box pat| {
130- let mut candidate = Candidate :: new ( place. clone ( ) , pat, candidate. has_guard , self ) ;
131- self . simplify_candidate ( & mut candidate) ;
122+ let mut candidate = Candidate :: new ( place. clone ( ) , pat, has_guard, self ) ;
123+ if let [ MatchPair { pattern : Pat { kind : PatKind :: Or { pats } , .. } , place, .. } ] =
124+ & * candidate. match_pairs
125+ {
126+ candidate. subcandidates =
127+ self . create_or_subcandidates ( place, pats, candidate. has_guard ) ;
128+ candidate. match_pairs . pop ( ) ;
129+ }
132130 candidate
133131 } )
134132 . collect ( )
@@ -141,8 +139,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
141139 /// candidate.
142140 fn simplify_match_pair < ' pat > (
143141 & mut self ,
144- match_pair : MatchPair < ' pat , ' tcx > ,
145- candidate : & mut Candidate < ' pat , ' tcx > ,
142+ mut match_pair : MatchPair < ' pat , ' tcx > ,
143+ bindings : & mut Vec < Binding < ' tcx > > ,
144+ ascriptions : & mut Vec < Ascription < ' tcx > > ,
145+ match_pairs : & mut Vec < MatchPair < ' pat , ' tcx > > ,
146146 ) -> Result < ( ) , MatchPair < ' pat , ' tcx > > {
147147 match match_pair. pattern . kind {
148148 PatKind :: AscribeUserType {
@@ -151,14 +151,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
151151 } => {
152152 // Apply the type ascription to the value at `match_pair.place`, which is the
153153 if let Some ( source) = match_pair. place . try_to_place ( self ) {
154- candidate . ascriptions . push ( Ascription {
154+ ascriptions. push ( Ascription {
155155 annotation : annotation. clone ( ) ,
156156 source,
157157 variance,
158158 } ) ;
159159 }
160160
161- candidate . match_pairs . push ( MatchPair :: new ( match_pair. place , subpattern, self ) ) ;
161+ match_pairs. push ( MatchPair :: new ( match_pair. place , subpattern, self ) ) ;
162162
163163 Ok ( ( ) )
164164 }
@@ -178,7 +178,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
178178 is_primary : _,
179179 } => {
180180 if let Some ( source) = match_pair. place . try_to_place ( self ) {
181- candidate . bindings . push ( Binding {
181+ bindings. push ( Binding {
182182 span : match_pair. pattern . span ,
183183 source,
184184 var_id : var,
@@ -188,7 +188,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
188188
189189 if let Some ( subpattern) = subpattern. as_ref ( ) {
190190 // this is the `x @ P` case; have to keep matching against `P` now
191- candidate . match_pairs . push ( MatchPair :: new ( match_pair. place , subpattern, self ) ) ;
191+ match_pairs. push ( MatchPair :: new ( match_pair. place , subpattern, self ) ) ;
192192 }
193193
194194 Ok ( ( ) )
@@ -206,7 +206,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
206206 }
207207
208208 PatKind :: InlineConstant { subpattern : ref pattern, def : _ } => {
209- candidate . match_pairs . push ( MatchPair :: new ( match_pair. place , pattern, self ) ) ;
209+ match_pairs. push ( MatchPair :: new ( match_pair. place , pattern, self ) ) ;
210210
211211 Ok ( ( ) )
212212 }
@@ -222,15 +222,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
222222 PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
223223 if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
224224 // irrefutable
225+ self . prefix_slice_suffix ( match_pairs, & match_pair. place , prefix, slice, suffix) ;
226+ Ok ( ( ) )
227+ } else {
225228 self . prefix_slice_suffix (
226- & mut candidate . match_pairs ,
229+ & mut match_pair . subpairs ,
227230 & match_pair. place ,
228231 prefix,
229232 slice,
230233 suffix,
231234 ) ;
232- Ok ( ( ) )
233- } else {
235+ self . simplify_candidate ( bindings, ascriptions, & mut match_pair. subpairs ) ;
234236 Err ( match_pair)
235237 }
236238 }
@@ -248,35 +250,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
248250 || !adt_def. is_variant_list_non_exhaustive ( ) ) ;
249251 if irrefutable {
250252 let place_builder = match_pair. place . downcast ( adt_def, variant_index) ;
251- candidate
252- . match_pairs
253- . extend ( self . field_match_pairs ( place_builder, subpatterns) ) ;
253+ match_pairs. extend ( self . field_match_pairs ( place_builder, subpatterns) ) ;
254254 Ok ( ( ) )
255255 } else {
256+ // If we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
257+ // we want to create a set of derived match-patterns like
258+ // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
259+ let downcast_place = match_pair. place . clone ( ) . downcast ( adt_def, variant_index) ; // `(x as Variant)`
260+ let consequent_match_pairs = subpatterns. iter ( ) . map ( |subpattern| {
261+ // e.g., `(x as Variant).0`
262+ let place = downcast_place. clone_project ( PlaceElem :: Field (
263+ subpattern. field ,
264+ subpattern. pattern . ty ,
265+ ) ) ;
266+ // e.g., `(x as Variant).0 @ P1`
267+ MatchPair :: new ( place, & subpattern. pattern , self )
268+ } ) ;
269+
270+ match_pair. subpairs . extend ( consequent_match_pairs) ;
271+ self . simplify_candidate ( bindings, ascriptions, & mut match_pair. subpairs ) ;
256272 Err ( match_pair)
257273 }
258274 }
259275
260276 PatKind :: Array { ref prefix, ref slice, ref suffix } => {
261- self . prefix_slice_suffix (
262- & mut candidate. match_pairs ,
263- & match_pair. place ,
264- prefix,
265- slice,
266- suffix,
267- ) ;
277+ self . prefix_slice_suffix ( match_pairs, & match_pair. place , prefix, slice, suffix) ;
268278 Ok ( ( ) )
269279 }
270280
271281 PatKind :: Leaf { ref subpatterns } => {
272282 // tuple struct, match subpats (if any)
273- candidate . match_pairs . extend ( self . field_match_pairs ( match_pair. place , subpatterns) ) ;
283+ match_pairs. extend ( self . field_match_pairs ( match_pair. place , subpatterns) ) ;
274284 Ok ( ( ) )
275285 }
276286
277287 PatKind :: Deref { ref subpattern } => {
278288 let place_builder = match_pair. place . deref ( ) ;
279- candidate . match_pairs . push ( MatchPair :: new ( place_builder, subpattern, self ) ) ;
289+ match_pairs. push ( MatchPair :: new ( place_builder, subpattern, self ) ) ;
280290 Ok ( ( ) )
281291 }
282292
0 commit comments