Skip to content

Commit 0749721

Browse files
committed
compute SCCs in dependency order
1 parent b8caef4 commit 0749721

File tree

1 file changed

+60
-33
lines changed
  • src/librustc_mir/borrow_check/region_infer

1 file changed

+60
-33
lines changed

src/librustc_mir/borrow_check/region_infer/mod.rs

+60-33
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ pub struct RegionInferenceContext<'tcx> {
6767
/// compute the values of each region.
6868
constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
6969

70+
/// SCCs in "dependency order" (or "post order"), meaning that if S1 -> S2,
71+
/// then S2 appears first. If you process the SCCs in this order, then you
72+
/// are always ensured that when you proces a given SCC, all of its
73+
/// successors have been processed.
74+
scc_dependency_order: Vec<ConstraintSccIndex>,
75+
7076
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if
7177
/// `B: A`. This is used to compute the universal regions that are required
7278
/// to outlive a given SCC. Computed lazily.
@@ -277,7 +283,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
277283
scc_values.merge_liveness(scc, region, &liveness_constraints);
278284
}
279285

280-
let scc_universes = Self::compute_scc_universes(&constraint_sccs, &definitions);
286+
let scc_dependency_order = Self::compute_scc_dependency_order(&constraint_sccs);
287+
288+
let scc_universes =
289+
Self::compute_scc_universes(&constraint_sccs, &scc_dependency_order, &definitions);
281290

282291
let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions);
283292

@@ -290,6 +299,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
290299
constraints,
291300
constraint_graph,
292301
constraint_sccs,
302+
scc_dependency_order,
293303
rev_scc_graph: None,
294304
member_constraints,
295305
member_constraints_applied: Vec::new(),
@@ -307,6 +317,43 @@ impl<'tcx> RegionInferenceContext<'tcx> {
307317
result
308318
}
309319

320+
/// Returns a vector of all scc-ids in "dependency" or "post order". See the
321+
/// `scc_dependency_order` field for more details.
322+
fn compute_scc_dependency_order(
323+
constraints_scc: &Sccs<RegionVid, ConstraintSccIndex>,
324+
) -> Vec<ConstraintSccIndex> {
325+
let mut visited = &mut BitSet::new_empty(constraints_scc.num_sccs());
326+
let mut output = vec![];
327+
328+
for scc in constraints_scc.all_sccs() {
329+
Self::compute_scc_dependency_order_if_new(
330+
constraints_scc,
331+
scc,
332+
&mut visited,
333+
&mut output,
334+
);
335+
}
336+
337+
output
338+
}
339+
340+
fn compute_scc_dependency_order_if_new(
341+
constraints_scc: &Sccs<RegionVid, ConstraintSccIndex>,
342+
index: ConstraintSccIndex,
343+
visited: &mut BitSet<ConstraintSccIndex>,
344+
output: &mut Vec<ConstraintSccIndex>,
345+
) {
346+
if !visited.insert(index) {
347+
return;
348+
}
349+
350+
for &succ in constraints_scc.successors(index) {
351+
Self::compute_scc_dependency_order_if_new(constraints_scc, succ, visited, output);
352+
}
353+
354+
output.push(index);
355+
}
356+
310357
/// Each SCC is the combination of many region variables which
311358
/// have been equated. Therefore, we can associate a universe with
312359
/// each SCC which is minimum of all the universes of its
@@ -315,10 +362,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
315362
/// SCC could have as well. This implies that the SCC must have
316363
/// the minimum, or narrowest, universe.
317364
fn compute_scc_universes(
318-
constraints_scc: &Sccs<RegionVid, ConstraintSccIndex>,
365+
constraint_sccs: &Sccs<RegionVid, ConstraintSccIndex>,
366+
scc_dependency_order: &[ConstraintSccIndex],
319367
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
320368
) -> IndexVec<ConstraintSccIndex, ty::UniverseIndex> {
321-
let num_sccs = constraints_scc.num_sccs();
369+
let num_sccs = constraint_sccs.num_sccs();
322370
let mut scc_universes = IndexVec::from_elem_n(ty::UniverseIndex::MAX, num_sccs);
323371

324372
debug!("compute_scc_universes()");
@@ -327,7 +375,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
327375
// that contains R is "no bigger" than U. This effectively sets the universe
328376
// for each SCC to be the minimum of the regions within.
329377
for (region_vid, region_definition) in definitions.iter_enumerated() {
330-
let scc = constraints_scc.scc(region_vid);
378+
let scc = constraint_sccs.scc(region_vid);
331379
let scc_universe = &mut scc_universes[scc];
332380
let scc_min = std::cmp::min(region_definition.universe, *scc_universe);
333381
if scc_min != *scc_universe {
@@ -372,8 +420,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
372420
// constraint lowers the universe of `R1` to `U0`, which in turn
373421
// means that the `R1: !1` constraint will (later) cause
374422
// `R1` to become `'static`.
375-
for scc_a in constraints_scc.all_sccs() {
376-
for &scc_b in constraints_scc.successors(scc_a) {
423+
for &scc_a in scc_dependency_order {
424+
for &scc_b in constraint_sccs.successors(scc_a) {
377425
let scc_universe_a = scc_universes[scc_a];
378426
let scc_universe_b = scc_universes[scc_b];
379427
let scc_universe_min = std::cmp::min(scc_universe_a, scc_universe_b);
@@ -616,47 +664,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
616664
// SCC. For each SCC, we visit its successors and compute
617665
// their values, then we union all those values to get our
618666
// own.
619-
let visited = &mut BitSet::new_empty(self.constraint_sccs.num_sccs());
620-
for scc_index in self.constraint_sccs.all_sccs() {
621-
self.propagate_constraint_sccs_if_new(scc_index, visited);
667+
for i in 0..self.scc_dependency_order.len() {
668+
self.compute_value_for_scc(self.scc_dependency_order[i]);
622669
}
623670

624671
// Sort the applied member constraints so we can binary search
625672
// through them later.
626673
self.member_constraints_applied.sort_by_key(|applied| applied.member_region_scc);
627674
}
628675

629-
/// Computes the value of the SCC `scc_a` if it has not already
630-
/// been computed. The `visited` parameter is a bitset
631-
#[inline]
632-
fn propagate_constraint_sccs_if_new(
633-
&mut self,
634-
scc_a: ConstraintSccIndex,
635-
visited: &mut BitSet<ConstraintSccIndex>,
636-
) {
637-
if visited.insert(scc_a) {
638-
self.propagate_constraint_sccs_new(scc_a, visited);
639-
}
640-
}
641-
642676
/// Computes the value of the SCC `scc_a`, which has not yet been
643-
/// computed. This works by first computing all successors of the
644-
/// SCC (if they haven't been computed already) and then unioning
645-
/// together their elements.
646-
fn propagate_constraint_sccs_new(
647-
&mut self,
648-
scc_a: ConstraintSccIndex,
649-
visited: &mut BitSet<ConstraintSccIndex>,
650-
) {
677+
/// computed, by unioning the values of its successors.
678+
/// Assumes that all successors have been computed already
679+
/// (which is assured by iterating over SCCs in dependency order).
680+
fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) {
651681
let constraint_sccs = self.constraint_sccs.clone();
652682

653683
// Walk each SCC `B` such that `A: B`...
654684
for &scc_b in constraint_sccs.successors(scc_a) {
655685
debug!("propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", scc_a, scc_b);
656686

657-
// ...compute the value of `B`...
658-
self.propagate_constraint_sccs_if_new(scc_b, visited);
659-
660687
// ...and add elements from `B` into `A`. One complication
661688
// arises because of universes: If `B` contains something
662689
// that `A` cannot name, then `A` can only contain `B` if

0 commit comments

Comments
 (0)