@@ -10,14 +10,15 @@ use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
10
10
use rustc_middle:: middle:: region;
11
11
use rustc_middle:: mir:: AssertKind :: BoundsCheck ;
12
12
use rustc_middle:: mir:: * ;
13
+ use rustc_middle:: ty:: AdtDef ;
13
14
use rustc_middle:: ty:: { self , CanonicalUserTypeAnnotation , Ty , TyCtxt , Variance } ;
14
15
use rustc_span:: Span ;
15
16
use rustc_target:: abi:: VariantIdx ;
16
17
17
18
use rustc_index:: vec:: Idx ;
18
19
19
20
/// The "outermost" place that holds this value.
20
- #[ derive( Copy , Clone ) ]
21
+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
21
22
crate enum PlaceBase {
22
23
/// Denotes the start of a `Place`.
23
24
Local ( Local ) ,
@@ -67,7 +68,7 @@ crate enum PlaceBase {
67
68
///
68
69
/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
69
70
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
70
- #[ derive( Clone ) ]
71
+ #[ derive( Clone , Debug , PartialEq ) ]
71
72
crate struct PlaceBuilder < ' tcx > {
72
73
base : PlaceBase ,
73
74
projection : Vec < PlaceElem < ' tcx > > ,
@@ -83,20 +84,23 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
83
84
mir_projections : & [ PlaceElem < ' tcx > ] ,
84
85
) -> Vec < HirProjectionKind > {
85
86
let mut hir_projections = Vec :: new ( ) ;
87
+ let mut variant = None ;
86
88
87
89
for mir_projection in mir_projections {
88
90
let hir_projection = match mir_projection {
89
91
ProjectionElem :: Deref => HirProjectionKind :: Deref ,
90
92
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)
94
95
}
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 ;
100
104
}
101
105
ProjectionElem :: Index ( ..)
102
106
| ProjectionElem :: ConstantIndex { .. }
@@ -106,7 +110,7 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
106
110
break ;
107
111
}
108
112
} ;
109
-
113
+ variant = None ;
110
114
hir_projections. push ( hir_projection) ;
111
115
}
112
116
@@ -194,12 +198,12 @@ fn find_capture_matching_projections<'a, 'tcx>(
194
198
/// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the
195
199
/// `PlaceBuilder` now starts from `PlaceBase::Local`.
196
200
///
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.
198
202
fn to_upvars_resolved_place_builder < ' a , ' tcx > (
199
203
from_builder : PlaceBuilder < ' tcx > ,
200
204
tcx : TyCtxt < ' tcx > ,
201
205
typeck_results : & ' a ty:: TypeckResults < ' tcx > ,
202
- ) -> Result < PlaceBuilder < ' tcx > , HirId > {
206
+ ) -> Result < PlaceBuilder < ' tcx > , PlaceBuilder < ' tcx > > {
203
207
match from_builder. base {
204
208
PlaceBase :: Local ( _) => Ok ( from_builder) ,
205
209
PlaceBase :: Upvar { var_hir_id, closure_def_id, closure_kind } => {
@@ -230,13 +234,12 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
230
234
from_builder. projection
231
235
)
232
236
} else {
233
- // FIXME(project-rfc-2229#24): Handle this case properly
234
237
debug ! (
235
238
"No associated capture found for {:?}[{:#?}]" ,
236
239
var_hir_id, from_builder. projection,
237
240
) ;
238
241
}
239
- return Err ( var_hir_id ) ;
242
+ return Err ( from_builder ) ;
240
243
} ;
241
244
242
245
let closure_ty = typeck_results
@@ -300,6 +303,25 @@ impl<'tcx> PlaceBuilder<'tcx> {
300
303
to_upvars_resolved_place_builder ( self , tcx, typeck_results) . unwrap ( )
301
304
}
302
305
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
+
303
325
crate fn base ( & self ) -> PlaceBase {
304
326
self . base
305
327
}
@@ -308,15 +330,22 @@ impl<'tcx> PlaceBuilder<'tcx> {
308
330
self . project ( PlaceElem :: Field ( f, ty) )
309
331
}
310
332
311
- fn deref ( self ) -> Self {
333
+ crate fn deref ( self ) -> Self {
312
334
self . project ( PlaceElem :: Deref )
313
335
}
314
336
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
+
315
344
fn index ( self , index : Local ) -> Self {
316
345
self . project ( PlaceElem :: Index ( index) )
317
346
}
318
347
319
- fn project ( mut self , elem : PlaceElem < ' tcx > ) -> Self {
348
+ crate fn project ( mut self , elem : PlaceElem < ' tcx > ) -> Self {
320
349
self . projection . push ( elem) ;
321
350
self
322
351
}
@@ -602,13 +631,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
602
631
// The "retagging" transformation (for Stacked Borrows) relies on this.
603
632
let idx = unpack ! ( block = self . as_temp( block, temp_lifetime, index, Mutability :: Not , ) ) ;
604
633
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) ;
612
635
613
636
if is_outermost_index {
614
637
self . read_fake_borrows ( block, fake_borrow_temps, source_info)
@@ -629,7 +652,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
629
652
fn bounds_check (
630
653
& mut self ,
631
654
block : BasicBlock ,
632
- slice : Place < ' tcx > ,
655
+ slice : PlaceBuilder < ' tcx > ,
633
656
index : Local ,
634
657
expr_span : Span ,
635
658
source_info : SourceInfo ,
@@ -641,7 +664,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
641
664
let lt = self . temp ( bool_ty, expr_span) ;
642
665
643
666
// 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
+ ) ;
645
673
// lt = idx < len
646
674
self . cfg . push_assign (
647
675
block,
0 commit comments