11#![ deny( rustc:: untranslatable_diagnostic) ]
22#![ deny( rustc:: diagnostic_outside_of_impl) ]
3- use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
4- use rustc_index:: bit_set:: { BitSet , SparseBitMatrix } ;
3+ use rustc_data_structures:: fx:: FxIndexMap ;
4+ use rustc_data_structures:: graph:: WithSuccessors ;
5+ use rustc_index:: bit_set:: BitSet ;
6+ use rustc_infer:: infer:: { NllRegionVariableOrigin , RegionVariableOrigin } ;
57use rustc_middle:: mir:: {
68 self , BasicBlock , Body , CallReturnPlaces , Location , Place , TerminatorEdges ,
79} ;
@@ -13,8 +15,6 @@ use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
1315use rustc_mir_dataflow:: { Analysis , Direction , Results } ;
1416use std:: fmt;
1517
16- use crate :: constraints:: ConstraintSccIndex ;
17- use crate :: region_infer:: values:: PointIndex ;
1818use crate :: { places_conflict, BorrowSet , PlaceConflictBias , PlaceExt , RegionInferenceContext } ;
1919
2020/// A tuple with named fields that can hold either the results or the transient state of the
@@ -255,66 +255,17 @@ struct PoloniusOutOfScopePrecomputer<'a, 'tcx> {
255255 visit_stack : Vec < StackEntry > ,
256256 body : & ' a Body < ' tcx > ,
257257 regioncx : & ' a RegionInferenceContext < ' tcx > ,
258-
259- sccs_live_at_all_points : FxHashSet < ConstraintSccIndex > ,
260- live_sccs_per_point : SparseBitMatrix < PointIndex , ConstraintSccIndex > ,
261-
262- reachability : BitSet < ConstraintSccIndex > ,
263- reachability_stack : Vec < ConstraintSccIndex > ,
264-
265258 loans_out_of_scope_at_location : FxIndexMap < Location , Vec < BorrowIndex > > ,
266259}
267260
268261impl < ' a , ' tcx > PoloniusOutOfScopePrecomputer < ' a , ' tcx > {
269262 fn new ( body : & ' a Body < ' tcx > , regioncx : & ' a RegionInferenceContext < ' tcx > ) -> Self {
270- let sccs = regioncx. constraint_sccs ( ) ;
271- let num_sccs = sccs. num_sccs ( ) ;
272-
273- // Compute the list of SCCs that are live at all points, as it will be used for all the
274- // loan scopes we'll compute.
275- // FIXME: they're surely already available somewhere.
276- let sccs_live_at_all_points: FxHashSet < _ > = regioncx
277- . regions ( )
278- . filter ( |& r| {
279- use rustc_infer:: infer:: { NllRegionVariableOrigin , RegionVariableOrigin } ;
280- let origin = regioncx. var_infos [ r] . origin ;
281- let live_at_all_points = matches ! (
282- origin,
283- RegionVariableOrigin :: Nll (
284- NllRegionVariableOrigin :: Placeholder ( _)
285- | NllRegionVariableOrigin :: FreeRegion
286- )
287- ) ;
288- live_at_all_points
289- } )
290- . map ( |r| sccs. scc ( r) )
291- . collect ( ) ;
292-
293- // Pre-compute the set of live SCCs per point
294- let liveness = regioncx. liveness_values ( ) ;
295- let mut live_sccs_per_point = SparseBitMatrix :: new ( num_sccs) ;
296-
297- for region in liveness. rows ( ) {
298- let scc = sccs. scc ( region) ;
299- if sccs_live_at_all_points. contains ( & scc) {
300- continue ;
301- }
302- for location in liveness. get_elements ( region) {
303- let point = liveness. point_from_location ( location) ;
304- live_sccs_per_point. insert ( point, scc) ;
305- }
306- }
307-
308263 Self {
309264 visited : BitSet :: new_empty ( body. basic_blocks . len ( ) ) ,
310265 visit_stack : vec ! [ ] ,
311266 body,
312267 regioncx,
313268 loans_out_of_scope_at_location : FxIndexMap :: default ( ) ,
314- sccs_live_at_all_points,
315- live_sccs_per_point,
316- reachability : BitSet :: new_empty ( num_sccs) ,
317- reachability_stack : vec ! [ ] ,
318269 }
319270 }
320271}
@@ -329,48 +280,44 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
329280 issuing_region : RegionVid ,
330281 issued_location : Location ,
331282 ) {
332- // Let's precompute the reachability set of the issuing region, via reachability on the
333- // condensation graph. We can also early return when reaching regions that outlive free
334- // regions via member constraints. (The `OutOfScopePrecomputer` wouldn't be called on a
335- // region that outlives free regions via outlives constraints.)
336-
337283 let sccs = self . regioncx . constraint_sccs ( ) ;
338-
339284 let issuing_region_scc = sccs. scc ( issuing_region) ;
340- self . reachability_stack . push ( issuing_region_scc) ;
341- self . reachability . insert ( issuing_region_scc) ;
342285
343- while let Some ( scc ) = self . reachability_stack . pop ( ) {
344- // Handle successors of this SCC:
345- //
286+ // We first handle the cases where the loan doesn't go out of scope, depending on the issuing
287+ // region's successors.
288+ for scc in sccs . depth_first_search ( issuing_region_scc ) {
346289 // 1. Via member constraints
347290 //
348- // The issuing region can flow into the choice regions here , and they are either:
291+ // The issuing region can flow into the choice regions, and they are either:
349292 // - placeholders or free regions themselves,
350293 // - or also transitively outlive a free region.
351294 //
352- // That is to say, if there are member constraints here, the loan escapes the
353- // function and cannot go out of scope. We can early return.
354- //
295+ // That is to say, if there are member constraints here, the loan escapes the function
296+ // and cannot go out of scope. We can early return.
297+ if self . regioncx . scc_has_member_constraints ( scc) {
298+ return ;
299+ }
300+
355301 // 2. Via regions that are live at all points: placeholders and free regions.
356302 //
357303 // If the issuing region outlives such a region, its loan escapes the function and
358304 // cannot go out of scope. We can early return.
359- if self . regioncx . scc_has_member_constraints ( scc)
360- || self . sccs_live_at_all_points . contains ( & scc)
361- {
362- self . reachability_stack . clear ( ) ;
363- self . reachability . clear ( ) ;
305+ //
306+ // FIXME: there must be a cleaner way to find this information. At least, when
307+ // higher-ranked subtyping is abstracted away from the borrowck main path, we'll only
308+ // need to check whether this is a universal region.
309+ //
310+ let representative = self . regioncx . scc_representatives [ scc] ;
311+ let origin = self . regioncx . var_infos [ representative] . origin ;
312+ let live_at_all_points = matches ! (
313+ origin,
314+ RegionVariableOrigin :: Nll (
315+ NllRegionVariableOrigin :: Placeholder ( _) | NllRegionVariableOrigin :: FreeRegion
316+ )
317+ ) ;
318+ if live_at_all_points {
364319 return ;
365320 }
366-
367- // 3. Via outlives successors, which we want to record and traverse: we add them
368- // to the worklist stack
369- for & succ_scc in sccs. successors ( scc) {
370- if self . reachability . insert ( succ_scc) {
371- self . reachability_stack . push ( succ_scc) ;
372- }
373- }
374321 }
375322
376323 // We visit one BB at a time. The complication is that we may start in the
@@ -397,26 +344,26 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
397344 for i in lo..=hi {
398345 let location = Location { block : bb, statement_index : i } ;
399346
400- // The loan is out of scope at point `location` if it's not contained within any
401- // live regions.
347+ // Check whether the issuing region can reach local regions that are live at this
348+ // point:
349+ // - a loan is always live at its issuing location because it can reach the issuing
350+ // region, which is always live at this location.
351+ if location == issued_location {
352+ continue ;
353+ }
354+
355+ // - the loan is out of scope at point `location` if it's not contained within any
356+ // regions live at this point.
402357 let mut issuing_region_can_reach_live_regions = false ;
403358
404- // Check whether the issuing region can reach local regions that are live at this
405- // point.
406- //
407359 // FIXME: if the issuing region `i` can reach a live region `r` at point `p`, and
408360 // `r` is live at point `q`, then it's guaranteed that `i` would reach `r` at point
409361 // `q`. The reachability is location-insensitive, and we could take advantage of
410362 // that, by jumping to a further point than the next statement. We can jump to the
411363 // furthest point within the block where `r` is live.
412364 let point = self . regioncx . liveness_values ( ) . point_from_location ( location) ;
413- if let Some ( live_sccs) = self . live_sccs_per_point . row ( point) {
414- for live_scc in live_sccs. iter ( ) {
415- if self . reachability . contains ( live_scc) {
416- issuing_region_can_reach_live_regions = true ;
417- break ;
418- }
419- }
365+ if self . regioncx . live_loans . contains ( point, loan_idx) {
366+ issuing_region_can_reach_live_regions = true ;
420367 }
421368
422369 // If no live region is reachable from the issuing region, then the loan is
@@ -462,9 +409,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
462409 }
463410
464411 self . visited . clear ( ) ;
465- self . reachability . clear ( ) ;
466412 assert ! ( self . visit_stack. is_empty( ) , "visit stack should be empty" ) ;
467- assert ! ( self . reachability_stack. is_empty( ) , "reachability stack should be empty" ) ;
468413 }
469414}
470415
@@ -495,8 +440,8 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
495440 }
496441
497442 assert_eq ! (
498- borrows_out_of_scope_at_location , polonius_prec. loans_out_of_scope_at_location,
499- "the loans out of scope must be the same as the borrows out of scope"
443+ polonius_prec. loans_out_of_scope_at_location, borrows_out_of_scope_at_location ,
444+ "the loans out of scope are different from the borrows out of scope"
500445 ) ;
501446
502447 borrows_out_of_scope_at_location = polonius_prec. loans_out_of_scope_at_location ;
0 commit comments