Skip to content

Commit 8d39bdd

Browse files
committed
integrate reverse graph and upper-bound computation
1 parent 7fd0db7 commit 8d39bdd

File tree

1 file changed

+69
-17
lines changed
  • src/librustc_mir/borrow_check/nll/region_infer

1 file changed

+69
-17
lines changed

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

Lines changed: 69 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
2323
use rustc::util::common::{self, ErrorReported};
2424
use rustc_data_structures::bit_set::BitSet;
2525
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
26+
use crate::rustc_data_structures::graph::WithSuccessors;
2627
use rustc_data_structures::graph::scc::Sccs;
28+
use rustc_data_structures::graph::vec_graph::VecGraph;
2729
use rustc_data_structures::indexed_vec::IndexVec;
2830
use rustc_errors::{Diagnostic, DiagnosticBuilder};
2931
use syntax_pos::Span;
@@ -60,10 +62,15 @@ pub struct RegionInferenceContext<'tcx> {
6062
/// the SCC (see `constraint_sccs`) and for error reporting.
6163
constraint_graph: Rc<NormalConstraintGraph>,
6264

63-
/// The SCC computed from `constraints` and the constraint graph. Used to
65+
/// The SCC computed from `constraints` and the constraint
66+
/// graph. We have an edge from SCC A to SCC B if `A: B`. Used to
6467
/// compute the values of each region.
6568
constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
6669

70+
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B`
71+
/// exists if `B: A`. Computed lazilly.
72+
rev_constraint_graph: Option<Rc<VecGraph<ConstraintSccIndex>>>,
73+
6774
/// The "pick R0 from [R1..Rn]" constraints, indexed by SCC.
6875
pick_constraints: Rc<PickConstraintSet<'tcx, ConstraintSccIndex>>,
6976

@@ -234,6 +241,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
234241
constraints,
235242
constraint_graph,
236243
constraint_sccs,
244+
rev_constraint_graph: None,
237245
pick_constraints,
238246
closure_bounds_mapping,
239247
scc_universes,
@@ -602,21 +610,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
602610
.universal_regions_outlived_by(scc)
603611
.all(|lb| self.universal_region_relations.outlives(o_r, lb))
604612
});
613+
debug!("apply_pick_constraint: after lb, option_regions={:?}", option_regions);
605614

606615
// Now find all the *upper bounds* -- that is, each UB is a free
607616
// region that must outlive pick region R0 (`UB: R0`). Therefore,
608-
// we need only keep an option O if `UB: O`.
609-
//
610-
// TODO -- need to implement the reverse graph construction for this
611-
//
612-
// let mut upper_bounds = ...;
613-
// option_regions.retain(|&o_r| {
614-
// upper_bounds
615-
// .all(|ub| self.universal_region_relations.outlives(
616-
// ub,
617-
// o_r,
618-
// })
619-
// });
617+
// we need only keep an option O if `UB: O` for all UB.
618+
if option_regions.len() > 1 {
619+
let universal_region_relations = self.universal_region_relations.clone();
620+
for ub in self.upper_bounds(scc) {
621+
debug!("apply_pick_constraint: ub={:?}", ub);
622+
option_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r));
623+
}
624+
debug!("apply_pick_constraint: after ub, option_regions={:?}", option_regions);
625+
}
620626

621627
// If we ruled everything out, we're done.
622628
if option_regions.is_empty() {
@@ -656,8 +662,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
656662
}
657663
}
658664

659-
debug!("apply_pick_constraint: best_choice={:?}", best_option);
660-
self.scc_values.add_element(scc, best_option)
665+
let best_option_scc = self.constraint_sccs.scc(best_option);
666+
debug!(
667+
"apply_pick_constraint: best_choice={:?} best_option_scc={:?}",
668+
best_option,
669+
best_option_scc,
670+
);
671+
self.scc_values.add_region(scc, best_option_scc)
672+
}
673+
674+
/// Compute and return the reverse SCC-based constraint graph (lazilly).
675+
fn upper_bounds(
676+
&mut self,
677+
scc0: ConstraintSccIndex,
678+
) -> Vec<RegionVid> {
679+
// I wanted to return an `impl Iterator` here, but it's
680+
// annoying because the `rev_constraint_graph` is in a local
681+
// variable. We'd need a "once-cell" or some such thing to let
682+
// us borrow it for the right amount of time.
683+
let rev_constraint_graph = self.rev_constraint_graph();
684+
let scc_values = &self.scc_values;
685+
let mut duplicates = FxHashSet::default();
686+
rev_constraint_graph
687+
.depth_first_search(scc0)
688+
.skip(1)
689+
.flat_map(|scc1| scc_values.universal_regions_outlived_by(scc1))
690+
.filter(|&r| duplicates.insert(r))
691+
.collect()
692+
}
693+
694+
/// Compute and return the reverse SCC-based constraint graph (lazilly).
695+
fn rev_constraint_graph(
696+
&mut self,
697+
) -> Rc<VecGraph<ConstraintSccIndex>> {
698+
if let Some(g) = &self.rev_constraint_graph {
699+
return g.clone();
700+
}
701+
702+
let rev_graph = Rc::new(self.constraint_sccs.reverse());
703+
self.rev_constraint_graph = Some(rev_graph.clone());
704+
rev_graph
661705
}
662706

663707
/// Returns `true` if all the elements in the value of `scc_b` are nameable
@@ -1145,8 +1189,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11451189
fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
11461190
debug!("eval_outlives({:?}: {:?})", sup_region, sub_region);
11471191

1148-
debug!("eval_outlives: sup_region's value = {:?}", self.region_value_str(sup_region),);
1149-
debug!("eval_outlives: sub_region's value = {:?}", self.region_value_str(sub_region),);
1192+
debug!(
1193+
"eval_outlives: sup_region's value = {:?} universal={:?}",
1194+
self.region_value_str(sup_region),
1195+
self.universal_regions.is_universal_region(sup_region),
1196+
);
1197+
debug!(
1198+
"eval_outlives: sub_region's value = {:?} universal={:?}",
1199+
self.region_value_str(sub_region),
1200+
self.universal_regions.is_universal_region(sub_region),
1201+
);
11501202

11511203
let sub_region_scc = self.constraint_sccs.scc(sub_region);
11521204
let sup_region_scc = self.constraint_sccs.scc(sup_region);

0 commit comments

Comments
 (0)