Skip to content

Commit

Permalink
[nll] teach SCC about 'static
Browse files Browse the repository at this point in the history
Fixes #53178
  • Loading branch information
wesleywiser committed Sep 6, 2018
1 parent db01b67 commit 4e706f5
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 13 deletions.
70 changes: 61 additions & 9 deletions src/librustc_mir/borrow_check/nll/constraints/graph.rs
Expand Up @@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use borrow_check::nll::type_check::Locations;
use borrow_check::nll::constraints::{ConstraintIndex, ConstraintSet, OutlivesConstraint};
use rustc::ty::RegionVid;
use rustc_data_structures::graph;
Expand All @@ -31,6 +32,7 @@ crate type ReverseConstraintGraph = ConstraintGraph<Reverse>;
crate trait ConstraintGraphDirecton: Copy + 'static {
fn start_region(c: &OutlivesConstraint) -> RegionVid;
fn end_region(c: &OutlivesConstraint) -> RegionVid;
fn is_normal() -> bool;
}

/// In normal mode, a `R1: R2` constraint results in an edge `R1 ->
Expand All @@ -48,6 +50,10 @@ impl ConstraintGraphDirecton for Normal {
fn end_region(c: &OutlivesConstraint) -> RegionVid {
c.sub
}

fn is_normal() -> bool {
true
}
}

/// In reverse mode, a `R1: R2` constraint results in an edge `R2 ->
Expand All @@ -65,6 +71,10 @@ impl ConstraintGraphDirecton for Reverse {
fn end_region(c: &OutlivesConstraint) -> RegionVid {
c.sup
}

fn is_normal() -> bool {
false
}
}

impl<D: ConstraintGraphDirecton> ConstraintGraph<D> {
Expand Down Expand Up @@ -98,21 +108,41 @@ impl<D: ConstraintGraphDirecton> ConstraintGraph<D> {
/// 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)
crate fn region_graph<'rg>(
&'rg self,
set: &'rg ConstraintSet,
static_region: RegionVid,
) -> RegionGraph<'rg, D> {
RegionGraph::new(set, self, static_region)
}

/// Given a region `R`, iterate over all constraints `R: R1`.
crate fn outgoing_edges<'a>(
&'a self,
region_sup: RegionVid,
constraints: &'a ConstraintSet,
static_region: RegionVid,
) -> Edges<'a, D> {
let first = self.first_constraints[region_sup];
Edges {
graph: self,
constraints,
pointer: first,
//if this is the `'static` region and the graph's direction is normal,
//then setup the Edges iterator to return all regions #53178
if region_sup == static_region && D::is_normal() {
Edges {
graph: self,
constraints,
pointer: None,
next_static_idx: Some(0),
static_region,
}
} else {
//otherwise, just setup the iterator as normal
let first = self.first_constraints[region_sup];
Edges {
graph: self,
constraints,
pointer: first,
next_static_idx: None,
static_region,
}
}
}
}
Expand All @@ -121,6 +151,8 @@ crate struct Edges<'s, D: ConstraintGraphDirecton> {
graph: &'s ConstraintGraph<D>,
constraints: &'s ConstraintSet,
pointer: Option<ConstraintIndex>,
next_static_idx: Option<usize>,
static_region: RegionVid,
}

impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> {
Expand All @@ -129,7 +161,21 @@ impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> {
fn next(&mut self) -> Option<Self::Item> {
if let Some(p) = self.pointer {
self.pointer = self.graph.next_constraints[p];

Some(self.constraints[p])
} else if let Some(next_static_idx) = self.next_static_idx {
self.next_static_idx =
if next_static_idx == (self.graph.first_constraints.len() - 1) {
None
} else {
Some(next_static_idx + 1)
};

Some(OutlivesConstraint {
sup: self.static_region,
sub: next_static_idx.into(),
locations: Locations::All,
})
} else {
None
}
Expand All @@ -142,25 +188,31 @@ impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> {
crate struct RegionGraph<'s, D: ConstraintGraphDirecton> {
set: &'s ConstraintSet,
constraint_graph: &'s ConstraintGraph<D>,
static_region: RegionVid,
}

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<D>) -> Self {
crate fn new(
set: &'s ConstraintSet,
constraint_graph: &'s ConstraintGraph<D>,
static_region: RegionVid,
) -> Self {
Self {
set,
constraint_graph,
static_region,
}
}

/// Given a region `R`, iterate over all regions `R1` such that
/// there exists a constraint `R: R1`.
crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, D> {
Successors {
edges: self.constraint_graph.outgoing_edges(region_sup, self.set),
edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region),
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/borrow_check/nll/constraints/mod.rs
Expand Up @@ -58,8 +58,9 @@ impl ConstraintSet {
crate fn compute_sccs(
&self,
constraint_graph: &graph::NormalConstraintGraph,
static_region: RegionVid,
) -> Sccs<RegionVid, ConstraintSccIndex> {
let region_graph = &constraint_graph.region_graph(self);
let region_graph = &constraint_graph.region_graph(self, static_region);
Sccs::new(region_graph)
}
}
Expand Down
Expand Up @@ -201,7 +201,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Otherwise, walk over the outgoing constraints and
// enqueue any regions we find, keeping track of how we
// reached them.
for constraint in self.constraint_graph.outgoing_edges(r, &self.constraints) {
let fr_static = self.universal_regions.fr_static;
for constraint in self.constraint_graph.outgoing_edges(r,
&self.constraints,
fr_static) {
assert_eq!(constraint.sup, r);
let sub_region = constraint.sub;
if let Trace::NotVisited = context[sub_region] {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/borrow_check/nll/region_infer/mod.rs
Expand Up @@ -234,7 +234,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {

let constraints = Rc::new(outlives_constraints); // freeze constraints
let constraint_graph = Rc::new(constraints.graph(definitions.len()));
let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph));
let fr_static = universal_regions.fr_static;
let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static));

let mut scc_values = RegionValues::new(elements, universal_regions.len(), max_universe);

Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
Expand Up @@ -69,7 +69,8 @@ fn regions_that_outlive_free_regions(
// reachable from each free region, we will have all the
// regions that are forced to outlive some free region.
let rev_constraint_graph = constraint_set.reverse_graph(num_region_vars);
let rev_region_graph = rev_constraint_graph.region_graph(constraint_set);
let fr_static = universal_regions.fr_static;
let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static);

// Stack for the depth-first search. Start out with all the free regions.
let mut stack: Vec<_> = universal_regions.universal_regions().collect();
Expand Down

0 comments on commit 4e706f5

Please sign in to comment.