@@ -6,27 +6,25 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt};
6
6
7
7
use crate :: builder:: Builder ;
8
8
use crate :: builder:: expr:: as_place:: { PlaceBase , PlaceBuilder } ;
9
- use crate :: builder:: matches:: { FlatPat , MatchPairTree , TestCase } ;
9
+ use crate :: builder:: matches:: { FlatPat , MatchPairTree , PatternExtraData , TestCase } ;
10
10
11
11
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
12
- /// Builds and returns [`MatchPairTree`] subtrees, one for each pattern in
12
+ /// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in
13
13
/// `subpatterns`, representing the fields of a [`PatKind::Variant`] or
14
14
/// [`PatKind::Leaf`].
15
15
///
16
16
/// Used internally by [`MatchPairTree::for_pattern`].
17
17
fn field_match_pairs (
18
18
& mut self ,
19
+ match_pairs : & mut Vec < MatchPairTree < ' tcx > > ,
20
+ extra_data : & mut PatternExtraData < ' tcx > ,
19
21
place : PlaceBuilder < ' tcx > ,
20
22
subpatterns : & [ FieldPat < ' tcx > ] ,
21
- ) -> Vec < MatchPairTree < ' tcx > > {
22
- subpatterns
23
- . iter ( )
24
- . map ( |fieldpat| {
25
- let place =
26
- place. clone_project ( PlaceElem :: Field ( fieldpat. field , fieldpat. pattern . ty ) ) ;
27
- MatchPairTree :: for_pattern ( place, & fieldpat. pattern , self )
28
- } )
29
- . collect ( )
23
+ ) {
24
+ for fieldpat in subpatterns {
25
+ let place = place. clone_project ( PlaceElem :: Field ( fieldpat. field , fieldpat. pattern . ty ) ) ;
26
+ MatchPairTree :: for_pattern ( place, & fieldpat. pattern , self , match_pairs, extra_data) ;
27
+ }
30
28
}
31
29
32
30
/// Builds [`MatchPairTree`] subtrees for the prefix/middle/suffix parts of an
@@ -36,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
36
34
fn prefix_slice_suffix (
37
35
& mut self ,
38
36
match_pairs : & mut Vec < MatchPairTree < ' tcx > > ,
37
+ extra_data : & mut PatternExtraData < ' tcx > ,
39
38
place : & PlaceBuilder < ' tcx > ,
40
39
prefix : & [ Pat < ' tcx > ] ,
41
40
opt_slice : & Option < Box < Pat < ' tcx > > > ,
@@ -56,11 +55,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
56
55
( ( prefix. len ( ) + suffix. len ( ) ) . try_into ( ) . unwrap ( ) , false )
57
56
} ;
58
57
59
- match_pairs . extend ( prefix. iter ( ) . enumerate ( ) . map ( | ( idx , subpattern ) | {
58
+ for ( idx , subpattern ) in prefix. iter ( ) . enumerate ( ) {
60
59
let elem =
61
60
ProjectionElem :: ConstantIndex { offset : idx as u64 , min_length, from_end : false } ;
62
- MatchPairTree :: for_pattern ( place. clone_project ( elem) , subpattern, self )
63
- } ) ) ;
61
+ let place = place. clone_project ( elem) ;
62
+ MatchPairTree :: for_pattern ( place, subpattern, self , match_pairs, extra_data)
63
+ }
64
64
65
65
if let Some ( subslice_pat) = opt_slice {
66
66
let suffix_len = suffix. len ( ) as u64 ;
@@ -69,30 +69,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
69
69
to : if exact_size { min_length - suffix_len } else { suffix_len } ,
70
70
from_end : !exact_size,
71
71
} ) ;
72
- match_pairs . push ( MatchPairTree :: for_pattern ( subslice, subslice_pat, self ) ) ;
72
+ MatchPairTree :: for_pattern ( subslice, subslice_pat, self , match_pairs , extra_data ) ;
73
73
}
74
74
75
- match_pairs . extend ( suffix. iter ( ) . rev ( ) . enumerate ( ) . map ( | ( idx , subpattern ) | {
75
+ for ( idx , subpattern ) in suffix. iter ( ) . rev ( ) . enumerate ( ) {
76
76
let end_offset = ( idx + 1 ) as u64 ;
77
77
let elem = ProjectionElem :: ConstantIndex {
78
78
offset : if exact_size { min_length - end_offset } else { end_offset } ,
79
79
min_length,
80
80
from_end : !exact_size,
81
81
} ;
82
82
let place = place. clone_project ( elem) ;
83
- MatchPairTree :: for_pattern ( place, subpattern, self )
84
- } ) ) ;
83
+ MatchPairTree :: for_pattern ( place, subpattern, self , match_pairs , extra_data )
84
+ }
85
85
}
86
86
}
87
87
88
88
impl < ' tcx > MatchPairTree < ' tcx > {
89
89
/// Recursively builds a match pair tree for the given pattern and its
90
90
/// subpatterns.
91
- pub ( in crate :: builder ) fn for_pattern (
91
+ pub ( super ) fn for_pattern (
92
92
mut place_builder : PlaceBuilder < ' tcx > ,
93
93
pattern : & Pat < ' tcx > ,
94
94
cx : & mut Builder < ' _ , ' tcx > ,
95
- ) -> MatchPairTree < ' tcx > {
95
+ match_pairs : & mut Vec < Self > , // Newly-created nodes are added to this vector
96
+ extra_data : & mut PatternExtraData < ' tcx > , // Bindings/ascriptions are added here
97
+ ) {
96
98
// Force the place type to the pattern's type.
97
99
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
98
100
if let Some ( resolved) = place_builder. resolve_upvar ( cx) {
@@ -113,64 +115,102 @@ impl<'tcx> MatchPairTree<'tcx> {
113
115
place_builder = place_builder. project ( ProjectionElem :: OpaqueCast ( pattern. ty ) ) ;
114
116
}
115
117
118
+ // Place can be none if the pattern refers to a non-captured place in a closure.
116
119
let place = place_builder. try_to_place ( cx) ;
117
- let default_irrefutable = || TestCase :: Irrefutable { binding : None , ascription : None } ;
118
120
let mut subpairs = Vec :: new ( ) ;
119
121
let test_case = match pattern. kind {
120
- PatKind :: Wild | PatKind :: Error ( _) => default_irrefutable ( ) ,
122
+ PatKind :: Wild | PatKind :: Error ( _) => None ,
121
123
122
- PatKind :: Or { ref pats } => TestCase :: Or {
124
+ PatKind :: Or { ref pats } => Some ( TestCase :: Or {
123
125
pats : pats. iter ( ) . map ( |pat| FlatPat :: new ( place_builder. clone ( ) , pat, cx) ) . collect ( ) ,
124
- } ,
126
+ } ) ,
125
127
126
128
PatKind :: Range ( ref range) => {
127
129
if range. is_full_range ( cx. tcx ) == Some ( true ) {
128
- default_irrefutable ( )
130
+ None
129
131
} else {
130
- TestCase :: Range ( Arc :: clone ( range) )
132
+ Some ( TestCase :: Range ( Arc :: clone ( range) ) )
131
133
}
132
134
}
133
135
134
- PatKind :: Constant { value } => TestCase :: Constant { value } ,
136
+ PatKind :: Constant { value } => Some ( TestCase :: Constant { value } ) ,
135
137
136
138
PatKind :: AscribeUserType {
137
139
ascription : Ascription { ref annotation, variance } ,
138
140
ref subpattern,
139
141
..
140
142
} => {
143
+ MatchPairTree :: for_pattern (
144
+ place_builder,
145
+ subpattern,
146
+ cx,
147
+ & mut subpairs,
148
+ extra_data,
149
+ ) ;
150
+
141
151
// Apply the type ascription to the value at `match_pair.place`
142
- let ascription = place. map ( |source| super :: Ascription {
143
- annotation : annotation. clone ( ) ,
144
- source,
145
- variance,
146
- } ) ;
147
-
148
- subpairs. push ( MatchPairTree :: for_pattern ( place_builder, subpattern, cx) ) ;
149
- TestCase :: Irrefutable { ascription, binding : None }
152
+ if let Some ( source) = place {
153
+ let annotation = annotation. clone ( ) ;
154
+ extra_data. ascriptions . push ( super :: Ascription { source, annotation, variance } ) ;
155
+ }
156
+
157
+ None
150
158
}
151
159
152
160
PatKind :: Binding { mode, var, ref subpattern, .. } => {
153
- let binding = place. map ( |source| super :: Binding {
154
- span : pattern. span ,
155
- source,
156
- var_id : var,
157
- binding_mode : mode,
158
- } ) ;
161
+ // In order to please the borrow checker, when lowering a pattern
162
+ // like `x @ subpat` we must establish any bindings in `subpat`
163
+ // before establishing the binding for `x`.
164
+ //
165
+ // For example (from #69971):
166
+ //
167
+ // ```ignore (illustrative)
168
+ // struct NonCopyStruct {
169
+ // copy_field: u32,
170
+ // }
171
+ //
172
+ // fn foo1(x: NonCopyStruct) {
173
+ // let y @ NonCopyStruct { copy_field: z } = x;
174
+ // // the above should turn into
175
+ // let z = x.copy_field;
176
+ // let y = x;
177
+ // }
178
+ // ```
159
179
180
+ // First, recurse into the subpattern, if any.
160
181
if let Some ( subpattern) = subpattern. as_ref ( ) {
161
182
// this is the `x @ P` case; have to keep matching against `P` now
162
- subpairs. push ( MatchPairTree :: for_pattern ( place_builder, subpattern, cx) ) ;
183
+ MatchPairTree :: for_pattern (
184
+ place_builder,
185
+ subpattern,
186
+ cx,
187
+ & mut subpairs,
188
+ extra_data,
189
+ ) ;
163
190
}
164
- TestCase :: Irrefutable { ascription : None , binding }
191
+
192
+ // Then push this binding, after any bindings in the subpattern.
193
+ if let Some ( source) = place {
194
+ extra_data. bindings . push ( super :: Binding {
195
+ span : pattern. span ,
196
+ source,
197
+ var_id : var,
198
+ binding_mode : mode,
199
+ } ) ;
200
+ }
201
+
202
+ None
165
203
}
166
204
167
205
PatKind :: ExpandedConstant { subpattern : ref pattern, def_id : _, is_inline : false } => {
168
- subpairs . push ( MatchPairTree :: for_pattern ( place_builder, pattern, cx) ) ;
169
- default_irrefutable ( )
206
+ MatchPairTree :: for_pattern ( place_builder, pattern, cx, & mut subpairs , extra_data ) ;
207
+ None
170
208
}
171
209
PatKind :: ExpandedConstant { subpattern : ref pattern, def_id, is_inline : true } => {
210
+ MatchPairTree :: for_pattern ( place_builder, pattern, cx, & mut subpairs, extra_data) ;
211
+
172
212
// Apply a type ascription for the inline constant to the value at `match_pair.place`
173
- let ascription = place. map ( |source| {
213
+ if let Some ( source ) = place {
174
214
let span = pattern. span ;
175
215
let parent_id = cx. tcx . typeck_root_def_id ( cx. def_id . to_def_id ( ) ) ;
176
216
let args = ty:: InlineConstArgs :: new (
@@ -189,33 +229,47 @@ impl<'tcx> MatchPairTree<'tcx> {
189
229
span,
190
230
user_ty : Box :: new ( user_ty) ,
191
231
} ;
192
- super :: Ascription { annotation, source, variance : ty:: Contravariant }
193
- } ) ;
232
+ let variance = ty:: Contravariant ;
233
+ extra_data. ascriptions . push ( super :: Ascription { annotation, source, variance } ) ;
234
+ }
194
235
195
- subpairs. push ( MatchPairTree :: for_pattern ( place_builder, pattern, cx) ) ;
196
- TestCase :: Irrefutable { ascription, binding : None }
236
+ None
197
237
}
198
238
199
239
PatKind :: Array { ref prefix, ref slice, ref suffix } => {
200
- cx. prefix_slice_suffix ( & mut subpairs, & place_builder, prefix, slice, suffix) ;
201
- default_irrefutable ( )
240
+ cx. prefix_slice_suffix (
241
+ & mut subpairs,
242
+ extra_data,
243
+ & place_builder,
244
+ prefix,
245
+ slice,
246
+ suffix,
247
+ ) ;
248
+ None
202
249
}
203
250
PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
204
- cx. prefix_slice_suffix ( & mut subpairs, & place_builder, prefix, slice, suffix) ;
251
+ cx. prefix_slice_suffix (
252
+ & mut subpairs,
253
+ extra_data,
254
+ & place_builder,
255
+ prefix,
256
+ slice,
257
+ suffix,
258
+ ) ;
205
259
206
260
if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
207
- default_irrefutable ( )
261
+ None
208
262
} else {
209
- TestCase :: Slice {
263
+ Some ( TestCase :: Slice {
210
264
len : prefix. len ( ) + suffix. len ( ) ,
211
265
variable_length : slice. is_some ( ) ,
212
- }
266
+ } )
213
267
}
214
268
}
215
269
216
270
PatKind :: Variant { adt_def, variant_index, args, ref subpatterns } => {
217
271
let downcast_place = place_builder. downcast ( adt_def, variant_index) ; // `(x as Variant)`
218
- subpairs = cx. field_match_pairs ( downcast_place, subpatterns) ;
272
+ cx. field_match_pairs ( & mut subpairs , extra_data , downcast_place, subpatterns) ;
219
273
220
274
let irrefutable = adt_def. variants ( ) . iter_enumerated ( ) . all ( |( i, v) | {
221
275
i == variant_index
@@ -225,21 +279,23 @@ impl<'tcx> MatchPairTree<'tcx> {
225
279
. apply_ignore_module ( cx. tcx , cx. infcx . typing_env ( cx. param_env ) )
226
280
} ) && ( adt_def. did ( ) . is_local ( )
227
281
|| !adt_def. is_variant_list_non_exhaustive ( ) ) ;
228
- if irrefutable {
229
- default_irrefutable ( )
230
- } else {
231
- TestCase :: Variant { adt_def, variant_index }
232
- }
282
+ if irrefutable { None } else { Some ( TestCase :: Variant { adt_def, variant_index } ) }
233
283
}
234
284
235
285
PatKind :: Leaf { ref subpatterns } => {
236
- subpairs = cx. field_match_pairs ( place_builder, subpatterns) ;
237
- default_irrefutable ( )
286
+ cx. field_match_pairs ( & mut subpairs , extra_data , place_builder, subpatterns) ;
287
+ None
238
288
}
239
289
240
290
PatKind :: Deref { ref subpattern } => {
241
- subpairs. push ( MatchPairTree :: for_pattern ( place_builder. deref ( ) , subpattern, cx) ) ;
242
- default_irrefutable ( )
291
+ MatchPairTree :: for_pattern (
292
+ place_builder. deref ( ) ,
293
+ subpattern,
294
+ cx,
295
+ & mut subpairs,
296
+ extra_data,
297
+ ) ;
298
+ None
243
299
}
244
300
245
301
PatKind :: DerefPattern { ref subpattern, mutability } => {
@@ -249,23 +305,32 @@ impl<'tcx> MatchPairTree<'tcx> {
249
305
Ty :: new_ref ( cx. tcx , cx. tcx . lifetimes . re_erased , subpattern. ty , mutability) ,
250
306
pattern. span ,
251
307
) ;
252
- subpairs . push ( MatchPairTree :: for_pattern (
308
+ MatchPairTree :: for_pattern (
253
309
PlaceBuilder :: from ( temp) . deref ( ) ,
254
310
subpattern,
255
311
cx,
256
- ) ) ;
257
- TestCase :: Deref { temp, mutability }
312
+ & mut subpairs,
313
+ extra_data,
314
+ ) ;
315
+ Some ( TestCase :: Deref { temp, mutability } )
258
316
}
259
317
260
- PatKind :: Never => TestCase :: Never ,
318
+ PatKind :: Never => Some ( TestCase :: Never ) ,
261
319
} ;
262
320
263
- MatchPairTree {
264
- place,
265
- test_case,
266
- subpairs,
267
- pattern_ty : pattern. ty ,
268
- pattern_span : pattern. span ,
321
+ if let Some ( test_case) = test_case {
322
+ // This pattern is refutable, so push a new match-pair node.
323
+ match_pairs. push ( MatchPairTree {
324
+ place : place. expect ( "refutable patterns should always have a place to inspect" ) ,
325
+ test_case,
326
+ subpairs,
327
+ pattern_ty : pattern. ty ,
328
+ pattern_span : pattern. span ,
329
+ } )
330
+ } else {
331
+ // This pattern is irrefutable, so it doesn't need its own match-pair node.
332
+ // Just push its refutable subpatterns instead, if any.
333
+ match_pairs. extend ( subpairs) ;
269
334
}
270
335
}
271
336
}
0 commit comments