@@ -65,7 +65,7 @@ pub(crate) enum PlaceBase {
6565
6666/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
6767/// 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.
6969///
7070/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
7171/// 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>(
167167 } )
168168}
169169
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`
174172#[ instrument( level = "trace" , skip( cx) , ret) ]
175173fn to_upvars_resolved_place_builder < ' tcx > (
176- from_builder : PlaceBuilder < ' tcx > ,
177174 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+ } ;
204201
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] ;
207204
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 ) ;
209206
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) ;
219216
220- Ok ( upvar_resolved_place_builder)
221- }
222- }
217+ Some ( upvar_resolved_place_builder)
223218}
224219
225220/// Returns projections remaining after stripping an initial prefix of HIR
@@ -228,13 +223,14 @@ fn to_upvars_resolved_place_builder<'tcx>(
228223/// Supports only HIR projection kinds that represent a path that might be
229224/// captured by a closure or a generator, i.e., an `Index` or a `Subslice`
230225/// projection kinds are unsupported.
231- fn strip_prefix < ' tcx > (
226+ fn strip_prefix < ' a , ' tcx > (
232227 mut base_ty : Ty < ' tcx > ,
233- projections : Vec < PlaceElem < ' tcx > > ,
228+ projections : & ' a [ PlaceElem < ' tcx > ] ,
234229 prefix_projections : & [ HirProjection < ' tcx > ] ,
235- ) -> impl Iterator < Item = PlaceElem < ' tcx > > {
230+ ) -> impl Iterator < Item = PlaceElem < ' tcx > > + ' a {
236231 let mut iter = projections
237- . into_iter ( )
232+ . iter ( )
233+ . copied ( )
238234 // Filter out opaque casts, they are unnecessary in the prefix.
239235 . filter ( |elem| !matches ! ( elem, ProjectionElem :: OpaqueCast ( ..) ) ) ;
240236 for projection in prefix_projections {
@@ -258,21 +254,21 @@ fn strip_prefix<'tcx>(
258254}
259255
260256impl < ' 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 ( )
267259 }
268260
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 } )
271268 }
272269
273270 /// 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.
276272 ///
277273 /// Upvars resolve may fail for a `PlaceBuilder` when attempting to
278274 /// resolve a disjoint field whose root variable is not captured
@@ -281,11 +277,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
281277 /// not captured. This can happen because the final mir that will be
282278 /// generated doesn't require a read for this place. Failures will only
283279 /// happen inside closures.
284- pub ( in crate :: build) fn try_upvars_resolved (
285- self ,
280+ pub ( in crate :: build) fn resolve_upvar (
281+ & self ,
286282 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 )
289288 }
290289
291290 pub ( crate ) fn base ( & self ) -> PlaceBase {
@@ -316,6 +315,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
316315 self . projection . push ( elem) ;
317316 self
318317 }
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+ }
319326}
320327
321328impl < ' tcx > From < Local > for PlaceBuilder < ' tcx > {
@@ -355,7 +362,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
355362 expr : & Expr < ' tcx > ,
356363 ) -> BlockAnd < Place < ' tcx > > {
357364 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 ) )
359366 }
360367
361368 /// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -379,7 +386,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
379386 expr : & Expr < ' tcx > ,
380387 ) -> BlockAnd < Place < ' tcx > > {
381388 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 ) )
383390 }
384391
385392 /// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -474,7 +481,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
474481 inferred_ty : expr. ty ,
475482 } ) ;
476483
477- let place = place_builder. clone ( ) . into_place ( this) ;
484+ let place = place_builder. to_place ( this) ;
478485 this. cfg . push (
479486 block,
480487 Statement {
@@ -599,22 +606,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
599606 let is_outermost_index = fake_borrow_temps. is_none ( ) ;
600607 let fake_borrow_temps = fake_borrow_temps. unwrap_or ( base_fake_borrow_temps) ;
601608
602- let mut base_place =
609+ let base_place =
603610 unpack ! ( block = self . expr_as_place( block, base, mutability, Some ( fake_borrow_temps) , ) ) ;
604611
605612 // Making this a *fresh* temporary means we do not have to worry about
606613 // the index changing later: Nothing will ever change this temporary.
607614 // The "retagging" transformation (for Stacked Borrows) relies on this.
608615 let idx = unpack ! ( block = self . as_temp( block, temp_lifetime, index, Mutability :: Not , ) ) ;
609616
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) ;
611618
612619 if is_outermost_index {
613620 self . read_fake_borrows ( block, fake_borrow_temps, source_info)
614621 } else {
615- base_place = base_place. expect_upvars_resolved ( self ) ;
616622 self . add_fake_borrows_of_base (
617- & base_place,
623+ base_place. to_place ( self ) ,
618624 block,
619625 fake_borrow_temps,
620626 expr_span,
@@ -628,7 +634,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
628634 fn bounds_check (
629635 & mut self ,
630636 block : BasicBlock ,
631- slice : PlaceBuilder < ' tcx > ,
637+ slice : & PlaceBuilder < ' tcx > ,
632638 index : Local ,
633639 expr_span : Span ,
634640 source_info : SourceInfo ,
@@ -640,7 +646,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
640646 let lt = self . temp ( bool_ty, expr_span) ;
641647
642648 // 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 ) ) ) ;
644650 // lt = idx < len
645651 self . cfg . push_assign (
646652 block,
@@ -658,19 +664,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
658664
659665 fn add_fake_borrows_of_base (
660666 & mut self ,
661- base_place : & PlaceBuilder < ' tcx > ,
667+ base_place : Place < ' tcx > ,
662668 block : BasicBlock ,
663669 fake_borrow_temps : & mut Vec < Local > ,
664670 expr_span : Span ,
665671 source_info : SourceInfo ,
666672 ) {
667673 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- } ;
672674
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) ;
674676 if let ty:: Slice ( _) = place_ty. ty . kind ( ) {
675677 // We need to create fake borrows to ensure that the bounds
676678 // check that we just did stays valid. Since we can't assign to
@@ -680,7 +682,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
680682 match elem {
681683 ProjectionElem :: Deref => {
682684 let fake_borrow_deref_ty = Place :: ty_from (
683- local,
685+ base_place . local ,
684686 & base_place. projection [ ..idx] ,
685687 & self . local_decls ,
686688 tcx,
@@ -698,14 +700,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
698700 Rvalue :: Ref (
699701 tcx. lifetimes . re_erased ,
700702 BorrowKind :: Shallow ,
701- Place { local, projection } ,
703+ Place { local : base_place . local , projection } ,
702704 ) ,
703705 ) ;
704706 fake_borrow_temps. push ( fake_borrow_temp) ;
705707 }
706708 ProjectionElem :: Index ( _) => {
707709 let index_ty = Place :: ty_from (
708- local,
710+ base_place . local ,
709711 & base_place. projection [ ..idx] ,
710712 & self . local_decls ,
711713 tcx,
0 commit comments