@@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt};
66
77use crate :: builder:: Builder ;
88use crate :: builder:: expr:: as_place:: { PlaceBase , PlaceBuilder } ;
9- use crate :: builder:: matches:: { FlatPat , MatchPairTree , TestCase } ;
9+ use crate :: builder:: matches:: { FlatPat , MatchPairTree , PatternExtraData , TestCase } ;
1010
1111impl < ' a , ' tcx > Builder < ' a , ' tcx > {
1212 /// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in
@@ -17,12 +17,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1717 fn field_match_pairs (
1818 & mut self ,
1919 match_pairs : & mut Vec < MatchPairTree < ' tcx > > ,
20+ extra_data : & mut PatternExtraData < ' tcx > ,
2021 place : PlaceBuilder < ' tcx > ,
2122 subpatterns : & [ FieldPat < ' tcx > ] ,
2223 ) {
2324 for fieldpat in subpatterns {
2425 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 ) ;
2627 }
2728 }
2829
@@ -33,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3334 fn prefix_slice_suffix (
3435 & mut self ,
3536 match_pairs : & mut Vec < MatchPairTree < ' tcx > > ,
37+ extra_data : & mut PatternExtraData < ' tcx > ,
3638 place : & PlaceBuilder < ' tcx > ,
3739 prefix : & [ Pat < ' tcx > ] ,
3840 opt_slice : & Option < Box < Pat < ' tcx > > > ,
@@ -57,7 +59,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
5759 let elem =
5860 ProjectionElem :: ConstantIndex { offset : idx as u64 , min_length, from_end : false } ;
5961 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 )
6163 }
6264
6365 if let Some ( subslice_pat) = opt_slice {
@@ -67,7 +69,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6769 to : if exact_size { min_length - suffix_len } else { suffix_len } ,
6870 from_end : !exact_size,
6971 } ) ;
70- MatchPairTree :: for_pattern ( subslice, subslice_pat, self , match_pairs) ;
72+ MatchPairTree :: for_pattern ( subslice, subslice_pat, self , match_pairs, extra_data ) ;
7173 }
7274
7375 for ( idx, subpattern) in suffix. iter ( ) . rev ( ) . enumerate ( ) {
@@ -78,19 +80,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
7880 from_end : !exact_size,
7981 } ;
8082 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 )
8284 }
8385 }
8486}
8587
8688impl < ' tcx > MatchPairTree < ' tcx > {
8789 /// Recursively builds a match pair tree for the given pattern and its
8890 /// subpatterns.
89- pub ( in crate :: builder ) fn for_pattern (
91+ pub ( super ) fn for_pattern (
9092 mut place_builder : PlaceBuilder < ' tcx > ,
9193 pattern : & Pat < ' tcx > ,
9294 cx : & mut Builder < ' _ , ' tcx > ,
9395 match_pairs : & mut Vec < Self > , // Newly-created nodes are added to this vector
96+ extra_data : & mut PatternExtraData < ' tcx > , // Bindings/ascriptions are added here
9497 ) {
9598 // Force the place type to the pattern's type.
9699 // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
@@ -113,7 +116,7 @@ impl<'tcx> MatchPairTree<'tcx> {
113116 }
114117
115118 let place = place_builder. try_to_place ( cx) ;
116- let default_irrefutable = || TestCase :: Irrefutable { binding : None , ascription : None } ;
119+ let default_irrefutable = || TestCase :: Irrefutable { } ;
117120 let mut subpairs = Vec :: new ( ) ;
118121 let test_case = match pattern. kind {
119122 PatKind :: Wild | PatKind :: Error ( _) => default_irrefutable ( ) ,
@@ -137,39 +140,77 @@ impl<'tcx> MatchPairTree<'tcx> {
137140 ref subpattern,
138141 ..
139142 } => {
143+ MatchPairTree :: for_pattern (
144+ place_builder,
145+ subpattern,
146+ cx,
147+ & mut subpairs,
148+ extra_data,
149+ ) ;
150+
140151 // 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 ( )
149158 }
150159
151160 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+ // ```
158179
180+ // First, recurse into the subpattern, if any.
159181 if let Some ( subpattern) = subpattern. as_ref ( ) {
160182 // 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+ } ) ;
162200 }
163- TestCase :: Irrefutable { ascription : None , binding }
201+
202+ default_irrefutable ( )
164203 }
165204
166205 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 ) ;
168207 default_irrefutable ( )
169208 }
170209 PatKind :: ExpandedConstant { subpattern : ref pattern, def_id, is_inline : true } => {
210+ MatchPairTree :: for_pattern ( place_builder, pattern, cx, & mut subpairs, extra_data) ;
211+
171212 // 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 {
173214 let span = pattern. span ;
174215 let parent_id = cx. tcx . typeck_root_def_id ( cx. def_id . to_def_id ( ) ) ;
175216 let args = ty:: InlineConstArgs :: new (
@@ -188,19 +229,33 @@ impl<'tcx> MatchPairTree<'tcx> {
188229 span,
189230 user_ty : Box :: new ( user_ty) ,
190231 } ;
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+ }
193235
194- MatchPairTree :: for_pattern ( place_builder, pattern, cx, & mut subpairs) ;
195- TestCase :: Irrefutable { ascription, binding : None }
236+ default_irrefutable ( )
196237 }
197238
198239 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+ ) ;
200248 default_irrefutable ( )
201249 }
202250 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+ ) ;
204259
205260 if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
206261 default_irrefutable ( )
@@ -214,7 +269,7 @@ impl<'tcx> MatchPairTree<'tcx> {
214269
215270 PatKind :: Variant { adt_def, variant_index, args, ref subpatterns } => {
216271 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) ;
218273
219274 let irrefutable = adt_def. variants ( ) . iter_enumerated ( ) . all ( |( i, v) | {
220275 i == variant_index
@@ -232,12 +287,18 @@ impl<'tcx> MatchPairTree<'tcx> {
232287 }
233288
234289 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) ;
236291 default_irrefutable ( )
237292 }
238293
239294 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+ ) ;
241302 default_irrefutable ( )
242303 }
243304
@@ -253,6 +314,7 @@ impl<'tcx> MatchPairTree<'tcx> {
253314 subpattern,
254315 cx,
255316 & mut subpairs,
317+ extra_data,
256318 ) ;
257319 TestCase :: Deref { temp, mutability }
258320 }
0 commit comments