]> git.lizzy.rs Git - rust.git/commitdiff
make it possible to customize the `RegionGraph` direction
authorNiko Matsakis <niko@alum.mit.edu>
Tue, 7 Aug 2018 18:14:38 +0000 (14:14 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 7 Aug 2018 18:52:59 +0000 (14:52 -0400)
src/librustc_mir/borrow_check/nll/constraints/graph.rs
src/librustc_mir/borrow_check/nll/constraints/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/mod.rs

index 5f05ae8ade5107947d5dc1c65af66cad9899b3ef..6fd6c41bebe83824df09585ee725b916b93bcc4c 100644 (file)
@@ -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>;
 }
index 289557a9a0753c583210ebdaa51a087df7ae0591..f5cab56bd29ee62fec8fea83483e0df8b9fc1460 100644 (file)
@@ -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)
     }
 }
index afd4e2859aced768268d115e4c867da0bd4d5e53..867b05639f5e2eac36151734f95df3972d524b42 100644 (file)
@@ -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.