@@ -5,6 +5,7 @@ use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
5
5
use crate :: build:: { BlockAnd , BlockAndExtension , Builder } ;
6
6
use rustc_hir:: def_id:: DefId ;
7
7
use rustc_hir:: HirId ;
8
+ use rustc_middle:: hir:: place:: Projection as HirProjection ;
8
9
use rustc_middle:: hir:: place:: ProjectionKind as HirProjectionKind ;
9
10
use rustc_middle:: middle:: region;
10
11
use rustc_middle:: mir:: AssertKind :: BoundsCheck ;
@@ -268,20 +269,52 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
268
269
ty:: UpvarCapture :: ByValue => upvar_resolved_place_builder,
269
270
} ;
270
271
271
- let next_projection = capture. place . projections . len ( ) ;
272
- let mut curr_projections = from_builder. projection ;
273
-
274
272
// We used some of the projections to build the capture itself,
275
273
// now we apply the remaining to the upvar resolved place.
276
- upvar_resolved_place_builder
277
- . projection
278
- . extend ( curr_projections. drain ( next_projection..) ) ;
274
+ let remaining_projections = strip_prefix (
275
+ capture. place . base_ty ,
276
+ from_builder. projection ,
277
+ & capture. place . projections ,
278
+ ) ;
279
+ upvar_resolved_place_builder. projection . extend ( remaining_projections) ;
279
280
280
281
Ok ( upvar_resolved_place_builder)
281
282
}
282
283
}
283
284
}
284
285
286
+ /// Returns projections remaining after stripping an initial prefix of HIR
287
+ /// projections.
288
+ ///
289
+ /// Supports only HIR projection kinds that represent a path that might be
290
+ /// captured by a closure or a generator, i.e., an `Index` or a `Subslice`
291
+ /// projection kinds are unsupported.
292
+ fn strip_prefix < ' tcx > (
293
+ mut base_ty : Ty < ' tcx > ,
294
+ projections : Vec < PlaceElem < ' tcx > > ,
295
+ prefix_projections : & [ HirProjection < ' tcx > ] ,
296
+ ) -> impl Iterator < Item = PlaceElem < ' tcx > > {
297
+ let mut iter = projections. into_iter ( ) ;
298
+ for projection in prefix_projections {
299
+ match projection. kind {
300
+ HirProjectionKind :: Deref => {
301
+ assert ! ( matches!( iter. next( ) , Some ( ProjectionElem :: Deref ) ) ) ;
302
+ }
303
+ HirProjectionKind :: Field ( ..) => {
304
+ if base_ty. is_enum ( ) {
305
+ assert ! ( matches!( iter. next( ) , Some ( ProjectionElem :: Downcast ( ..) ) ) ) ;
306
+ }
307
+ assert ! ( matches!( iter. next( ) , Some ( ProjectionElem :: Field ( ..) ) ) ) ;
308
+ }
309
+ HirProjectionKind :: Index | HirProjectionKind :: Subslice => {
310
+ bug ! ( "unexpected projection kind: {:?}" , projection) ;
311
+ }
312
+ }
313
+ base_ty = projection. ty ;
314
+ }
315
+ iter
316
+ }
317
+
285
318
impl < ' tcx > PlaceBuilder < ' tcx > {
286
319
pub ( crate ) fn into_place < ' a > (
287
320
self ,
@@ -438,11 +471,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
438
471
this. expr_as_place ( block, & this. thir [ value] , mutability, fake_borrow_temps)
439
472
} )
440
473
}
441
- ExprKind :: Field { lhs, name } => {
442
- let place_builder = unpack ! (
443
- block =
444
- this. expr_as_place( block, & this. thir[ lhs] , mutability, fake_borrow_temps, )
445
- ) ;
474
+ ExprKind :: Field { lhs, variant_index, name } => {
475
+ let lhs = & this. thir [ lhs] ;
476
+ let mut place_builder =
477
+ unpack ! ( block = this. expr_as_place( block, lhs, mutability, fake_borrow_temps, ) ) ;
478
+ if let ty:: Adt ( adt_def, _) = lhs. ty . kind ( ) {
479
+ if adt_def. is_enum ( ) {
480
+ place_builder = place_builder. downcast ( * adt_def, variant_index) ;
481
+ }
482
+ }
446
483
block. and ( place_builder. field ( name, expr. ty ) )
447
484
}
448
485
ExprKind :: Deref { arg } => {
0 commit comments