@@ -5,6 +5,7 @@ use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
55use crate :: build:: { BlockAnd , BlockAndExtension , Builder } ;
66use rustc_hir:: def_id:: DefId ;
77use rustc_hir:: HirId ;
8+ use rustc_middle:: hir:: place:: Projection as HirProjection ;
89use rustc_middle:: hir:: place:: ProjectionKind as HirProjectionKind ;
910use rustc_middle:: middle:: region;
1011use rustc_middle:: mir:: AssertKind :: BoundsCheck ;
@@ -268,20 +269,52 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
268269 ty:: UpvarCapture :: ByValue => upvar_resolved_place_builder,
269270 } ;
270271
271- let next_projection = capture. place . projections . len ( ) ;
272- let mut curr_projections = from_builder. projection ;
273-
274272 // We used some of the projections to build the capture itself,
275273 // 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) ;
279280
280281 Ok ( upvar_resolved_place_builder)
281282 }
282283 }
283284}
284285
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+
285318impl < ' tcx > PlaceBuilder < ' tcx > {
286319 pub ( crate ) fn into_place < ' a > (
287320 self ,
@@ -438,11 +471,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
438471 this. expr_as_place ( block, & this. thir [ value] , mutability, fake_borrow_temps)
439472 } )
440473 }
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+ }
446483 block. and ( place_builder. field ( name, expr. ty ) )
447484 }
448485 ExprKind :: Deref { arg } => {
0 commit comments