@@ -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 = 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) ;
33
42
let mut visited = FxHashSet :: default ( ) ;
34
43
let mut stack = Vec :: new ( ) ;
35
44
@@ -125,11 +134,16 @@ pub(super) fn compute_loan_liveness<'tcx>(
125
134
live_loans
126
135
}
127
136
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.
130
139
struct LocalizedConstraintGraph {
131
140
/// The actual, physical, edges we have recorded for a given node.
132
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 > > ,
133
147
}
134
148
135
149
/// A node in the graph to be traversed, one of the two vertices of a localized outlives constraint.
@@ -141,20 +155,41 @@ struct LocalizedNode {
141
155
142
156
impl LocalizedConstraintGraph {
143
157
/// 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 {
145
162
let mut edges: FxHashMap < _ , FxIndexSet < _ > > = FxHashMap :: default ( ) ;
146
163
for constraint in & constraints. outlives {
147
164
let source = LocalizedNode { region : constraint. source , point : constraint. from } ;
148
165
let target = LocalizedNode { region : constraint. target , point : constraint. to } ;
149
166
edges. entry ( source) . or_default ( ) . insert ( target) ;
150
167
}
151
168
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 }
153
175
}
154
176
155
177
/// Returns the outgoing edges of a given node, not its transitive closure.
156
178
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)
158
193
}
159
194
}
160
195
0 commit comments