1
Fork 0

integrate reverse graph and upper-bound computation

This commit is contained in:
Niko Matsakis 2019-06-12 10:22:07 -04:00
parent 7fd0db7dd3
commit 8d39bdd5f9

View file

@ -23,7 +23,9 @@ use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
use rustc::util::common::{self, ErrorReported}; use rustc::util::common::{self, ErrorReported};
use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use crate::rustc_data_structures::graph::WithSuccessors;
use rustc_data_structures::graph::scc::Sccs; use rustc_data_structures::graph::scc::Sccs;
use rustc_data_structures::graph::vec_graph::VecGraph;
use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::indexed_vec::IndexVec;
use rustc_errors::{Diagnostic, DiagnosticBuilder}; use rustc_errors::{Diagnostic, DiagnosticBuilder};
use syntax_pos::Span; use syntax_pos::Span;
@ -60,10 +62,15 @@ pub struct RegionInferenceContext<'tcx> {
/// the SCC (see `constraint_sccs`) and for error reporting. /// the SCC (see `constraint_sccs`) and for error reporting.
constraint_graph: Rc<NormalConstraintGraph>, constraint_graph: Rc<NormalConstraintGraph>,
/// The SCC computed from `constraints` and the constraint graph. Used to /// The SCC computed from `constraints` and the constraint
/// graph. We have an edge from SCC A to SCC B if `A: B`. Used to
/// compute the values of each region. /// compute the values of each region.
constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>, constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B`
/// exists if `B: A`. Computed lazilly.
rev_constraint_graph: Option<Rc<VecGraph<ConstraintSccIndex>>>,
/// The "pick R0 from [R1..Rn]" constraints, indexed by SCC. /// The "pick R0 from [R1..Rn]" constraints, indexed by SCC.
pick_constraints: Rc<PickConstraintSet<'tcx, ConstraintSccIndex>>, pick_constraints: Rc<PickConstraintSet<'tcx, ConstraintSccIndex>>,
@ -234,6 +241,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
constraints, constraints,
constraint_graph, constraint_graph,
constraint_sccs, constraint_sccs,
rev_constraint_graph: None,
pick_constraints, pick_constraints,
closure_bounds_mapping, closure_bounds_mapping,
scc_universes, scc_universes,
@ -602,21 +610,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.universal_regions_outlived_by(scc) .universal_regions_outlived_by(scc)
.all(|lb| self.universal_region_relations.outlives(o_r, lb)) .all(|lb| self.universal_region_relations.outlives(o_r, lb))
}); });
debug!("apply_pick_constraint: after lb, option_regions={:?}", option_regions);
// Now find all the *upper bounds* -- that is, each UB is a free // Now find all the *upper bounds* -- that is, each UB is a free
// region that must outlive pick region R0 (`UB: R0`). Therefore, // region that must outlive pick region R0 (`UB: R0`). Therefore,
// we need only keep an option O if `UB: O`. // we need only keep an option O if `UB: O` for all UB.
// if option_regions.len() > 1 {
// TODO -- need to implement the reverse graph construction for this let universal_region_relations = self.universal_region_relations.clone();
// for ub in self.upper_bounds(scc) {
// let mut upper_bounds = ...; debug!("apply_pick_constraint: ub={:?}", ub);
// option_regions.retain(|&o_r| { option_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r));
// upper_bounds }
// .all(|ub| self.universal_region_relations.outlives( debug!("apply_pick_constraint: after ub, option_regions={:?}", option_regions);
// ub, }
// o_r,
// })
// });
// If we ruled everything out, we're done. // If we ruled everything out, we're done.
if option_regions.is_empty() { if option_regions.is_empty() {
@ -656,8 +662,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
} }
} }
debug!("apply_pick_constraint: best_choice={:?}", best_option); let best_option_scc = self.constraint_sccs.scc(best_option);
self.scc_values.add_element(scc, best_option) debug!(
"apply_pick_constraint: best_choice={:?} best_option_scc={:?}",
best_option,
best_option_scc,
);
self.scc_values.add_region(scc, best_option_scc)
}
/// Compute and return the reverse SCC-based constraint graph (lazilly).
fn upper_bounds(
&mut self,
scc0: ConstraintSccIndex,
) -> Vec<RegionVid> {
// I wanted to return an `impl Iterator` here, but it's
// annoying because the `rev_constraint_graph` is in a local
// variable. We'd need a "once-cell" or some such thing to let
// us borrow it for the right amount of time.
let rev_constraint_graph = self.rev_constraint_graph();
let scc_values = &self.scc_values;
let mut duplicates = FxHashSet::default();
rev_constraint_graph
.depth_first_search(scc0)
.skip(1)
.flat_map(|scc1| scc_values.universal_regions_outlived_by(scc1))
.filter(|&r| duplicates.insert(r))
.collect()
}
/// Compute and return the reverse SCC-based constraint graph (lazilly).
fn rev_constraint_graph(
&mut self,
) -> Rc<VecGraph<ConstraintSccIndex>> {
if let Some(g) = &self.rev_constraint_graph {
return g.clone();
}
let rev_graph = Rc::new(self.constraint_sccs.reverse());
self.rev_constraint_graph = Some(rev_graph.clone());
rev_graph
} }
/// Returns `true` if all the elements in the value of `scc_b` are nameable /// Returns `true` if all the elements in the value of `scc_b` are nameable
@ -1145,8 +1189,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
debug!("eval_outlives({:?}: {:?})", sup_region, sub_region); debug!("eval_outlives({:?}: {:?})", sup_region, sub_region);
debug!("eval_outlives: sup_region's value = {:?}", self.region_value_str(sup_region),); debug!(
debug!("eval_outlives: sub_region's value = {:?}", self.region_value_str(sub_region),); "eval_outlives: sup_region's value = {:?} universal={:?}",
self.region_value_str(sup_region),
self.universal_regions.is_universal_region(sup_region),
);
debug!(
"eval_outlives: sub_region's value = {:?} universal={:?}",
self.region_value_str(sub_region),
self.universal_regions.is_universal_region(sub_region),
);
let sub_region_scc = self.constraint_sccs.scc(sub_region); let sub_region_scc = self.constraint_sccs.scc(sub_region);
let sup_region_scc = self.constraint_sccs.scc(sup_region); let sup_region_scc = self.constraint_sccs.scc(sup_region);