@@ -4,6 +4,8 @@ use crate::build::expr::category::Category;
4
4
use crate :: build:: ForGuard :: { OutsideGuard , RefWithinGuard } ;
5
5
use crate :: build:: { BlockAnd , BlockAndExtension , Builder } ;
6
6
use crate :: thir:: * ;
7
+ use rustc_hir:: def_id:: DefId ;
8
+ use rustc_hir:: HirId ;
7
9
use rustc_middle:: middle:: region;
8
10
use rustc_middle:: mir:: AssertKind :: BoundsCheck ;
9
11
use rustc_middle:: mir:: * ;
@@ -12,6 +14,12 @@ use rustc_span::Span;
12
14
13
15
use rustc_index:: vec:: Idx ;
14
16
17
+ #[ derive( Copy , Clone ) ]
18
+ pub enum PlaceBase {
19
+ Local ( Local ) ,
20
+ Upvar { var_hir_id : HirId , closure_def_id : DefId , closure_kind : ty:: ClosureKind } ,
21
+ }
22
+
15
23
/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
16
24
/// place by pushing more and more projections onto the end, and then convert the final set into a
17
25
/// place using the `into_place` method.
@@ -20,13 +28,132 @@ use rustc_index::vec::Idx;
20
28
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
21
29
#[ derive( Clone ) ]
22
30
struct PlaceBuilder < ' tcx > {
23
- local : Local ,
31
+ base : PlaceBase ,
24
32
projection : Vec < PlaceElem < ' tcx > > ,
25
33
}
26
34
35
+ fn capture_matching_projections < ' a , ' tcx > (
36
+ tcx : TyCtxt < ' tcx > ,
37
+ typeck_results : & ' a ty:: TypeckResults < ' tcx > ,
38
+ var_hir_id : HirId ,
39
+ closure_def_id : DefId ,
40
+ projections : & Vec < PlaceElem < ' tcx > > ,
41
+ ) -> Option < ( usize , Ty < ' tcx > , ty:: UpvarCapture < ' tcx > ) > {
42
+ let capture = typeck_results
43
+ . closure_captures
44
+ . get ( & closure_def_id)
45
+ . and_then ( |captures| captures. get_full ( & var_hir_id) ) ;
46
+
47
+ if capture. is_none ( ) {
48
+ if !tcx. features ( ) . capture_disjoint_fields {
49
+ bug ! (
50
+ "No associated capture found for {:?}[{:#?}] even though \
51
+ capture_disjoint_fields isn't enabled",
52
+ var_hir_id,
53
+ projections
54
+ )
55
+ }
56
+ }
57
+
58
+ // Unwrap until the FIXME has been resolved
59
+ let ( capture_index, _, _) = capture. unwrap ( ) ;
60
+
61
+ let closure_ty =
62
+ typeck_results. node_type ( tcx. hir ( ) . local_def_id_to_hir_id ( closure_def_id. expect_local ( ) ) ) ;
63
+
64
+ let substs = match closure_ty. kind ( ) {
65
+ ty:: Closure ( _, substs) => ty:: UpvarSubsts :: Closure ( substs) ,
66
+ ty:: Generator ( _, substs, _) => ty:: UpvarSubsts :: Generator ( substs) ,
67
+ _ => bug ! ( "Lowering capture for non-closure type {:?}" , closure_ty) ,
68
+ } ;
69
+
70
+ // Access the capture by accessing the field within the Closure struct.
71
+ //
72
+ // We must have inferred the capture types since we are building MIR, therefore
73
+ // it's safe to call `upvar_tys` and we can unwrap here because
74
+ // we know that the capture exists and is the `capture_index`-th capture.
75
+ let var_ty = substs. upvar_tys ( ) . nth ( capture_index) . unwrap ( ) ;
76
+
77
+ let upvar_id = ty:: UpvarId :: new ( var_hir_id, closure_def_id. expect_local ( ) ) ;
78
+ let capture_kind = typeck_results. upvar_capture ( upvar_id) ;
79
+
80
+ Some ( ( capture_index, var_ty, capture_kind) )
81
+ }
82
+
83
+ /// Takes a PlaceBuilder and resolves the upvar (if any) within it,
84
+ /// so that the PlaceBuilder now starts from PlaceBase::Local.
85
+ ///
86
+ /// Returns a Result with the error being the HirId of the
87
+ /// Upvar that was not found.
88
+ fn to_upvars_resolved_place_builder < ' a , ' tcx > (
89
+ from_builder : PlaceBuilder < ' tcx > ,
90
+ tcx : TyCtxt < ' tcx > ,
91
+ typeck_results : & ' a ty:: TypeckResults < ' tcx > ,
92
+ ) -> Result < PlaceBuilder < ' tcx > , HirId > {
93
+ match from_builder. base {
94
+ PlaceBase :: Local ( _) => Ok ( from_builder) ,
95
+ PlaceBase :: Upvar { var_hir_id, closure_def_id, closure_kind } => {
96
+ // Captures are represented using fields inside a structure.
97
+ // This represents accessing self in the closure structure
98
+ let local = PlaceBase :: Local ( Local :: new ( 1 ) ) ;
99
+ let mut place_builder = PlaceBuilder :: from ( local) ;
100
+ match closure_kind {
101
+ ty:: ClosureKind :: Fn | ty:: ClosureKind :: FnMut => {
102
+ place_builder = place_builder. deref ( ) ;
103
+ }
104
+ ty:: ClosureKind :: FnOnce => { }
105
+ }
106
+
107
+ let ( capture_index, var_ty, capture_kind) =
108
+ if let Some ( capture_details) = capture_matching_projections (
109
+ tcx,
110
+ typeck_results,
111
+ var_hir_id,
112
+ closure_def_id,
113
+ & from_builder. projection ,
114
+ ) {
115
+ capture_details
116
+ } else {
117
+ return Err ( var_hir_id) ;
118
+ } ;
119
+
120
+ place_builder = place_builder. field ( Field :: new ( capture_index) , var_ty) ;
121
+
122
+ // If the variable is captured via ByRef(Immutable/Mutable) Borrow,
123
+ // we need to deref it
124
+ place_builder = match capture_kind {
125
+ ty:: UpvarCapture :: ByRef ( _) => place_builder. deref ( ) ,
126
+ ty:: UpvarCapture :: ByValue ( _) => place_builder,
127
+ } ;
128
+
129
+ let next_projection = 0 ;
130
+ let mut curr_projections = from_builder. projection ;
131
+ place_builder. projection . extend ( curr_projections. drain ( next_projection..) ) ;
132
+
133
+ Ok ( place_builder)
134
+ }
135
+ }
136
+ }
137
+
27
138
impl < ' tcx > PlaceBuilder < ' tcx > {
28
- fn into_place ( self , tcx : TyCtxt < ' tcx > ) -> Place < ' tcx > {
29
- Place { local : self . local , projection : tcx. intern_place_elems ( & self . projection ) }
139
+ fn into_place < ' a > (
140
+ self ,
141
+ tcx : TyCtxt < ' tcx > ,
142
+ typeck_results : & ' a ty:: TypeckResults < ' tcx > ,
143
+ ) -> Place < ' tcx > {
144
+ if let PlaceBase :: Local ( local) = self . base {
145
+ Place { local, projection : tcx. intern_place_elems ( & self . projection ) }
146
+ } else {
147
+ self . expect_upvars_resolved ( tcx, typeck_results) . into_place ( tcx, typeck_results)
148
+ }
149
+ }
150
+
151
+ fn expect_upvars_resolved < ' a > (
152
+ self ,
153
+ tcx : TyCtxt < ' tcx > ,
154
+ typeck_results : & ' a ty:: TypeckResults < ' tcx > ,
155
+ ) -> PlaceBuilder < ' tcx > {
156
+ to_upvars_resolved_place_builder ( self , tcx, typeck_results) . unwrap ( )
30
157
}
31
158
32
159
fn field ( self , f : Field , ty : Ty < ' tcx > ) -> Self {
@@ -47,9 +174,9 @@ impl<'tcx> PlaceBuilder<'tcx> {
47
174
}
48
175
}
49
176
50
- impl < ' tcx > From < Local > for PlaceBuilder < ' tcx > {
51
- fn from ( local : Local ) -> Self {
52
- Self { local , projection : Vec :: new ( ) }
177
+ impl < ' tcx > From < PlaceBase > for PlaceBuilder < ' tcx > {
178
+ fn from ( base : PlaceBase ) -> Self {
179
+ Self { base , projection : Vec :: new ( ) }
53
180
}
54
181
}
55
182
@@ -71,7 +198,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
71
198
M : Mirror < ' tcx , Output = Expr < ' tcx > > ,
72
199
{
73
200
let place_builder = unpack ! ( block = self . as_place_builder( block, expr) ) ;
74
- block. and ( place_builder. into_place ( self . hir . tcx ( ) ) )
201
+ block. and ( place_builder. into_place ( self . hir . tcx ( ) , self . hir . typeck_results ( ) ) )
75
202
}
76
203
77
204
/// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -98,7 +225,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
98
225
M : Mirror < ' tcx , Output = Expr < ' tcx > > ,
99
226
{
100
227
let place_builder = unpack ! ( block = self . as_read_only_place_builder( block, expr) ) ;
101
- block. and ( place_builder. into_place ( self . hir . tcx ( ) ) )
228
+ block. and ( place_builder. into_place ( self . hir . tcx ( ) , self . hir . typeck_results ( ) ) )
102
229
}
103
230
104
231
/// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -161,36 +288,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
161
288
source_info,
162
289
) ,
163
290
ExprKind :: UpvarRef { closure_def_id, var_hir_id } => {
164
- let capture = this
165
- . hir
166
- . typeck_results
167
- . closure_captures
168
- . get ( & closure_def_id)
169
- . and_then ( |captures| captures. get_full ( & var_hir_id) ) ;
170
-
171
- if capture. is_none ( ) {
172
- if !this. hir . tcx ( ) . features ( ) . capture_disjoint_fields {
173
- bug ! (
174
- "No associated capture found for {:?} even though \
175
- capture_disjoint_fields isn't enabled",
176
- expr. kind
177
- )
178
- }
179
- // FIXME(project-rfc-2229#24): Handle this case properly
180
- }
181
-
182
- // Unwrap until the FIXME has been resolved
183
- let ( capture_index, _, upvar_id) = capture. unwrap ( ) ;
184
- this. lower_closure_capture ( block, capture_index, * upvar_id)
291
+ let upvar_id = ty:: UpvarId :: new ( var_hir_id, closure_def_id. expect_local ( ) ) ;
292
+ this. lower_closure_capture ( block, upvar_id)
185
293
}
186
294
187
295
ExprKind :: VarRef { id } => {
188
296
let place_builder = if this. is_bound_var_in_guard ( id) {
189
297
let index = this. var_local_id ( id, RefWithinGuard ) ;
190
- PlaceBuilder :: from ( index) . deref ( )
298
+ PlaceBuilder :: from ( PlaceBase :: Local ( index) ) . deref ( )
191
299
} else {
192
300
let index = this. var_local_id ( id, OutsideGuard ) ;
193
- PlaceBuilder :: from ( index)
301
+ PlaceBuilder :: from ( PlaceBase :: Local ( index) )
194
302
} ;
195
303
block. and ( place_builder)
196
304
}
@@ -208,7 +316,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
208
316
inferred_ty : expr. ty ,
209
317
} ) ;
210
318
211
- let place = place_builder. clone ( ) . into_place ( this. hir . tcx ( ) ) ;
319
+ let place =
320
+ place_builder. clone ( ) . into_place ( this. hir . tcx ( ) , this. hir . typeck_results ( ) ) ;
212
321
this. cfg . push (
213
322
block,
214
323
Statement {
@@ -250,7 +359,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
250
359
} ,
251
360
) ;
252
361
}
253
- block. and ( PlaceBuilder :: from ( temp) )
362
+ block. and ( PlaceBuilder :: from ( PlaceBase :: Local ( temp) ) )
254
363
}
255
364
256
365
ExprKind :: Array { .. }
@@ -288,64 +397,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
288
397
debug_assert ! ( !matches!( Category :: of( & expr. kind) , Some ( Category :: Place ) ) ) ;
289
398
let temp =
290
399
unpack ! ( block = this. as_temp( block, expr. temp_lifetime, expr, mutability) ) ;
291
- block. and ( PlaceBuilder :: from ( temp) )
400
+ block. and ( PlaceBuilder :: from ( PlaceBase :: Local ( temp) ) )
292
401
}
293
402
}
294
403
}
295
404
296
405
/// Lower a closure/generator capture by representing it as a field
297
406
/// access within the desugared closure/generator.
298
- ///
299
- /// `capture_index` is the index of the capture within the desugared
300
- /// closure/generator.
301
407
fn lower_closure_capture (
302
408
& mut self ,
303
409
block : BasicBlock ,
304
- capture_index : usize ,
305
410
upvar_id : ty:: UpvarId ,
306
- ) -> BlockAnd < PlaceBuilder < ' tcx > > {
411
+ ) -> BlockAnd < PlaceBuilder < ' tcx > > {
307
412
let closure_ty = self
308
413
. hir
309
414
. typeck_results ( )
310
415
. node_type ( self . hir . tcx ( ) . hir ( ) . local_def_id_to_hir_id ( upvar_id. closure_expr_id ) ) ;
311
416
312
- // Captures are represented using fields inside a structure.
313
- // This represents accessing self in the closure structure
314
- let mut place_builder = PlaceBuilder :: from ( Local :: new ( 1 ) ) ;
315
-
316
- // In case of Fn/FnMut closures we must deref to access the fields
317
- // Generators are considered FnOnce, so we ignore this step for them.
318
- if let ty:: Closure ( _, closure_substs) = closure_ty. kind ( ) {
319
- match self . hir . infcx ( ) . closure_kind ( closure_substs) . unwrap ( ) {
320
- ty:: ClosureKind :: Fn | ty:: ClosureKind :: FnMut => {
321
- place_builder = place_builder. deref ( ) ;
322
- }
323
- ty:: ClosureKind :: FnOnce => { }
324
- }
325
- }
326
-
327
- let substs = match closure_ty. kind ( ) {
328
- ty:: Closure ( _, substs) => ty:: UpvarSubsts :: Closure ( substs) ,
329
- ty:: Generator ( _, substs, _) => ty:: UpvarSubsts :: Generator ( substs) ,
330
- _ => bug ! ( "Lowering capture for non-closure type {:?}" , closure_ty)
417
+ let closure_kind = if let ty:: Closure ( _, closure_substs) = closure_ty. kind ( ) {
418
+ self . hir . infcx ( ) . closure_kind ( closure_substs) . unwrap ( )
419
+ } else {
420
+ // Generators are considered FnOnce.
421
+ ty:: ClosureKind :: FnOnce
331
422
} ;
332
423
333
- // Access the capture by accessing the field within the Closure struct.
334
- //
335
- // We must have inferred the capture types since we are building MIR, therefore
336
- // it's safe to call `upvar_tys` and we can unwrap here because
337
- // we know that the capture exists and is the `capture_index`-th capture.
338
- let var_ty = substs. upvar_tys ( ) . nth ( capture_index) . unwrap ( ) ;
339
- place_builder = place_builder. field ( Field :: new ( capture_index) , var_ty) ;
340
-
341
- // If the variable is captured via ByRef(Immutable/Mutable) Borrow,
342
- // we need to deref it
343
- match self . hir . typeck_results . upvar_capture ( upvar_id) {
344
- ty:: UpvarCapture :: ByRef ( _) => {
345
- block. and ( place_builder. deref ( ) )
346
- }
347
- ty:: UpvarCapture :: ByValue ( _) => block. and ( place_builder) ,
348
- }
424
+ block. and ( PlaceBuilder :: from ( PlaceBase :: Upvar {
425
+ var_hir_id : upvar_id. var_path . hir_id ,
426
+ closure_def_id : upvar_id. closure_expr_id . to_def_id ( ) ,
427
+ closure_kind,
428
+ } ) )
349
429
}
350
430
351
431
/// Lower an index expression
@@ -373,7 +453,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
373
453
let is_outermost_index = fake_borrow_temps. is_none ( ) ;
374
454
let fake_borrow_temps = fake_borrow_temps. unwrap_or ( base_fake_borrow_temps) ;
375
455
376
- let base_place =
456
+ let mut base_place =
377
457
unpack ! ( block = self . expr_as_place( block, lhs, mutability, Some ( fake_borrow_temps) , ) ) ;
378
458
379
459
// Making this a *fresh* temporary means we do not have to worry about
@@ -383,7 +463,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
383
463
384
464
block = self . bounds_check (
385
465
block,
386
- base_place. clone ( ) . into_place ( self . hir . tcx ( ) ) ,
466
+ base_place. clone ( ) . into_place ( self . hir . tcx ( ) , self . hir . typeck_results ( ) ) ,
387
467
idx,
388
468
expr_span,
389
469
source_info,
@@ -392,6 +472,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
392
472
if is_outermost_index {
393
473
self . read_fake_borrows ( block, fake_borrow_temps, source_info)
394
474
} else {
475
+ base_place = base_place. expect_upvars_resolved ( self . hir . tcx ( ) , self . hir . typeck_results ( ) ) ;
395
476
self . add_fake_borrows_of_base (
396
477
& base_place,
397
478
block,
@@ -441,8 +522,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
441
522
source_info : SourceInfo ,
442
523
) {
443
524
let tcx = self . hir . tcx ( ) ;
444
- let place_ty =
445
- Place :: ty_from ( base_place. local , & base_place. projection , & self . local_decls , tcx) ;
525
+ let local = match base_place. base {
526
+ PlaceBase :: Local ( local) => local,
527
+ PlaceBase :: Upvar { .. } => bug ! ( "Expected PlacseBase::Local found Upvar" )
528
+ } ;
529
+
530
+ let place_ty = Place :: ty_from ( local, & base_place. projection , & self . local_decls , tcx) ;
446
531
if let ty:: Slice ( _) = place_ty. ty . kind ( ) {
447
532
// We need to create fake borrows to ensure that the bounds
448
533
// check that we just did stays valid. Since we can't assign to
@@ -452,7 +537,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
452
537
match elem {
453
538
ProjectionElem :: Deref => {
454
539
let fake_borrow_deref_ty = Place :: ty_from (
455
- base_place . local ,
540
+ local,
456
541
& base_place. projection [ ..idx] ,
457
542
& self . local_decls ,
458
543
tcx,
@@ -470,14 +555,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
470
555
Rvalue :: Ref (
471
556
tcx. lifetimes . re_erased ,
472
557
BorrowKind :: Shallow ,
473
- Place { local : base_place . local , projection } ,
558
+ Place { local, projection } ,
474
559
) ,
475
560
) ;
476
561
fake_borrow_temps. push ( fake_borrow_temp) ;
477
562
}
478
563
ProjectionElem :: Index ( _) => {
479
564
let index_ty = Place :: ty_from (
480
- base_place . local ,
565
+ local,
481
566
& base_place. projection [ ..idx] ,
482
567
& self . local_decls ,
483
568
tcx,
0 commit comments