@@ -10,14 +10,15 @@ use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
1010use rustc_middle:: middle:: region;
1111use rustc_middle:: mir:: AssertKind :: BoundsCheck ;
1212use rustc_middle:: mir:: * ;
13+ use rustc_middle:: ty:: AdtDef ;
1314use rustc_middle:: ty:: { self , CanonicalUserTypeAnnotation , Ty , TyCtxt , Variance } ;
1415use rustc_span:: Span ;
1516use rustc_target:: abi:: VariantIdx ;
1617
1718use rustc_index:: vec:: Idx ;
1819
1920/// The "outermost" place that holds this value.
20- #[ derive( Copy , Clone ) ]
21+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
2122crate enum PlaceBase {
2223 /// Denotes the start of a `Place`.
2324 Local ( Local ) ,
@@ -67,7 +68,7 @@ crate enum PlaceBase {
6768///
6869/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
6970/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
70- #[ derive( Clone ) ]
71+ #[ derive( Clone , Debug , PartialEq ) ]
7172crate struct PlaceBuilder < ' tcx > {
7273 base : PlaceBase ,
7374 projection : Vec < PlaceElem < ' tcx > > ,
@@ -83,20 +84,23 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
8384 mir_projections : & [ PlaceElem < ' tcx > ] ,
8485) -> Vec < HirProjectionKind > {
8586 let mut hir_projections = Vec :: new ( ) ;
87+ let mut variant = None ;
8688
8789 for mir_projection in mir_projections {
8890 let hir_projection = match mir_projection {
8991 ProjectionElem :: Deref => HirProjectionKind :: Deref ,
9092 ProjectionElem :: Field ( field, _) => {
91- // We will never encouter this for multivariant enums,
92- // read the comment for `Downcast`.
93- HirProjectionKind :: Field ( field. index ( ) as u32 , VariantIdx :: new ( 0 ) )
93+ let variant = variant. unwrap_or ( VariantIdx :: new ( 0 ) ) ;
94+ HirProjectionKind :: Field ( field. index ( ) as u32 , variant)
9495 }
95- ProjectionElem :: Downcast ( ..) => {
96- // This projections exist only for enums that have
97- // multiple variants. Since such enums that are captured
98- // completely, we can stop here.
99- break ;
96+ ProjectionElem :: Downcast ( .., idx) => {
97+ // We don't expect to see multi-variant enums here, as earlier
98+ // phases will have truncated them already. However, there can
99+ // still be downcasts, thanks to single-variant enums.
100+ // We keep track of VariantIdx so we can use this information
101+ // if the next ProjectionElem is a Field.
102+ variant = Some ( * idx) ;
103+ continue ;
100104 }
101105 ProjectionElem :: Index ( ..)
102106 | ProjectionElem :: ConstantIndex { .. }
@@ -106,7 +110,7 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
106110 break ;
107111 }
108112 } ;
109-
113+ variant = None ;
110114 hir_projections. push ( hir_projection) ;
111115 }
112116
@@ -194,12 +198,12 @@ fn find_capture_matching_projections<'a, 'tcx>(
194198/// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the
195199/// `PlaceBuilder` now starts from `PlaceBase::Local`.
196200///
197- /// Returns a Result with the error being the HirId of the Upvar that was not found.
201+ /// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found.
198202fn to_upvars_resolved_place_builder < ' a , ' tcx > (
199203 from_builder : PlaceBuilder < ' tcx > ,
200204 tcx : TyCtxt < ' tcx > ,
201205 typeck_results : & ' a ty:: TypeckResults < ' tcx > ,
202- ) -> Result < PlaceBuilder < ' tcx > , HirId > {
206+ ) -> Result < PlaceBuilder < ' tcx > , PlaceBuilder < ' tcx > > {
203207 match from_builder. base {
204208 PlaceBase :: Local ( _) => Ok ( from_builder) ,
205209 PlaceBase :: Upvar { var_hir_id, closure_def_id, closure_kind } => {
@@ -230,13 +234,12 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
230234 from_builder. projection
231235 )
232236 } else {
233- // FIXME(project-rfc-2229#24): Handle this case properly
234237 debug ! (
235238 "No associated capture found for {:?}[{:#?}]" ,
236239 var_hir_id, from_builder. projection,
237240 ) ;
238241 }
239- return Err ( var_hir_id ) ;
242+ return Err ( from_builder ) ;
240243 } ;
241244
242245 let closure_ty = typeck_results
@@ -300,6 +303,25 @@ impl<'tcx> PlaceBuilder<'tcx> {
300303 to_upvars_resolved_place_builder ( self , tcx, typeck_results) . unwrap ( )
301304 }
302305
306+ /// Attempts to resolve the `PlaceBuilder`.
307+ /// On success, it will return the resolved `PlaceBuilder`.
308+ /// On failure, it will return itself.
309+ ///
310+ /// Upvars resolve may fail for a `PlaceBuilder` when attempting to
311+ /// resolve a disjoint field whose root variable is not captured
312+ /// (destructured assignments) or when attempting to resolve a root
313+ /// variable (discriminant matching with only wildcard arm) that is
314+ /// not captured. This can happen because the final mir that will be
315+ /// generated doesn't require a read for this place. Failures will only
316+ /// happen inside closures.
317+ crate fn try_upvars_resolved < ' a > (
318+ self ,
319+ tcx : TyCtxt < ' tcx > ,
320+ typeck_results : & ' a ty:: TypeckResults < ' tcx > ,
321+ ) -> Result < PlaceBuilder < ' tcx > , PlaceBuilder < ' tcx > > {
322+ to_upvars_resolved_place_builder ( self , tcx, typeck_results)
323+ }
324+
303325 crate fn base ( & self ) -> PlaceBase {
304326 self . base
305327 }
@@ -308,15 +330,22 @@ impl<'tcx> PlaceBuilder<'tcx> {
308330 self . project ( PlaceElem :: Field ( f, ty) )
309331 }
310332
311- fn deref ( self ) -> Self {
333+ crate fn deref ( self ) -> Self {
312334 self . project ( PlaceElem :: Deref )
313335 }
314336
337+ crate fn downcast ( self , adt_def : & ' tcx AdtDef , variant_index : VariantIdx ) -> Self {
338+ self . project ( PlaceElem :: Downcast (
339+ Some ( adt_def. variants [ variant_index] . ident . name ) ,
340+ variant_index,
341+ ) )
342+ }
343+
315344 fn index ( self , index : Local ) -> Self {
316345 self . project ( PlaceElem :: Index ( index) )
317346 }
318347
319- fn project ( mut self , elem : PlaceElem < ' tcx > ) -> Self {
348+ crate fn project ( mut self , elem : PlaceElem < ' tcx > ) -> Self {
320349 self . projection . push ( elem) ;
321350 self
322351 }
@@ -602,13 +631,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
602631 // The "retagging" transformation (for Stacked Borrows) relies on this.
603632 let idx = unpack ! ( block = self . as_temp( block, temp_lifetime, index, Mutability :: Not , ) ) ;
604633
605- block = self . bounds_check (
606- block,
607- base_place. clone ( ) . into_place ( self . tcx , self . typeck_results ) ,
608- idx,
609- expr_span,
610- source_info,
611- ) ;
634+ block = self . bounds_check ( block, base_place. clone ( ) , idx, expr_span, source_info) ;
612635
613636 if is_outermost_index {
614637 self . read_fake_borrows ( block, fake_borrow_temps, source_info)
@@ -629,7 +652,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
629652 fn bounds_check (
630653 & mut self ,
631654 block : BasicBlock ,
632- slice : Place < ' tcx > ,
655+ slice : PlaceBuilder < ' tcx > ,
633656 index : Local ,
634657 expr_span : Span ,
635658 source_info : SourceInfo ,
@@ -641,7 +664,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
641664 let lt = self . temp ( bool_ty, expr_span) ;
642665
643666 // len = len(slice)
644- self . cfg . push_assign ( block, source_info, len, Rvalue :: Len ( slice) ) ;
667+ self . cfg . push_assign (
668+ block,
669+ source_info,
670+ len,
671+ Rvalue :: Len ( slice. into_place ( self . tcx , self . typeck_results ) ) ,
672+ ) ;
645673 // lt = idx < len
646674 self . cfg . push_assign (
647675 block,
0 commit comments