@@ -9,16 +9,21 @@ use rustc_middle::ty::{RegionVid, TyCtxt};
9
9
use rustc_mir_dataflow:: points:: PointIndex ;
10
10
11
11
use super :: { LiveLoans , LocalizedOutlivesConstraintSet } ;
12
+ use crate :: constraints:: OutlivesConstraint ;
12
13
use crate :: dataflow:: BorrowIndex ;
13
14
use crate :: region_infer:: values:: LivenessValues ;
15
+ use crate :: type_check:: Locations ;
14
16
use crate :: { BorrowSet , PlaceConflictBias , places_conflict} ;
15
17
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).
18
22
pub ( super ) fn compute_loan_liveness < ' tcx > (
19
23
tcx : TyCtxt < ' tcx > ,
20
24
body : & Body < ' tcx > ,
21
25
liveness : & LivenessValues ,
26
+ outlives_constraints : impl Iterator < Item = OutlivesConstraint < ' tcx > > ,
22
27
borrow_set : & BorrowSet < ' tcx > ,
23
28
localized_outlives_constraints : & LocalizedOutlivesConstraintSet ,
24
29
) -> LiveLoans {
@@ -29,7 +34,11 @@ pub(super) fn compute_loan_liveness<'tcx>(
29
34
// edges when visualizing the constraint graph anyways.
30
35
let kills = collect_kills ( body, tcx, borrow_set) ;
31
36
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) ;
33
42
let mut visited = FxHashSet :: default ( ) ;
34
43
let mut stack = Vec :: new ( ) ;
35
44
@@ -108,7 +117,7 @@ pub(super) fn compute_loan_liveness<'tcx>(
108
117
let is_loan_killed =
109
118
kills. get ( & current_location) . is_some_and ( |kills| kills. contains ( & loan_idx) ) ;
110
119
111
- for succ in outgoing_edges ( & graph , node) {
120
+ for succ in graph . outgoing_edges ( node) {
112
121
// If the loan is killed at this point, it is killed _on exit_. But only during
113
122
// forward traversal.
114
123
if is_loan_killed {
@@ -125,9 +134,17 @@ pub(super) fn compute_loan_liveness<'tcx>(
125
134
live_loans
126
135
}
127
136
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
+ }
131
148
132
149
/// A node in the graph to be traversed, one of the two vertices of a localized outlives constraint.
133
150
#[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug ) ]
@@ -136,24 +153,44 @@ struct LocalizedNode {
136
153
point : PointIndex ,
137
154
}
138
155
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
+ }
147
168
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
+ }
150
176
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
+ }
157
194
}
158
195
159
196
/// Traverses the MIR and collects kills.
0 commit comments