@@ -65,7 +65,7 @@ pub(crate) enum PlaceBase {
65
65
66
66
/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
67
67
/// place by pushing more and more projections onto the end, and then convert the final set into a
68
- /// place using the `into_place ` method.
68
+ /// place using the `to_place ` method.
69
69
///
70
70
/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
71
71
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
@@ -167,59 +167,54 @@ fn find_capture_matching_projections<'a, 'tcx>(
167
167
} )
168
168
}
169
169
170
- /// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the
171
- /// `PlaceBuilder` now starts from `PlaceBase::Local`.
172
- ///
173
- /// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found.
170
+ /// Takes an upvar place and tries to resolve it into a `PlaceBuilder`
171
+ /// with `PlaceBase::Local`
174
172
#[ instrument( level = "trace" , skip( cx) , ret) ]
175
173
fn to_upvars_resolved_place_builder < ' tcx > (
176
- from_builder : PlaceBuilder < ' tcx > ,
177
174
cx : & Builder < ' _ , ' tcx > ,
178
- ) -> Result < PlaceBuilder < ' tcx > , PlaceBuilder < ' tcx > > {
179
- match from_builder . base {
180
- PlaceBase :: Local ( _ ) => Ok ( from_builder ) ,
181
- PlaceBase :: Upvar { var_hir_id , closure_def_id } = > {
182
- let Some ( ( capture_index, capture) ) =
183
- find_capture_matching_projections (
184
- & cx. upvars ,
185
- var_hir_id,
186
- & from_builder . projection ,
187
- ) else {
188
- let closure_span = cx. tcx . def_span ( closure_def_id) ;
189
- if !enable_precise_capture ( cx. tcx , closure_span) {
190
- bug ! (
191
- "No associated capture found for {:?}[{:#?}] even though \
192
- capture_disjoint_fields isn't enabled",
193
- var_hir_id,
194
- from_builder . projection
195
- )
196
- } else {
197
- debug ! (
198
- "No associated capture found for {:?}[{:#?}]" ,
199
- var_hir_id, from_builder . projection,
200
- ) ;
201
- }
202
- return Err ( from_builder ) ;
203
- } ;
175
+ var_hir_id : LocalVarId ,
176
+ closure_def_id : LocalDefId ,
177
+ projection : & [ PlaceElem < ' tcx > ] ,
178
+ ) -> Option < PlaceBuilder < ' tcx > > {
179
+ let Some ( ( capture_index, capture) ) =
180
+ find_capture_matching_projections (
181
+ & cx. upvars ,
182
+ var_hir_id,
183
+ & projection,
184
+ ) else {
185
+ let closure_span = cx. tcx . def_span ( closure_def_id) ;
186
+ if !enable_precise_capture ( cx. tcx , closure_span) {
187
+ bug ! (
188
+ "No associated capture found for {:?}[{:#?}] even though \
189
+ capture_disjoint_fields isn't enabled",
190
+ var_hir_id,
191
+ projection
192
+ )
193
+ } else {
194
+ debug ! (
195
+ "No associated capture found for {:?}[{:#?}]" ,
196
+ var_hir_id, projection,
197
+ ) ;
198
+ }
199
+ return None ;
200
+ } ;
204
201
205
- // Access the capture by accessing the field within the Closure struct.
206
- let capture_info = & cx. upvars [ capture_index] ;
202
+ // Access the capture by accessing the field within the Closure struct.
203
+ let capture_info = & cx. upvars [ capture_index] ;
207
204
208
- let mut upvar_resolved_place_builder = PlaceBuilder :: from ( capture_info. use_place ) ;
205
+ let mut upvar_resolved_place_builder = PlaceBuilder :: from ( capture_info. use_place ) ;
209
206
210
- // We used some of the projections to build the capture itself,
211
- // now we apply the remaining to the upvar resolved place.
212
- trace ! ( ?capture. captured_place, ?from_builder . projection) ;
213
- let remaining_projections = strip_prefix (
214
- capture. captured_place . place . base_ty ,
215
- from_builder . projection ,
216
- & capture. captured_place . place . projections ,
217
- ) ;
218
- upvar_resolved_place_builder. projection . extend ( remaining_projections) ;
207
+ // We used some of the projections to build the capture itself,
208
+ // now we apply the remaining to the upvar resolved place.
209
+ trace ! ( ?capture. captured_place, ?projection) ;
210
+ let remaining_projections = strip_prefix (
211
+ capture. captured_place . place . base_ty ,
212
+ projection,
213
+ & capture. captured_place . place . projections ,
214
+ ) ;
215
+ upvar_resolved_place_builder. projection . extend ( remaining_projections) ;
219
216
220
- Ok ( upvar_resolved_place_builder)
221
- }
222
- }
217
+ Some ( upvar_resolved_place_builder)
223
218
}
224
219
225
220
/// Returns projections remaining after stripping an initial prefix of HIR
@@ -228,13 +223,14 @@ fn to_upvars_resolved_place_builder<'tcx>(
228
223
/// Supports only HIR projection kinds that represent a path that might be
229
224
/// captured by a closure or a generator, i.e., an `Index` or a `Subslice`
230
225
/// projection kinds are unsupported.
231
- fn strip_prefix < ' tcx > (
226
+ fn strip_prefix < ' a , ' tcx > (
232
227
mut base_ty : Ty < ' tcx > ,
233
- projections : Vec < PlaceElem < ' tcx > > ,
228
+ projections : & ' a [ PlaceElem < ' tcx > ] ,
234
229
prefix_projections : & [ HirProjection < ' tcx > ] ,
235
- ) -> impl Iterator < Item = PlaceElem < ' tcx > > {
230
+ ) -> impl Iterator < Item = PlaceElem < ' tcx > > + ' a {
236
231
let mut iter = projections
237
- . into_iter ( )
232
+ . iter ( )
233
+ . copied ( )
238
234
// Filter out opaque casts, they are unnecessary in the prefix.
239
235
. filter ( |elem| !matches ! ( elem, ProjectionElem :: OpaqueCast ( ..) ) ) ;
240
236
for projection in prefix_projections {
@@ -258,21 +254,21 @@ fn strip_prefix<'tcx>(
258
254
}
259
255
260
256
impl < ' tcx > PlaceBuilder < ' tcx > {
261
- pub ( in crate :: build) fn into_place ( self , cx : & Builder < ' _ , ' tcx > ) -> Place < ' tcx > {
262
- if let PlaceBase :: Local ( local) = self . base {
263
- Place { local, projection : cx. tcx . intern_place_elems ( & self . projection ) }
264
- } else {
265
- self . expect_upvars_resolved ( cx) . into_place ( cx)
266
- }
257
+ pub ( in crate :: build) fn to_place ( & self , cx : & Builder < ' _ , ' tcx > ) -> Place < ' tcx > {
258
+ self . try_to_place ( cx) . unwrap ( )
267
259
}
268
260
269
- fn expect_upvars_resolved ( self , cx : & Builder < ' _ , ' tcx > ) -> PlaceBuilder < ' tcx > {
270
- to_upvars_resolved_place_builder ( self , cx) . unwrap ( )
261
+ /// Creates a `Place` or returns `None` if an upvar cannot be resolved
262
+ pub ( in crate :: build) fn try_to_place ( & self , cx : & Builder < ' _ , ' tcx > ) -> Option < Place < ' tcx > > {
263
+ let resolved = self . resolve_upvar ( cx) ;
264
+ let builder = resolved. as_ref ( ) . unwrap_or ( self ) ;
265
+ let PlaceBase :: Local ( local) = builder. base else { return None } ;
266
+ let projection = cx. tcx . intern_place_elems ( & builder. projection ) ;
267
+ Some ( Place { local, projection } )
271
268
}
272
269
273
270
/// Attempts to resolve the `PlaceBuilder`.
274
- /// On success, it will return the resolved `PlaceBuilder`.
275
- /// On failure, it will return itself.
271
+ /// Returns `None` if this is not an upvar.
276
272
///
277
273
/// Upvars resolve may fail for a `PlaceBuilder` when attempting to
278
274
/// resolve a disjoint field whose root variable is not captured
@@ -281,11 +277,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
281
277
/// not captured. This can happen because the final mir that will be
282
278
/// generated doesn't require a read for this place. Failures will only
283
279
/// happen inside closures.
284
- pub ( in crate :: build) fn try_upvars_resolved (
285
- self ,
280
+ pub ( in crate :: build) fn resolve_upvar (
281
+ & self ,
286
282
cx : & Builder < ' _ , ' tcx > ,
287
- ) -> Result < PlaceBuilder < ' tcx > , PlaceBuilder < ' tcx > > {
288
- to_upvars_resolved_place_builder ( self , cx)
283
+ ) -> Option < PlaceBuilder < ' tcx > > {
284
+ let PlaceBase :: Upvar { var_hir_id, closure_def_id } = self . base else {
285
+ return None ;
286
+ } ;
287
+ to_upvars_resolved_place_builder ( cx, var_hir_id, closure_def_id, & self . projection )
289
288
}
290
289
291
290
pub ( crate ) fn base ( & self ) -> PlaceBase {
@@ -316,6 +315,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
316
315
self . projection . push ( elem) ;
317
316
self
318
317
}
318
+
319
+ /// Same as `.clone().project(..)` but more efficient
320
+ pub ( crate ) fn clone_project ( & self , elem : PlaceElem < ' tcx > ) -> Self {
321
+ Self {
322
+ base : self . base ,
323
+ projection : Vec :: from_iter ( self . projection . iter ( ) . copied ( ) . chain ( [ elem] ) ) ,
324
+ }
325
+ }
319
326
}
320
327
321
328
impl < ' tcx > From < Local > for PlaceBuilder < ' tcx > {
@@ -355,7 +362,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
355
362
expr : & Expr < ' tcx > ,
356
363
) -> BlockAnd < Place < ' tcx > > {
357
364
let place_builder = unpack ! ( block = self . as_place_builder( block, expr) ) ;
358
- block. and ( place_builder. into_place ( self ) )
365
+ block. and ( place_builder. to_place ( self ) )
359
366
}
360
367
361
368
/// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -379,7 +386,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
379
386
expr : & Expr < ' tcx > ,
380
387
) -> BlockAnd < Place < ' tcx > > {
381
388
let place_builder = unpack ! ( block = self . as_read_only_place_builder( block, expr) ) ;
382
- block. and ( place_builder. into_place ( self ) )
389
+ block. and ( place_builder. to_place ( self ) )
383
390
}
384
391
385
392
/// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -474,7 +481,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
474
481
inferred_ty : expr. ty ,
475
482
} ) ;
476
483
477
- let place = place_builder. clone ( ) . into_place ( this) ;
484
+ let place = place_builder. to_place ( this) ;
478
485
this. cfg . push (
479
486
block,
480
487
Statement {
@@ -599,22 +606,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
599
606
let is_outermost_index = fake_borrow_temps. is_none ( ) ;
600
607
let fake_borrow_temps = fake_borrow_temps. unwrap_or ( base_fake_borrow_temps) ;
601
608
602
- let mut base_place =
609
+ let base_place =
603
610
unpack ! ( block = self . expr_as_place( block, base, mutability, Some ( fake_borrow_temps) , ) ) ;
604
611
605
612
// Making this a *fresh* temporary means we do not have to worry about
606
613
// the index changing later: Nothing will ever change this temporary.
607
614
// The "retagging" transformation (for Stacked Borrows) relies on this.
608
615
let idx = unpack ! ( block = self . as_temp( block, temp_lifetime, index, Mutability :: Not , ) ) ;
609
616
610
- block = self . bounds_check ( block, base_place. clone ( ) , idx, expr_span, source_info) ;
617
+ block = self . bounds_check ( block, & base_place, idx, expr_span, source_info) ;
611
618
612
619
if is_outermost_index {
613
620
self . read_fake_borrows ( block, fake_borrow_temps, source_info)
614
621
} else {
615
- base_place = base_place. expect_upvars_resolved ( self ) ;
616
622
self . add_fake_borrows_of_base (
617
- & base_place,
623
+ base_place. to_place ( self ) ,
618
624
block,
619
625
fake_borrow_temps,
620
626
expr_span,
@@ -628,7 +634,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
628
634
fn bounds_check (
629
635
& mut self ,
630
636
block : BasicBlock ,
631
- slice : PlaceBuilder < ' tcx > ,
637
+ slice : & PlaceBuilder < ' tcx > ,
632
638
index : Local ,
633
639
expr_span : Span ,
634
640
source_info : SourceInfo ,
@@ -640,7 +646,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
640
646
let lt = self . temp ( bool_ty, expr_span) ;
641
647
642
648
// len = len(slice)
643
- self . cfg . push_assign ( block, source_info, len, Rvalue :: Len ( slice. into_place ( self ) ) ) ;
649
+ self . cfg . push_assign ( block, source_info, len, Rvalue :: Len ( slice. to_place ( self ) ) ) ;
644
650
// lt = idx < len
645
651
self . cfg . push_assign (
646
652
block,
@@ -658,19 +664,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
658
664
659
665
fn add_fake_borrows_of_base (
660
666
& mut self ,
661
- base_place : & PlaceBuilder < ' tcx > ,
667
+ base_place : Place < ' tcx > ,
662
668
block : BasicBlock ,
663
669
fake_borrow_temps : & mut Vec < Local > ,
664
670
expr_span : Span ,
665
671
source_info : SourceInfo ,
666
672
) {
667
673
let tcx = self . tcx ;
668
- let local = match base_place. base {
669
- PlaceBase :: Local ( local) => local,
670
- PlaceBase :: Upvar { .. } => bug ! ( "Expected PlacseBase::Local found Upvar" ) ,
671
- } ;
672
674
673
- let place_ty = Place :: ty_from ( local , & base_place. projection , & self . local_decls , tcx) ;
675
+ let place_ty = base_place. ty ( & self . local_decls , tcx) ;
674
676
if let ty:: Slice ( _) = place_ty. ty . kind ( ) {
675
677
// We need to create fake borrows to ensure that the bounds
676
678
// check that we just did stays valid. Since we can't assign to
@@ -680,7 +682,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
680
682
match elem {
681
683
ProjectionElem :: Deref => {
682
684
let fake_borrow_deref_ty = Place :: ty_from (
683
- local,
685
+ base_place . local ,
684
686
& base_place. projection [ ..idx] ,
685
687
& self . local_decls ,
686
688
tcx,
@@ -698,14 +700,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
698
700
Rvalue :: Ref (
699
701
tcx. lifetimes . re_erased ,
700
702
BorrowKind :: Shallow ,
701
- Place { local, projection } ,
703
+ Place { local : base_place . local , projection } ,
702
704
) ,
703
705
) ;
704
706
fake_borrow_temps. push ( fake_borrow_temp) ;
705
707
}
706
708
ProjectionElem :: Index ( _) => {
707
709
let index_ty = Place :: ty_from (
708
- local,
710
+ base_place . local ,
709
711
& base_place. projection [ ..idx] ,
710
712
& self . local_decls ,
711
713
tcx,
0 commit comments