make it possible to customize the RegionGraph
direction
This commit is contained in:
parent
a92bf8dd29
commit
887296e8c3
@ -8,27 +8,78 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::nll::constraints::{ConstraintIndex, ConstraintSet};
|
||||
use borrow_check::nll::constraints::{ConstraintIndex, ConstraintSet, OutlivesConstraint};
|
||||
use rustc::ty::RegionVid;
|
||||
use rustc_data_structures::graph;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
|
||||
crate struct ConstraintGraph {
|
||||
/// The construct graph organizes the constraints by their end-points.
|
||||
/// It can be used to view a `R1: R2` constraint as either an edge `R1
|
||||
/// -> R2` or `R2 -> R1` depending on the direction type `D`.
|
||||
crate struct ConstraintGraph<D: ConstraintGraphDirecton> {
|
||||
_direction: D,
|
||||
first_constraints: IndexVec<RegionVid, Option<ConstraintIndex>>,
|
||||
next_constraints: IndexVec<ConstraintIndex, Option<ConstraintIndex>>,
|
||||
}
|
||||
|
||||
impl ConstraintGraph {
|
||||
crate type NormalConstraintGraph = ConstraintGraph<Normal>;
|
||||
|
||||
/// Marker trait that controls whether a `R1: R2` constraint
|
||||
/// represents an edge `R1 -> R2` or `R2 -> R1`.
|
||||
crate trait ConstraintGraphDirecton: Copy + 'static {
|
||||
fn start_region(c: &OutlivesConstraint) -> RegionVid;
|
||||
fn end_region(c: &OutlivesConstraint) -> RegionVid;
|
||||
}
|
||||
|
||||
/// In normal mode, a `R1: R2` constraint results in an edge `R1 ->
|
||||
/// R2`. This is what we use when constructing the SCCs for
|
||||
/// inference. This is because we compute the value of R1 by union'ing
|
||||
/// all the things that it relies on.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
crate struct Normal;
|
||||
|
||||
impl ConstraintGraphDirecton for Normal {
|
||||
fn start_region(c: &OutlivesConstraint) -> RegionVid {
|
||||
c.sup
|
||||
}
|
||||
|
||||
fn end_region(c: &OutlivesConstraint) -> RegionVid {
|
||||
c.sub
|
||||
}
|
||||
}
|
||||
|
||||
/// In reverse mode, a `R1: R2` constraint results in an edge `R2 ->
|
||||
/// R1`. We use this for optimizing liveness computation, because then
|
||||
/// we wish to iterate from a region (e.g., R2) to all the regions
|
||||
/// that will outlive it (e.g., R1).
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
crate struct Reverse;
|
||||
|
||||
impl ConstraintGraphDirecton for Reverse {
|
||||
fn start_region(c: &OutlivesConstraint) -> RegionVid {
|
||||
c.sub
|
||||
}
|
||||
|
||||
fn end_region(c: &OutlivesConstraint) -> RegionVid {
|
||||
c.sup
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: ConstraintGraphDirecton> ConstraintGraph<D> {
|
||||
/// Create a "dependency graph" where each region constraint `R1:
|
||||
/// R2` is treated as an edge `R1 -> R2`. We use this graph to
|
||||
/// construct SCCs for region inference but also for error
|
||||
/// reporting.
|
||||
crate fn new(set: &ConstraintSet, num_region_vars: usize) -> Self {
|
||||
crate fn new(
|
||||
direction: D,
|
||||
set: &ConstraintSet,
|
||||
num_region_vars: usize,
|
||||
) -> Self {
|
||||
let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars);
|
||||
let mut next_constraints = IndexVec::from_elem(None, &set.constraints);
|
||||
|
||||
for (idx, constraint) in set.constraints.iter_enumerated().rev() {
|
||||
let head = &mut first_constraints[constraint.sup];
|
||||
let head = &mut first_constraints[D::start_region(constraint)];
|
||||
let next = &mut next_constraints[idx];
|
||||
debug_assert!(next.is_none());
|
||||
*next = *head;
|
||||
@ -36,13 +87,21 @@ impl ConstraintGraph {
|
||||
}
|
||||
|
||||
Self {
|
||||
_direction: direction,
|
||||
first_constraints,
|
||||
next_constraints,
|
||||
}
|
||||
}
|
||||
|
||||
/// Given the constraint set from which this graph was built
|
||||
/// creates a region graph so that you can iterate over *regions*
|
||||
/// and not constraints.
|
||||
crate fn region_graph<'rg>(&'rg self, set: &'rg ConstraintSet) -> RegionGraph<'rg, D> {
|
||||
RegionGraph::new(set, self)
|
||||
}
|
||||
|
||||
/// Given a region `R`, iterate over all constraints `R: R1`.
|
||||
crate fn outgoing_edges(&self, region_sup: RegionVid) -> Edges<'_> {
|
||||
crate fn outgoing_edges(&self, region_sup: RegionVid) -> Edges<'_, D> {
|
||||
let first = self.first_constraints[region_sup];
|
||||
Edges {
|
||||
graph: self,
|
||||
@ -51,12 +110,12 @@ impl ConstraintGraph {
|
||||
}
|
||||
}
|
||||
|
||||
crate struct Edges<'s> {
|
||||
graph: &'s ConstraintGraph,
|
||||
crate struct Edges<'s, D: ConstraintGraphDirecton> {
|
||||
graph: &'s ConstraintGraph<D>,
|
||||
pointer: Option<ConstraintIndex>,
|
||||
}
|
||||
|
||||
impl<'s> Iterator for Edges<'s> {
|
||||
impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> {
|
||||
type Item = ConstraintIndex;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
@ -69,17 +128,20 @@ fn next(&mut self) -> Option<Self::Item> {
|
||||
}
|
||||
}
|
||||
|
||||
crate struct RegionGraph<'s> {
|
||||
/// This struct brings together a constraint set and a (normal, not
|
||||
/// reverse) constraint graph. It implements the graph traits and is
|
||||
/// usd for doing the SCC computation.
|
||||
crate struct RegionGraph<'s, D: ConstraintGraphDirecton> {
|
||||
set: &'s ConstraintSet,
|
||||
constraint_graph: &'s ConstraintGraph,
|
||||
constraint_graph: &'s ConstraintGraph<D>,
|
||||
}
|
||||
|
||||
impl<'s> RegionGraph<'s> {
|
||||
impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> {
|
||||
/// Create a "dependency graph" where each region constraint `R1:
|
||||
/// R2` is treated as an edge `R1 -> R2`. We use this graph to
|
||||
/// construct SCCs for region inference but also for error
|
||||
/// reporting.
|
||||
crate fn new(set: &'s ConstraintSet, constraint_graph: &'s ConstraintGraph) -> Self {
|
||||
crate fn new(set: &'s ConstraintSet, constraint_graph: &'s ConstraintGraph<D>) -> Self {
|
||||
Self {
|
||||
set,
|
||||
constraint_graph,
|
||||
@ -88,7 +150,7 @@ impl<'s> RegionGraph<'s> {
|
||||
|
||||
/// Given a region `R`, iterate over all regions `R1` such that
|
||||
/// there exists a constraint `R: R1`.
|
||||
crate fn sub_regions(&self, region_sup: RegionVid) -> Successors<'_> {
|
||||
crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, D> {
|
||||
Successors {
|
||||
set: self.set,
|
||||
edges: self.constraint_graph.outgoing_edges(region_sup),
|
||||
@ -96,39 +158,39 @@ impl<'s> RegionGraph<'s> {
|
||||
}
|
||||
}
|
||||
|
||||
crate struct Successors<'s> {
|
||||
crate struct Successors<'s, D: ConstraintGraphDirecton> {
|
||||
set: &'s ConstraintSet,
|
||||
edges: Edges<'s>,
|
||||
edges: Edges<'s, D>,
|
||||
}
|
||||
|
||||
impl<'s> Iterator for Successors<'s> {
|
||||
impl<'s, D: ConstraintGraphDirecton> Iterator for Successors<'s, D> {
|
||||
type Item = RegionVid;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.edges.next().map(|c| self.set[c].sub)
|
||||
self.edges.next().map(|c| D::end_region(&self.set[c]))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> graph::DirectedGraph for RegionGraph<'s> {
|
||||
impl<'s, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, D> {
|
||||
type Node = RegionVid;
|
||||
}
|
||||
|
||||
impl<'s> graph::WithNumNodes for RegionGraph<'s> {
|
||||
impl<'s, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, D> {
|
||||
fn num_nodes(&self) -> usize {
|
||||
self.constraint_graph.first_constraints.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> graph::WithSuccessors for RegionGraph<'s> {
|
||||
impl<'s, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, D> {
|
||||
fn successors<'graph>(
|
||||
&'graph self,
|
||||
node: Self::Node,
|
||||
) -> <Self as graph::GraphSuccessors<'graph>>::Iter {
|
||||
self.sub_regions(node)
|
||||
self.outgoing_regions(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'graph> graph::GraphSuccessors<'graph> for RegionGraph<'s> {
|
||||
impl<'s, 'graph, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph> for RegionGraph<'s, D> {
|
||||
type Item = RegionVid;
|
||||
type Iter = Successors<'graph>;
|
||||
type Iter = Successors<'graph, D>;
|
||||
}
|
||||
|
@ -36,14 +36,14 @@ impl ConstraintSet {
|
||||
self.constraints.push(constraint);
|
||||
}
|
||||
|
||||
/// Constructs a graph from the constraint set; the graph makes it
|
||||
/// Constructs a "normal" graph from the constraint set; the graph makes it
|
||||
/// easy to find the constraints affecting a particular region.
|
||||
///
|
||||
/// NB: This graph contains a "frozen" view of the current
|
||||
/// constraints. any new constraints added to the `ConstraintSet`
|
||||
/// after the graph is built will not be present in the graph.
|
||||
crate fn graph(&self, num_region_vars: usize) -> graph::ConstraintGraph {
|
||||
graph::ConstraintGraph::new(self, num_region_vars)
|
||||
crate fn graph(&self, num_region_vars: usize) -> graph::NormalConstraintGraph {
|
||||
graph::ConstraintGraph::new(graph::Normal, self, num_region_vars)
|
||||
}
|
||||
|
||||
/// Compute cycles (SCCs) in the graph of regions. In particular,
|
||||
@ -51,9 +51,9 @@ impl ConstraintSet {
|
||||
/// them into an SCC, and find the relationships between SCCs.
|
||||
crate fn compute_sccs(
|
||||
&self,
|
||||
constraint_graph: &graph::ConstraintGraph,
|
||||
constraint_graph: &graph::NormalConstraintGraph,
|
||||
) -> Sccs<RegionVid, ConstraintSccIndex> {
|
||||
let region_graph = &graph::RegionGraph::new(self, constraint_graph);
|
||||
let region_graph = &constraint_graph.region_graph(self);
|
||||
Sccs::new(region_graph)
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use super::universal_regions::UniversalRegions;
|
||||
use borrow_check::nll::constraints::graph::ConstraintGraph;
|
||||
use borrow_check::nll::constraints::graph::NormalConstraintGraph;
|
||||
use borrow_check::nll::constraints::{
|
||||
ConstraintIndex, ConstraintSccIndex, ConstraintSet, OutlivesConstraint,
|
||||
};
|
||||
@ -61,7 +61,7 @@ pub struct RegionInferenceContext<'tcx> {
|
||||
/// The constraint-set, but in graph form, making it easy to traverse
|
||||
/// the constraints adjacent to a particular region. Used to construct
|
||||
/// the SCC (see `constraint_sccs`) and for error reporting.
|
||||
constraint_graph: Rc<ConstraintGraph>,
|
||||
constraint_graph: Rc<NormalConstraintGraph>,
|
||||
|
||||
/// The SCC computed from `constraints` and the constraint graph. Used to compute the values
|
||||
/// of each region.
|
||||
|
Loading…
Reference in New Issue
Block a user