@@ -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 = index_constraints ( & 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
@@ -108,7 +117,7 @@ pub(super) fn compute_loan_liveness<'tcx>(
108117 let is_loan_killed =
109118 kills. get ( & current_location) . is_some_and ( |kills| kills. contains ( & loan_idx) ) ;
110119
111- for succ in outgoing_edges ( & graph , node) {
120+ for succ in graph . outgoing_edges ( node) {
112121 // If the loan is killed at this point, it is killed _on exit_. But only during
113122 // forward traversal.
114123 if is_loan_killed {
@@ -125,9 +134,17 @@ pub(super) fn compute_loan_liveness<'tcx>(
125134 live_loans
126135}
127136
128- /// The localized constraint graph is currently the per-node map of its physical edges. In the
129- /// future, we'll add logical edges to model constraints that hold at all points in the CFG.
130- type LocalizedConstraintGraph = FxHashMap < LocalizedNode , FxIndexSet < LocalizedNode > > ;
137+ /// The localized constraint graph indexes the physical and logical edges to compute a given node's
138+ /// successors during traversal.
139+ struct LocalizedConstraintGraph {
140+ /// The actual, physical, edges we have recorded for a given node.
141+ 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 > > ,
147+ }
131148
132149/// A node in the graph to be traversed, one of the two vertices of a localized outlives constraint.
133150#[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug ) ]
@@ -136,24 +153,44 @@ struct LocalizedNode {
136153 point : PointIndex ,
137154}
138155
139- /// Traverses the constraints and returns the indexable graph of edges per node.
140- fn index_constraints ( constraints : & LocalizedOutlivesConstraintSet ) -> LocalizedConstraintGraph {
141- let mut edges = LocalizedConstraintGraph :: default ( ) ;
142- for constraint in & constraints. outlives {
143- let source = LocalizedNode { region : constraint. source , point : constraint. from } ;
144- let target = LocalizedNode { region : constraint. target , point : constraint. to } ;
145- edges. entry ( source) . or_default ( ) . insert ( target) ;
146- }
156+ impl LocalizedConstraintGraph {
157+ /// Traverses the constraints and returns the indexed graph of edges per node.
158+ fn new < ' tcx > (
159+ constraints : & LocalizedOutlivesConstraintSet ,
160+ logical_constraints : impl Iterator < Item = OutlivesConstraint < ' tcx > > ,
161+ ) -> Self {
162+ let mut edges: FxHashMap < _ , FxIndexSet < _ > > = FxHashMap :: default ( ) ;
163+ for constraint in & constraints. outlives {
164+ let source = LocalizedNode { region : constraint. source , point : constraint. from } ;
165+ let target = LocalizedNode { region : constraint. target , point : constraint. to } ;
166+ edges. entry ( source) . or_default ( ) . insert ( target) ;
167+ }
147168
148- edges
149- }
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 }
175+ }
150176
151- /// Returns the outgoing edges of a given node, not its transitive closure.
152- fn outgoing_edges (
153- graph : & LocalizedConstraintGraph ,
154- node : LocalizedNode ,
155- ) -> impl Iterator < Item = LocalizedNode > + use < ' _ > {
156- graph. get ( & node) . into_iter ( ) . flat_map ( |edges| edges. iter ( ) . copied ( ) )
177+ /// Returns the outgoing edges of a given node, not its transitive closure.
178+ fn outgoing_edges ( & self , node : LocalizedNode ) -> impl Iterator < Item = LocalizedNode > + use < ' _ > {
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)
193+ }
157194}
158195
159196/// Traverses the MIR and collects kills.
0 commit comments