@@ -6,7 +6,7 @@ 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
12
/// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in
@@ -17,12 +17,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17
17
fn field_match_pairs (
18
18
& mut self ,
19
19
match_pairs : & mut Vec < MatchPairTree < ' tcx > > ,
20
+ extra_data : & mut PatternExtraData < ' tcx > ,
20
21
place : PlaceBuilder < ' tcx > ,
21
22
subpatterns : & [ FieldPat < ' tcx > ] ,
22
23
) {
23
24
for fieldpat in subpatterns {
24
25
let place = place. clone_project ( PlaceElem :: Field ( fieldpat. field , fieldpat. pattern . ty ) ) ;
25
- MatchPairTree :: for_pattern ( place, & fieldpat. pattern , self , match_pairs) ;
26
+ MatchPairTree :: for_pattern ( place, & fieldpat. pattern , self , match_pairs, extra_data ) ;
26
27
}
27
28
}
28
29
@@ -33,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
33
34
fn prefix_slice_suffix (
34
35
& mut self ,
35
36
match_pairs : & mut Vec < MatchPairTree < ' tcx > > ,
37
+ extra_data : & mut PatternExtraData < ' tcx > ,
36
38
place : & PlaceBuilder < ' tcx > ,
37
39
prefix : & [ Pat < ' tcx > ] ,
38
40
opt_slice : & Option < Box < Pat < ' tcx > > > ,
@@ -57,7 +59,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
57
59
let elem =
58
60
ProjectionElem :: ConstantIndex { offset : idx as u64 , min_length, from_end : false } ;
59
61
let place = place. clone_project ( elem) ;
60
- MatchPairTree :: for_pattern ( place, subpattern, self , match_pairs) ;
62
+ MatchPairTree :: for_pattern ( place, subpattern, self , match_pairs, extra_data )
61
63
}
62
64
63
65
if let Some ( subslice_pat) = opt_slice {
@@ -67,7 +69,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
67
69
to : if exact_size { min_length - suffix_len } else { suffix_len } ,
68
70
from_end : !exact_size,
69
71
} ) ;
70
- MatchPairTree :: for_pattern ( subslice, subslice_pat, self , match_pairs) ;
72
+ MatchPairTree :: for_pattern ( subslice, subslice_pat, self , match_pairs, extra_data ) ;
71
73
}
72
74
73
75
for ( idx, subpattern) in suffix. iter ( ) . rev ( ) . enumerate ( ) {
@@ -78,19 +80,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
78
80
from_end : !exact_size,
79
81
} ;
80
82
let place = place. clone_project ( elem) ;
81
- MatchPairTree :: for_pattern ( place, subpattern, self , match_pairs) ;
83
+ MatchPairTree :: for_pattern ( place, subpattern, self , match_pairs, extra_data )
82
84
}
83
85
}
84
86
}
85
87
86
88
impl < ' tcx > MatchPairTree < ' tcx > {
87
89
/// Recursively builds a match pair tree for the given pattern and its
88
90
/// subpatterns.
89
- pub ( in crate :: builder ) fn for_pattern (
91
+ pub ( super ) fn for_pattern (
90
92
mut place_builder : PlaceBuilder < ' tcx > ,
91
93
pattern : & Pat < ' tcx > ,
92
94
cx : & mut Builder < ' _ , ' tcx > ,
93
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
94
97
) {
95
98
// Force the place type to the pattern's type.
96
99
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
@@ -113,7 +116,7 @@ impl<'tcx> MatchPairTree<'tcx> {
113
116
}
114
117
115
118
let place = place_builder. try_to_place ( cx) ;
116
- let default_irrefutable = || TestCase :: Irrefutable { binding : None , ascription : None } ;
119
+ let default_irrefutable = || TestCase :: Irrefutable { } ;
117
120
let mut subpairs = Vec :: new ( ) ;
118
121
let test_case = match pattern. kind {
119
122
PatKind :: Wild | PatKind :: Error ( _) => default_irrefutable ( ) ,
@@ -137,39 +140,77 @@ impl<'tcx> MatchPairTree<'tcx> {
137
140
ref subpattern,
138
141
..
139
142
} => {
143
+ MatchPairTree :: for_pattern (
144
+ place_builder,
145
+ subpattern,
146
+ cx,
147
+ & mut subpairs,
148
+ extra_data,
149
+ ) ;
150
+
140
151
// Apply the type ascription to the value at `match_pair.place`
141
- let ascription = place. map ( |source| super :: Ascription {
142
- annotation : annotation. clone ( ) ,
143
- source,
144
- variance,
145
- } ) ;
146
-
147
- MatchPairTree :: for_pattern ( place_builder, subpattern, cx, & mut subpairs) ;
148
- 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
+ default_irrefutable ( )
149
158
}
150
159
151
160
PatKind :: Binding { mode, var, ref subpattern, .. } => {
152
- let binding = place. map ( |source| super :: Binding {
153
- span : pattern. span ,
154
- source,
155
- var_id : var,
156
- binding_mode : mode,
157
- } ) ;
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
+ // ```
158
179
180
+ // First, recurse into the subpattern, if any.
159
181
if let Some ( subpattern) = subpattern. as_ref ( ) {
160
182
// this is the `x @ P` case; have to keep matching against `P` now
161
- MatchPairTree :: for_pattern ( place_builder, subpattern, cx, & mut subpairs) ;
183
+ MatchPairTree :: for_pattern (
184
+ place_builder,
185
+ subpattern,
186
+ cx,
187
+ & mut subpairs,
188
+ extra_data,
189
+ ) ;
190
+ }
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
+ } ) ;
162
200
}
163
- TestCase :: Irrefutable { ascription : None , binding }
201
+
202
+ default_irrefutable ( )
164
203
}
165
204
166
205
PatKind :: ExpandedConstant { subpattern : ref pattern, def_id : _, is_inline : false } => {
167
- MatchPairTree :: for_pattern ( place_builder, pattern, cx, & mut subpairs) ;
206
+ MatchPairTree :: for_pattern ( place_builder, pattern, cx, & mut subpairs, extra_data ) ;
168
207
default_irrefutable ( )
169
208
}
170
209
PatKind :: ExpandedConstant { subpattern : ref pattern, def_id, is_inline : true } => {
210
+ MatchPairTree :: for_pattern ( place_builder, pattern, cx, & mut subpairs, extra_data) ;
211
+
171
212
// Apply a type ascription for the inline constant to the value at `match_pair.place`
172
- let ascription = place. map ( |source| {
213
+ if let Some ( source ) = place {
173
214
let span = pattern. span ;
174
215
let parent_id = cx. tcx . typeck_root_def_id ( cx. def_id . to_def_id ( ) ) ;
175
216
let args = ty:: InlineConstArgs :: new (
@@ -188,19 +229,33 @@ impl<'tcx> MatchPairTree<'tcx> {
188
229
span,
189
230
user_ty : Box :: new ( user_ty) ,
190
231
} ;
191
- super :: Ascription { annotation, source, variance : ty:: Contravariant }
192
- } ) ;
232
+ let variance = ty:: Contravariant ;
233
+ extra_data. ascriptions . push ( super :: Ascription { annotation, source, variance } ) ;
234
+ }
193
235
194
- MatchPairTree :: for_pattern ( place_builder, pattern, cx, & mut subpairs) ;
195
- TestCase :: Irrefutable { ascription, binding : None }
236
+ default_irrefutable ( )
196
237
}
197
238
198
239
PatKind :: Array { ref prefix, ref slice, ref suffix } => {
199
- cx. prefix_slice_suffix ( & mut subpairs, & place_builder, prefix, slice, suffix) ;
240
+ cx. prefix_slice_suffix (
241
+ & mut subpairs,
242
+ extra_data,
243
+ & place_builder,
244
+ prefix,
245
+ slice,
246
+ suffix,
247
+ ) ;
200
248
default_irrefutable ( )
201
249
}
202
250
PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
203
- 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
+ ) ;
204
259
205
260
if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
206
261
default_irrefutable ( )
@@ -214,7 +269,7 @@ impl<'tcx> MatchPairTree<'tcx> {
214
269
215
270
PatKind :: Variant { adt_def, variant_index, args, ref subpatterns } => {
216
271
let downcast_place = place_builder. downcast ( adt_def, variant_index) ; // `(x as Variant)`
217
- cx. field_match_pairs ( & mut subpairs, downcast_place, subpatterns) ;
272
+ cx. field_match_pairs ( & mut subpairs, extra_data , downcast_place, subpatterns) ;
218
273
219
274
let irrefutable = adt_def. variants ( ) . iter_enumerated ( ) . all ( |( i, v) | {
220
275
i == variant_index
@@ -232,12 +287,18 @@ impl<'tcx> MatchPairTree<'tcx> {
232
287
}
233
288
234
289
PatKind :: Leaf { ref subpatterns } => {
235
- cx. field_match_pairs ( & mut subpairs, place_builder, subpatterns) ;
290
+ cx. field_match_pairs ( & mut subpairs, extra_data , place_builder, subpatterns) ;
236
291
default_irrefutable ( )
237
292
}
238
293
239
294
PatKind :: Deref { ref subpattern } => {
240
- MatchPairTree :: for_pattern ( place_builder. deref ( ) , subpattern, cx, & mut subpairs) ;
295
+ MatchPairTree :: for_pattern (
296
+ place_builder. deref ( ) ,
297
+ subpattern,
298
+ cx,
299
+ & mut subpairs,
300
+ extra_data,
301
+ ) ;
241
302
default_irrefutable ( )
242
303
}
243
304
@@ -253,6 +314,7 @@ impl<'tcx> MatchPairTree<'tcx> {
253
314
subpattern,
254
315
cx,
255
316
& mut subpairs,
317
+ extra_data,
256
318
) ;
257
319
TestCase :: Deref { temp, mutability }
258
320
}
0 commit comments