15
15
use crate :: build:: expr:: as_place:: PlaceBuilder ;
16
16
use crate :: build:: matches:: { Ascription , Binding , Candidate , MatchPair } ;
17
17
use crate :: build:: Builder ;
18
+ use rustc_middle:: mir:: PlaceElem ;
18
19
use rustc_middle:: thir:: { self , * } ;
19
-
20
20
use std:: mem;
21
21
22
22
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
23
23
/// 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" ) ]
37
25
pub ( super ) fn simplify_candidate < ' pat > (
38
26
& 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
+ ) {
41
31
// repeatedly simplify match pairs until fixed point is reached
42
- debug ! ( "{candidate:#?}" ) ;
43
32
44
33
// existing_bindings and new_bindings exists to keep the semantics in order.
45
34
// Reversing the binding order for bindings after `@` changes the binding order in places
@@ -59,28 +48,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
59
48
// binding in iter 2: [6, 7]
60
49
//
61
50
// 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 ) ;
63
52
let mut new_bindings = Vec :: new ( ) ;
64
53
loop {
65
- let match_pairs = mem:: take ( & mut candidate . match_pairs ) ;
54
+ let mut match_pairs = mem:: take ( candidate_match_pairs ) ;
66
55
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
69
57
{
70
58
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 ;
74
62
}
75
63
76
64
let mut changed = false ;
77
65
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
+ ) {
79
72
Ok ( ( ) ) => {
80
73
changed = true ;
81
74
}
82
75
Err ( match_pair) => {
83
- candidate . match_pairs . push ( match_pair) ;
76
+ candidate_match_pairs . push ( match_pair) ;
84
77
}
85
78
}
86
79
}
@@ -97,38 +90,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
97
90
// let z = x.copy_field;
98
91
// let y = x;
99
92
// }
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 ( ) ;
103
96
104
97
if !changed {
105
98
existing_bindings. extend_from_slice ( & new_bindings) ;
106
- mem:: swap ( & mut candidate . bindings , & mut existing_bindings) ;
99
+ mem:: swap ( candidate_bindings , & mut existing_bindings) ;
107
100
// Move or-patterns to the end, because they can result in us
108
101
// creating additional candidates, so we want to test them as
109
102
// late as possible.
110
- candidate
111
- . match_pairs
103
+ candidate_match_pairs
112
104
. 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.
115
107
}
116
108
}
117
109
}
118
110
119
111
/// Given `candidate` that has a single or-pattern for its match-pairs,
120
112
/// creates a fresh candidate for each of its input subpatterns passed via
121
113
/// `pats`.
122
- fn create_or_subcandidates < ' pat > (
114
+ pub ( super ) fn create_or_subcandidates < ' pat > (
123
115
& mut self ,
124
- candidate : & Candidate < ' pat , ' tcx > ,
125
116
place : & PlaceBuilder < ' tcx > ,
126
117
pats : & ' pat [ Box < Pat < ' tcx > > ] ,
118
+ has_guard : bool ,
127
119
) -> Vec < Candidate < ' pat , ' tcx > > {
128
120
pats. iter ( )
129
121
. 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
+ }
132
130
candidate
133
131
} )
134
132
. collect ( )
@@ -141,8 +139,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
141
139
/// candidate.
142
140
fn simplify_match_pair < ' pat > (
143
141
& 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 > > ,
146
146
) -> Result < ( ) , MatchPair < ' pat , ' tcx > > {
147
147
match match_pair. pattern . kind {
148
148
PatKind :: AscribeUserType {
@@ -151,14 +151,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
151
151
} => {
152
152
// Apply the type ascription to the value at `match_pair.place`, which is the
153
153
if let Some ( source) = match_pair. place . try_to_place ( self ) {
154
- candidate . ascriptions . push ( Ascription {
154
+ ascriptions. push ( Ascription {
155
155
annotation : annotation. clone ( ) ,
156
156
source,
157
157
variance,
158
158
} ) ;
159
159
}
160
160
161
- candidate . match_pairs . push ( MatchPair :: new ( match_pair. place , subpattern, self ) ) ;
161
+ match_pairs. push ( MatchPair :: new ( match_pair. place , subpattern, self ) ) ;
162
162
163
163
Ok ( ( ) )
164
164
}
@@ -178,7 +178,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
178
178
is_primary : _,
179
179
} => {
180
180
if let Some ( source) = match_pair. place . try_to_place ( self ) {
181
- candidate . bindings . push ( Binding {
181
+ bindings. push ( Binding {
182
182
span : match_pair. pattern . span ,
183
183
source,
184
184
var_id : var,
@@ -188,7 +188,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
188
188
189
189
if let Some ( subpattern) = subpattern. as_ref ( ) {
190
190
// 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 ) ) ;
192
192
}
193
193
194
194
Ok ( ( ) )
@@ -206,7 +206,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
206
206
}
207
207
208
208
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 ) ) ;
210
210
211
211
Ok ( ( ) )
212
212
}
@@ -222,15 +222,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
222
222
PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
223
223
if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
224
224
// irrefutable
225
+ self . prefix_slice_suffix ( match_pairs, & match_pair. place , prefix, slice, suffix) ;
226
+ Ok ( ( ) )
227
+ } else {
225
228
self . prefix_slice_suffix (
226
- & mut candidate . match_pairs ,
229
+ & mut match_pair . subpairs ,
227
230
& match_pair. place ,
228
231
prefix,
229
232
slice,
230
233
suffix,
231
234
) ;
232
- Ok ( ( ) )
233
- } else {
235
+ self . simplify_candidate ( bindings, ascriptions, & mut match_pair. subpairs ) ;
234
236
Err ( match_pair)
235
237
}
236
238
}
@@ -248,35 +250,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
248
250
|| !adt_def. is_variant_list_non_exhaustive ( ) ) ;
249
251
if irrefutable {
250
252
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) ) ;
254
254
Ok ( ( ) )
255
255
} 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 ) ;
256
272
Err ( match_pair)
257
273
}
258
274
}
259
275
260
276
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) ;
268
278
Ok ( ( ) )
269
279
}
270
280
271
281
PatKind :: Leaf { ref subpatterns } => {
272
282
// 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) ) ;
274
284
Ok ( ( ) )
275
285
}
276
286
277
287
PatKind :: Deref { ref subpattern } => {
278
288
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 ) ) ;
280
290
Ok ( ( ) )
281
291
}
282
292
0 commit comments