@@ -6,27 +6,25 @@ 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 > {
12- /// Builds and returns [`MatchPairTree`] subtrees, one for each pattern in
12+ /// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in
1313 /// `subpatterns`, representing the fields of a [`PatKind::Variant`] or
1414 /// [`PatKind::Leaf`].
1515 ///
1616 /// Used internally by [`MatchPairTree::for_pattern`].
1717 fn field_match_pairs (
1818 & mut self ,
19+ match_pairs : & mut Vec < MatchPairTree < ' tcx > > ,
20+ extra_data : & mut PatternExtraData < ' tcx > ,
1921 place : PlaceBuilder < ' tcx > ,
2022 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+ }
3028 }
3129
3230 /// Builds [`MatchPairTree`] subtrees for the prefix/middle/suffix parts of an
@@ -36,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3634 fn prefix_slice_suffix (
3735 & mut self ,
3836 match_pairs : & mut Vec < MatchPairTree < ' tcx > > ,
37+ extra_data : & mut PatternExtraData < ' tcx > ,
3938 place : & PlaceBuilder < ' tcx > ,
4039 prefix : & [ Pat < ' tcx > ] ,
4140 opt_slice : & Option < Box < Pat < ' tcx > > > ,
@@ -56,11 +55,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
5655 ( ( prefix. len ( ) + suffix. len ( ) ) . try_into ( ) . unwrap ( ) , false )
5756 } ;
5857
59- match_pairs . extend ( prefix. iter ( ) . enumerate ( ) . map ( | ( idx , subpattern ) | {
58+ for ( idx , subpattern ) in prefix. iter ( ) . enumerate ( ) {
6059 let elem =
6160 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+ }
6464
6565 if let Some ( subslice_pat) = opt_slice {
6666 let suffix_len = suffix. len ( ) as u64 ;
@@ -69,30 +69,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6969 to : if exact_size { min_length - suffix_len } else { suffix_len } ,
7070 from_end : !exact_size,
7171 } ) ;
72- match_pairs . push ( MatchPairTree :: for_pattern ( subslice, subslice_pat, self ) ) ;
72+ MatchPairTree :: for_pattern ( subslice, subslice_pat, self , match_pairs , extra_data ) ;
7373 }
7474
75- match_pairs . extend ( suffix. iter ( ) . rev ( ) . enumerate ( ) . map ( | ( idx , subpattern ) | {
75+ for ( idx , subpattern ) in suffix. iter ( ) . rev ( ) . enumerate ( ) {
7676 let end_offset = ( idx + 1 ) as u64 ;
7777 let elem = ProjectionElem :: ConstantIndex {
7878 offset : if exact_size { min_length - end_offset } else { end_offset } ,
7979 min_length,
8080 from_end : !exact_size,
8181 } ;
8282 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+ }
8585 }
8686}
8787
8888impl < ' tcx > MatchPairTree < ' tcx > {
8989 /// Recursively builds a match pair tree for the given pattern and its
9090 /// subpatterns.
91- pub ( in crate :: builder ) fn for_pattern (
91+ pub ( super ) fn for_pattern (
9292 mut place_builder : PlaceBuilder < ' tcx > ,
9393 pattern : & Pat < ' tcx > ,
9494 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+ ) {
9698 // Force the place type to the pattern's type.
9799 // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
98100 if let Some ( resolved) = place_builder. resolve_upvar ( cx) {
@@ -113,64 +115,102 @@ impl<'tcx> MatchPairTree<'tcx> {
113115 place_builder = place_builder. project ( ProjectionElem :: OpaqueCast ( pattern. ty ) ) ;
114116 }
115117
118+ // Place can be none if the pattern refers to a non-captured place in a closure.
116119 let place = place_builder. try_to_place ( cx) ;
117- let default_irrefutable = || TestCase :: Irrefutable { binding : None , ascription : None } ;
118120 let mut subpairs = Vec :: new ( ) ;
119121 let test_case = match pattern. kind {
120- PatKind :: Wild | PatKind :: Error ( _) => default_irrefutable ( ) ,
122+ PatKind :: Wild | PatKind :: Error ( _) => None ,
121123
122- PatKind :: Or { ref pats } => TestCase :: Or {
124+ PatKind :: Or { ref pats } => Some ( TestCase :: Or {
123125 pats : pats. iter ( ) . map ( |pat| FlatPat :: new ( place_builder. clone ( ) , pat, cx) ) . collect ( ) ,
124- } ,
126+ } ) ,
125127
126128 PatKind :: Range ( ref range) => {
127129 if range. is_full_range ( cx. tcx ) == Some ( true ) {
128- default_irrefutable ( )
130+ None
129131 } else {
130- TestCase :: Range ( Arc :: clone ( range) )
132+ Some ( TestCase :: Range ( Arc :: clone ( range) ) )
131133 }
132134 }
133135
134- PatKind :: Constant { value } => TestCase :: Constant { value } ,
136+ PatKind :: Constant { value } => Some ( TestCase :: Constant { value } ) ,
135137
136138 PatKind :: AscribeUserType {
137139 ascription : Ascription { ref annotation, variance } ,
138140 ref subpattern,
139141 ..
140142 } => {
143+ MatchPairTree :: for_pattern (
144+ place_builder,
145+ subpattern,
146+ cx,
147+ & mut subpairs,
148+ extra_data,
149+ ) ;
150+
141151 // 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
150158 }
151159
152160 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+ // ```
159179
180+ // First, recurse into the subpattern, if any.
160181 if let Some ( subpattern) = subpattern. as_ref ( ) {
161182 // 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+ ) ;
163190 }
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
165203 }
166204
167205 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
170208 }
171209 PatKind :: ExpandedConstant { subpattern : ref pattern, def_id, is_inline : true } => {
210+ MatchPairTree :: for_pattern ( place_builder, pattern, cx, & mut subpairs, extra_data) ;
211+
172212 // 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 {
174214 let span = pattern. span ;
175215 let parent_id = cx. tcx . typeck_root_def_id ( cx. def_id . to_def_id ( ) ) ;
176216 let args = ty:: InlineConstArgs :: new (
@@ -189,33 +229,47 @@ impl<'tcx> MatchPairTree<'tcx> {
189229 span,
190230 user_ty : Box :: new ( user_ty) ,
191231 } ;
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+ }
194235
195- subpairs. push ( MatchPairTree :: for_pattern ( place_builder, pattern, cx) ) ;
196- TestCase :: Irrefutable { ascription, binding : None }
236+ None
197237 }
198238
199239 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
202249 }
203250 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+ ) ;
205259
206260 if prefix. is_empty ( ) && slice. is_some ( ) && suffix. is_empty ( ) {
207- default_irrefutable ( )
261+ None
208262 } else {
209- TestCase :: Slice {
263+ Some ( TestCase :: Slice {
210264 len : prefix. len ( ) + suffix. len ( ) ,
211265 variable_length : slice. is_some ( ) ,
212- }
266+ } )
213267 }
214268 }
215269
216270 PatKind :: Variant { adt_def, variant_index, args, ref subpatterns } => {
217271 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) ;
219273
220274 let irrefutable = adt_def. variants ( ) . iter_enumerated ( ) . all ( |( i, v) | {
221275 i == variant_index
@@ -225,21 +279,23 @@ impl<'tcx> MatchPairTree<'tcx> {
225279 . apply_ignore_module ( cx. tcx , cx. infcx . typing_env ( cx. param_env ) )
226280 } ) && ( adt_def. did ( ) . is_local ( )
227281 || !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 } ) }
233283 }
234284
235285 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
238288 }
239289
240290 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
243299 }
244300
245301 PatKind :: DerefPattern { ref subpattern, mutability } => {
@@ -249,23 +305,32 @@ impl<'tcx> MatchPairTree<'tcx> {
249305 Ty :: new_ref ( cx. tcx , cx. tcx . lifetimes . re_erased , subpattern. ty , mutability) ,
250306 pattern. span ,
251307 ) ;
252- subpairs . push ( MatchPairTree :: for_pattern (
308+ MatchPairTree :: for_pattern (
253309 PlaceBuilder :: from ( temp) . deref ( ) ,
254310 subpattern,
255311 cx,
256- ) ) ;
257- TestCase :: Deref { temp, mutability }
312+ & mut subpairs,
313+ extra_data,
314+ ) ;
315+ Some ( TestCase :: Deref { temp, mutability } )
258316 }
259317
260- PatKind :: Never => TestCase :: Never ,
318+ PatKind :: Never => Some ( TestCase :: Never ) ,
261319 } ;
262320
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) ;
269334 }
270335 }
271336}
0 commit comments