[nll] teach SCC about 'static

Fixes #53178
This commit is contained in:
Wesley Wiser 2018-08-26 22:50:57 -04:00
parent db01b6789d
commit 4e706f56bd
5 changed files with 71 additions and 13 deletions

View file

@ -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;
@ -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 ->
@ -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 ->
@ -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> {
@ -98,8 +108,12 @@ 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`.
@ -107,12 +121,28 @@ impl<D: ConstraintGraphDirecton> ConstraintGraph<D> {
&'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,
}
}
}
}
@ -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> {
@ -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
}
@ -142,6 +188,7 @@ 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> {
@ -149,10 +196,15 @@ impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> {
/// 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,
}
}
@ -160,7 +212,7 @@ impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> {
/// 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),
}
}
}

View file

@ -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)
}
}

View file

@ -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] {

View file

@ -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);

View file

@ -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();