@@ -9,16 +9,21 @@ use rustc_middle::ty::{RegionVid, TyCtxt};
99use rustc_mir_dataflow:: points:: PointIndex ;
1010
1111use super :: { LiveLoans , LocalizedOutlivesConstraintSet } ;
12+ use crate :: constraints:: OutlivesConstraint ;
1213use crate :: dataflow:: BorrowIndex ;
1314use crate :: region_infer:: values:: LivenessValues ;
15+ use crate :: type_check:: Locations ;
1416use crate :: { BorrowSet , PlaceConflictBias , places_conflict} ;
1517
16- /// With the full graph of constraints, we can compute loan reachability, stop at kills, and trace
17- /// loan liveness throughout the CFG.
18+ /// Compute loan reachability, stop at kills, and trace loan liveness throughout the CFG, by
19+ /// traversing the full graph of constraints that combines:
20+ /// - the localized constraints (the physical edges),
21+ /// - with the constraints that hold at all points (the logical edges).
1822pub ( super ) fn compute_loan_liveness < ' tcx > (
1923 tcx : TyCtxt < ' tcx > ,
2024 body : & Body < ' tcx > ,
2125 liveness : & LivenessValues ,
26+ outlives_constraints : impl Iterator < Item = OutlivesConstraint < ' tcx > > ,
2227 borrow_set : & BorrowSet < ' tcx > ,
2328 localized_outlives_constraints : & LocalizedOutlivesConstraintSet ,
2429) -> LiveLoans {
@@ -29,7 +34,11 @@ pub(super) fn compute_loan_liveness<'tcx>(
2934 // edges when visualizing the constraint graph anyways.
3035 let kills = collect_kills ( body, tcx, borrow_set) ;
3136
32- let graph = LocalizedConstraintGraph :: new ( & localized_outlives_constraints) ;
37+ // Create the full graph with the physical edges we've localized earlier, and the logical edges
38+ // of constraints that hold at all points.
39+ let logical_constraints =
40+ outlives_constraints. filter ( |c| matches ! ( c. locations, Locations :: All ( _) ) ) ;
41+ let graph = LocalizedConstraintGraph :: new ( & localized_outlives_constraints, logical_constraints) ;
3342 let mut visited = FxHashSet :: default ( ) ;
3443 let mut stack = Vec :: new ( ) ;
3544
@@ -125,11 +134,16 @@ pub(super) fn compute_loan_liveness<'tcx>(
125134 live_loans
126135}
127136
128- /// The localized constraint graph indexes the physical edges to compute a given node's successors
129- /// during traversal.
137+ /// The localized constraint graph indexes the physical and logical edges to compute a given node's
138+ /// successors during traversal.
130139struct LocalizedConstraintGraph {
131140 /// The actual, physical, edges we have recorded for a given node.
132141 edges : FxHashMap < LocalizedNode , FxIndexSet < LocalizedNode > > ,
142+
143+ /// The logical edges representing the outlives constraints that hold at all points in the CFG,
144+ /// which we don't localize to avoid creating a lot of unnecessary edges in the graph. Some CFGs
145+ /// can be big, and we don't need to create such a physical edge for every point in the CFG.
146+ logical_edges : FxHashMap < RegionVid , FxIndexSet < RegionVid > > ,
133147}
134148
135149/// A node in the graph to be traversed, one of the two vertices of a localized outlives constraint.
@@ -141,20 +155,41 @@ struct LocalizedNode {
141155
142156impl LocalizedConstraintGraph {
143157 /// Traverses the constraints and returns the indexed graph of edges per node.
144- fn new ( constraints : & LocalizedOutlivesConstraintSet ) -> Self {
158+ fn new < ' tcx > (
159+ constraints : & LocalizedOutlivesConstraintSet ,
160+ logical_constraints : impl Iterator < Item = OutlivesConstraint < ' tcx > > ,
161+ ) -> Self {
145162 let mut edges: FxHashMap < _ , FxIndexSet < _ > > = FxHashMap :: default ( ) ;
146163 for constraint in & constraints. outlives {
147164 let source = LocalizedNode { region : constraint. source , point : constraint. from } ;
148165 let target = LocalizedNode { region : constraint. target , point : constraint. to } ;
149166 edges. entry ( source) . or_default ( ) . insert ( target) ;
150167 }
151168
152- LocalizedConstraintGraph { edges }
169+ let mut logical_edges: FxHashMap < _ , FxIndexSet < _ > > = FxHashMap :: default ( ) ;
170+ for constraint in logical_constraints {
171+ logical_edges. entry ( constraint. sup ) . or_default ( ) . insert ( constraint. sub ) ;
172+ }
173+
174+ LocalizedConstraintGraph { edges, logical_edges }
153175 }
154176
155177 /// Returns the outgoing edges of a given node, not its transitive closure.
156178 fn outgoing_edges ( & self , node : LocalizedNode ) -> impl Iterator < Item = LocalizedNode > + use < ' _ > {
157- self . edges . get ( & node) . into_iter ( ) . flat_map ( |targets| targets. iter ( ) . copied ( ) )
179+ // The outgoing edges are:
180+ // - the physical edges present at this node,
181+ // - the materialized logical edges that exist virtually at all points for this node's
182+ // region, localized at this point.
183+ let physical_edges =
184+ self . edges . get ( & node) . into_iter ( ) . flat_map ( |targets| targets. iter ( ) . copied ( ) ) ;
185+ let materialized_edges =
186+ self . logical_edges . get ( & node. region ) . into_iter ( ) . flat_map ( move |targets| {
187+ targets
188+ . iter ( )
189+ . copied ( )
190+ . map ( move |target| LocalizedNode { point : node. point , region : target } )
191+ } ) ;
192+ physical_edges. chain ( materialized_edges)
158193 }
159194}
160195
0 commit comments