split the var_origins
from the RegionConstraintData
This commit is contained in:
parent
a8daa37df6
commit
1efcf1a115
3 changed files with 262 additions and 238 deletions
|
@ -15,6 +15,7 @@ use infer::RegionVariableOrigin;
|
|||
use infer::region_constraints::Constraint;
|
||||
use infer::region_constraints::GenericKind;
|
||||
use infer::region_constraints::RegionConstraintData;
|
||||
use infer::region_constraints::VarOrigins;
|
||||
use infer::region_constraints::VerifyBound;
|
||||
use middle::free_region::RegionRelations;
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
|
@ -29,6 +30,28 @@ use ty::{ReLateBound, ReScope, ReSkolemized, ReVar};
|
|||
|
||||
mod graphviz;
|
||||
|
||||
/// This function performs lexical region resolution given a complete
|
||||
/// set of constraints and variable origins. It performs a fixed-point
|
||||
/// iteration to find region values which satisfy all constraints,
|
||||
/// assuming such values can be found. It returns the final values of
|
||||
/// all the variables as well as a set of errors that must be reported.
|
||||
pub fn resolve<'tcx>(
|
||||
region_rels: &RegionRelations<'_, '_, 'tcx>,
|
||||
var_origins: VarOrigins,
|
||||
data: RegionConstraintData<'tcx>
|
||||
) -> (
|
||||
LexicalRegionResolutions<'tcx>,
|
||||
Vec<RegionResolutionError<'tcx>>,
|
||||
) {
|
||||
debug!("RegionConstraintData: resolve_regions()");
|
||||
let mut errors = vec![];
|
||||
let mut resolver = LexicalResolver { region_rels, var_origins, data };
|
||||
let values = resolver.infer_variable_values(&mut errors);
|
||||
(values, errors)
|
||||
}
|
||||
|
||||
/// Contains the result of lexical region resolution. Offers methods
|
||||
/// to lookup up the final value of a region variable.
|
||||
pub struct LexicalRegionResolutions<'tcx> {
|
||||
values: IndexVec<RegionVid, VarValue<'tcx>>,
|
||||
error_region: ty::Region<'tcx>,
|
||||
|
@ -74,32 +97,171 @@ struct RegionAndOrigin<'tcx> {
|
|||
|
||||
type RegionGraph<'tcx> = graph::Graph<(), Constraint<'tcx>>;
|
||||
|
||||
impl<'tcx> RegionConstraintData<'tcx> {
|
||||
/// This function performs the actual region resolution. It must be
|
||||
/// called after all constraints have been added. It performs a
|
||||
/// fixed-point iteration to find region values which satisfy all
|
||||
/// constraints, assuming such values can be found; if they cannot,
|
||||
/// errors are reported.
|
||||
pub fn resolve_regions(
|
||||
mut self,
|
||||
region_rels: &RegionRelations<'_, '_, 'tcx>,
|
||||
) -> (
|
||||
LexicalRegionResolutions<'tcx>,
|
||||
Vec<RegionResolutionError<'tcx>>,
|
||||
) {
|
||||
debug!("RegionConstraintData: resolve_regions()");
|
||||
let mut errors = vec![];
|
||||
let values = self.infer_variable_values(region_rels, &mut errors);
|
||||
(values, errors)
|
||||
struct LexicalResolver<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
||||
region_rels: &'cx RegionRelations<'cx, 'gcx, 'tcx>,
|
||||
var_origins: VarOrigins,
|
||||
data: RegionConstraintData<'tcx>
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
||||
fn infer_variable_values(
|
||||
&mut self,
|
||||
errors: &mut Vec<RegionResolutionError<'tcx>>,
|
||||
) -> LexicalRegionResolutions<'tcx> {
|
||||
let mut var_data = self.construct_var_data(self.region_rels.tcx);
|
||||
|
||||
// Dorky hack to cause `dump_constraints` to only get called
|
||||
// if debug mode is enabled:
|
||||
debug!(
|
||||
"----() End constraint listing (context={:?}) {:?}---",
|
||||
self.region_rels.context,
|
||||
self.dump_constraints(self.region_rels)
|
||||
);
|
||||
graphviz::maybe_print_constraints_for(&self.data, self.region_rels);
|
||||
|
||||
let graph = self.construct_graph();
|
||||
self.expand_givens(&graph);
|
||||
self.expansion(&mut var_data);
|
||||
self.collect_errors(&mut var_data, errors);
|
||||
self.collect_var_errors(&var_data, &graph, errors);
|
||||
var_data
|
||||
}
|
||||
|
||||
fn num_vars(&self) -> usize {
|
||||
self.var_origins.len()
|
||||
}
|
||||
|
||||
/// Initially, the value for all variables is set to `'empty`, the
|
||||
/// empty region. The `expansion` phase will grow this larger.
|
||||
fn construct_var_data(&self, tcx: TyCtxt<'_, '_, 'tcx>) -> LexicalRegionResolutions<'tcx> {
|
||||
LexicalRegionResolutions {
|
||||
error_region: tcx.types.re_static,
|
||||
values: (0..self.num_vars())
|
||||
.map(|_| VarValue::Value(tcx.types.re_empty))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn dump_constraints(&self, free_regions: &RegionRelations<'_, '_, 'tcx>) {
|
||||
debug!(
|
||||
"----() Start constraint listing (context={:?}) ()----",
|
||||
free_regions.context
|
||||
);
|
||||
for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() {
|
||||
debug!("Constraint {} => {:?}", idx, constraint);
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_givens(&mut self, graph: &RegionGraph) {
|
||||
// Givens are a kind of horrible hack to account for
|
||||
// constraints like 'c <= '0 that are known to hold due to
|
||||
// closure signatures (see the comment above on the `givens`
|
||||
// field). They should go away. But until they do, the role
|
||||
// of this fn is to account for the transitive nature:
|
||||
//
|
||||
// Given 'c <= '0
|
||||
// and '0 <= '1
|
||||
// then 'c <= '1
|
||||
|
||||
let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
|
||||
for (r, vid) in seeds {
|
||||
|
||||
// While all things transitively reachable in the graph
|
||||
// from the variable (`'0` in the example above).
|
||||
let seed_index = NodeIndex(vid.index as usize);
|
||||
for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
|
||||
let succ_index = succ_index.0;
|
||||
|
||||
// The first N nodes correspond to the region
|
||||
// variables. Other nodes correspond to constant
|
||||
// regions.
|
||||
if succ_index < self.num_vars() {
|
||||
let succ_vid = RegionVid::new(succ_index);
|
||||
|
||||
// Add `'c <= '1`.
|
||||
self.data.givens.insert((r, succ_vid));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expansion(
|
||||
&self,
|
||||
var_values: &mut LexicalRegionResolutions<'tcx>,
|
||||
) {
|
||||
self.iterate_until_fixed_point("Expansion", |constraint, origin| {
|
||||
debug!("expansion: constraint={:?} origin={:?}", constraint, origin);
|
||||
match *constraint {
|
||||
Constraint::RegSubVar(a_region, b_vid) => {
|
||||
let b_data = var_values.value_mut(b_vid);
|
||||
self.expand_node(a_region, b_vid, b_data)
|
||||
}
|
||||
Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
|
||||
VarValue::ErrorValue => false,
|
||||
VarValue::Value(a_region) => {
|
||||
let b_node = var_values.value_mut(b_vid);
|
||||
self.expand_node(a_region, b_vid, b_node)
|
||||
}
|
||||
},
|
||||
Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
|
||||
// These constraints are checked after expansion
|
||||
// is done, in `collect_errors`.
|
||||
false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn expand_node(
|
||||
&self,
|
||||
a_region: Region<'tcx>,
|
||||
b_vid: RegionVid,
|
||||
b_data: &mut VarValue<'tcx>,
|
||||
) -> bool {
|
||||
debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
|
||||
|
||||
// Check if this relationship is implied by a given.
|
||||
match *a_region {
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||
if self.data.givens.contains(&(a_region, b_vid)) {
|
||||
debug!("given");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match *b_data {
|
||||
VarValue::Value(cur_region) => {
|
||||
let lub = self.lub_concrete_regions(a_region, cur_region);
|
||||
if lub == cur_region {
|
||||
return false;
|
||||
}
|
||||
|
||||
debug!(
|
||||
"Expanding value of {:?} from {:?} to {:?}",
|
||||
b_vid,
|
||||
cur_region,
|
||||
lub
|
||||
);
|
||||
|
||||
*b_data = VarValue::Value(lub);
|
||||
return true;
|
||||
}
|
||||
|
||||
VarValue::ErrorValue => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn lub_concrete_regions(
|
||||
&self,
|
||||
region_rels: &RegionRelations<'_, '_, 'tcx>,
|
||||
a: Region<'tcx>,
|
||||
b: Region<'tcx>,
|
||||
) -> Region<'tcx> {
|
||||
let tcx = region_rels.tcx;
|
||||
let tcx = self.region_rels.tcx;
|
||||
match (a, b) {
|
||||
(&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | (_, &ReErased) => {
|
||||
bug!("cannot relate region: LUB({:?}, {:?})", a, b);
|
||||
|
@ -132,14 +294,14 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
// reasonably compare free regions and scopes:
|
||||
let fr_scope = match (a, b) {
|
||||
(&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => {
|
||||
region_rels.region_scope_tree.early_free_scope(region_rels.tcx, br)
|
||||
self.region_rels.region_scope_tree.early_free_scope(self.region_rels.tcx, br)
|
||||
}
|
||||
(&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => {
|
||||
region_rels.region_scope_tree.free_scope(region_rels.tcx, fr)
|
||||
self.region_rels.region_scope_tree.free_scope(self.region_rels.tcx, fr)
|
||||
}
|
||||
_ => bug!(),
|
||||
};
|
||||
let r_id = region_rels
|
||||
let r_id = self.region_rels
|
||||
.region_scope_tree
|
||||
.nearest_common_ancestor(fr_scope, s_id);
|
||||
if r_id == fr_scope {
|
||||
|
@ -162,7 +324,7 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
// The region corresponding to an outer block is a
|
||||
// subtype of the region corresponding to an inner
|
||||
// block.
|
||||
let lub = region_rels
|
||||
let lub = self.region_rels
|
||||
.region_scope_tree
|
||||
.nearest_common_ancestor(a_id, b_id);
|
||||
tcx.mk_region(ReScope(lub))
|
||||
|
@ -171,7 +333,7 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
(&ReEarlyBound(_), &ReEarlyBound(_)) |
|
||||
(&ReFree(_), &ReEarlyBound(_)) |
|
||||
(&ReEarlyBound(_), &ReFree(_)) |
|
||||
(&ReFree(_), &ReFree(_)) => region_rels.lub_free_regions(a, b),
|
||||
(&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b),
|
||||
|
||||
// For these types, we cannot define any additional
|
||||
// relationship:
|
||||
|
@ -183,166 +345,15 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn infer_variable_values(
|
||||
&mut self,
|
||||
region_rels: &RegionRelations<'_, '_, 'tcx>,
|
||||
errors: &mut Vec<RegionResolutionError<'tcx>>,
|
||||
) -> LexicalRegionResolutions<'tcx> {
|
||||
let mut var_data = self.construct_var_data(region_rels.tcx);
|
||||
|
||||
// Dorky hack to cause `dump_constraints` to only get called
|
||||
// if debug mode is enabled:
|
||||
debug!(
|
||||
"----() End constraint listing (context={:?}) {:?}---",
|
||||
region_rels.context,
|
||||
self.dump_constraints(region_rels)
|
||||
);
|
||||
graphviz::maybe_print_constraints_for(self, region_rels);
|
||||
|
||||
let graph = self.construct_graph();
|
||||
self.expand_givens(&graph);
|
||||
self.expansion(region_rels, &mut var_data);
|
||||
self.collect_errors(region_rels, &mut var_data, errors);
|
||||
self.collect_var_errors(region_rels, &var_data, &graph, errors);
|
||||
var_data
|
||||
}
|
||||
|
||||
/// Initially, the value for all variables is set to `'empty`, the
|
||||
/// empty region. The `expansion` phase will grow this larger.
|
||||
fn construct_var_data(&self, tcx: TyCtxt<'_, '_, 'tcx>) -> LexicalRegionResolutions<'tcx> {
|
||||
LexicalRegionResolutions {
|
||||
error_region: tcx.types.re_static,
|
||||
values: (0..self.num_vars())
|
||||
.map(|_| VarValue::Value(tcx.types.re_empty))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn dump_constraints(&self, free_regions: &RegionRelations<'_, '_, 'tcx>) {
|
||||
debug!(
|
||||
"----() Start constraint listing (context={:?}) ()----",
|
||||
free_regions.context
|
||||
);
|
||||
for (idx, (constraint, _)) in self.constraints.iter().enumerate() {
|
||||
debug!("Constraint {} => {:?}", idx, constraint);
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_givens(&mut self, graph: &RegionGraph) {
|
||||
// Givens are a kind of horrible hack to account for
|
||||
// constraints like 'c <= '0 that are known to hold due to
|
||||
// closure signatures (see the comment above on the `givens`
|
||||
// field). They should go away. But until they do, the role
|
||||
// of this fn is to account for the transitive nature:
|
||||
//
|
||||
// Given 'c <= '0
|
||||
// and '0 <= '1
|
||||
// then 'c <= '1
|
||||
|
||||
let seeds: Vec<_> = self.givens.iter().cloned().collect();
|
||||
for (r, vid) in seeds {
|
||||
|
||||
// While all things transitively reachable in the graph
|
||||
// from the variable (`'0` in the example above).
|
||||
let seed_index = NodeIndex(vid.index as usize);
|
||||
for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
|
||||
let succ_index = succ_index.0;
|
||||
|
||||
// The first N nodes correspond to the region
|
||||
// variables. Other nodes correspond to constant
|
||||
// regions.
|
||||
if succ_index < self.num_vars() {
|
||||
let succ_vid = RegionVid::new(succ_index);
|
||||
|
||||
// Add `'c <= '1`.
|
||||
self.givens.insert((r, succ_vid));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expansion(
|
||||
&self,
|
||||
region_rels: &RegionRelations<'_, '_, 'tcx>,
|
||||
var_values: &mut LexicalRegionResolutions<'tcx>,
|
||||
) {
|
||||
self.iterate_until_fixed_point("Expansion", |constraint, origin| {
|
||||
debug!("expansion: constraint={:?} origin={:?}", constraint, origin);
|
||||
match *constraint {
|
||||
Constraint::RegSubVar(a_region, b_vid) => {
|
||||
let b_data = var_values.value_mut(b_vid);
|
||||
self.expand_node(region_rels, a_region, b_vid, b_data)
|
||||
}
|
||||
Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
|
||||
VarValue::ErrorValue => false,
|
||||
VarValue::Value(a_region) => {
|
||||
let b_node = var_values.value_mut(b_vid);
|
||||
self.expand_node(region_rels, a_region, b_vid, b_node)
|
||||
}
|
||||
},
|
||||
Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
|
||||
// These constraints are checked after expansion
|
||||
// is done, in `collect_errors`.
|
||||
false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn expand_node(
|
||||
&self,
|
||||
region_rels: &RegionRelations<'_, '_, 'tcx>,
|
||||
a_region: Region<'tcx>,
|
||||
b_vid: RegionVid,
|
||||
b_data: &mut VarValue<'tcx>,
|
||||
) -> bool {
|
||||
debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
|
||||
|
||||
// Check if this relationship is implied by a given.
|
||||
match *a_region {
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||
if self.givens.contains(&(a_region, b_vid)) {
|
||||
debug!("given");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match *b_data {
|
||||
VarValue::Value(cur_region) => {
|
||||
let lub = self.lub_concrete_regions(region_rels, a_region, cur_region);
|
||||
if lub == cur_region {
|
||||
return false;
|
||||
}
|
||||
|
||||
debug!(
|
||||
"Expanding value of {:?} from {:?} to {:?}",
|
||||
b_vid,
|
||||
cur_region,
|
||||
lub
|
||||
);
|
||||
|
||||
*b_data = VarValue::Value(lub);
|
||||
return true;
|
||||
}
|
||||
|
||||
VarValue::ErrorValue => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// After expansion is complete, go and check upper bounds (i.e.,
|
||||
/// cases where the region cannot grow larger than a fixed point)
|
||||
/// and check that they are satisfied.
|
||||
fn collect_errors(
|
||||
&self,
|
||||
region_rels: &RegionRelations<'_, '_, 'tcx>,
|
||||
var_data: &mut LexicalRegionResolutions<'tcx>,
|
||||
errors: &mut Vec<RegionResolutionError<'tcx>>,
|
||||
) {
|
||||
for (constraint, origin) in &self.constraints {
|
||||
for (constraint, origin) in &self.data.constraints {
|
||||
debug!(
|
||||
"collect_errors: constraint={:?} origin={:?}",
|
||||
constraint,
|
||||
|
@ -354,7 +365,7 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
}
|
||||
|
||||
Constraint::RegSubReg(sub, sup) => {
|
||||
if region_rels.is_subregion_of(sub, sup) {
|
||||
if self.region_rels.is_subregion_of(sub, sup) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -385,7 +396,7 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
// Do not report these errors immediately:
|
||||
// instead, set the variable value to error and
|
||||
// collect them later.
|
||||
if !region_rels.is_subregion_of(a_region, b_region) {
|
||||
if !self.region_rels.is_subregion_of(a_region, b_region) {
|
||||
debug!(
|
||||
"collect_errors: region error at {:?}: \
|
||||
cannot verify that {:?}={:?} <= {:?}",
|
||||
|
@ -400,7 +411,7 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
for verify in &self.verifys {
|
||||
for verify in &self.data.verifys {
|
||||
debug!("collect_errors: verify={:?}", verify);
|
||||
let sub = var_data.normalize(verify.region);
|
||||
|
||||
|
@ -410,7 +421,7 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
continue;
|
||||
}
|
||||
|
||||
if verify.bound.is_met(region_rels, var_data, sub) {
|
||||
if self.bound_is_met(&verify.bound, var_data, sub) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -434,7 +445,6 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
/// and create a `RegionResolutionError` for each of them.
|
||||
fn collect_var_errors(
|
||||
&self,
|
||||
region_rels: &RegionRelations<'_, '_, 'tcx>,
|
||||
var_data: &LexicalRegionResolutions<'tcx>,
|
||||
graph: &RegionGraph<'tcx>,
|
||||
errors: &mut Vec<RegionResolutionError<'tcx>>,
|
||||
|
@ -481,7 +491,6 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
starts to create problems we'll have to revisit
|
||||
this portion of the code and think hard about it. =) */
|
||||
self.collect_error_for_expanding_node(
|
||||
region_rels,
|
||||
graph,
|
||||
&mut dup_vec,
|
||||
node_vid,
|
||||
|
@ -509,7 +518,7 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
let dummy_source = graph.add_node(());
|
||||
let dummy_sink = graph.add_node(());
|
||||
|
||||
for (constraint, _) in &self.constraints {
|
||||
for (constraint, _) in &self.data.constraints {
|
||||
match *constraint {
|
||||
Constraint::VarSubVar(a_id, b_id) => {
|
||||
graph.add_edge(
|
||||
|
@ -536,7 +545,6 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
|
||||
fn collect_error_for_expanding_node(
|
||||
&self,
|
||||
region_rels: &RegionRelations<'_, '_, 'tcx>,
|
||||
graph: &RegionGraph<'tcx>,
|
||||
dup_vec: &mut [u32],
|
||||
node_idx: RegionVid,
|
||||
|
@ -568,7 +576,7 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
|
||||
for lower_bound in &lower_bounds {
|
||||
for upper_bound in &upper_bounds {
|
||||
if !region_rels.is_subregion_of(lower_bound.region, upper_bound.region) {
|
||||
if !self.region_rels.is_subregion_of(lower_bound.region, upper_bound.region) {
|
||||
let origin = self.var_origins[node_idx].clone();
|
||||
debug!(
|
||||
"region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
|
||||
|
@ -624,7 +632,7 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
|
||||
// to start off the process, walk the source node in the
|
||||
// direction specified
|
||||
process_edges(self, &mut state, graph, orig_node_idx, dir);
|
||||
process_edges(&self.data, &mut state, graph, orig_node_idx, dir);
|
||||
|
||||
while !state.stack.is_empty() {
|
||||
let node_idx = state.stack.pop().unwrap();
|
||||
|
@ -642,7 +650,7 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
node_idx
|
||||
);
|
||||
|
||||
process_edges(self, &mut state, graph, node_idx, dir);
|
||||
process_edges(&self.data, &mut state, graph, node_idx, dir);
|
||||
}
|
||||
|
||||
let WalkState {
|
||||
|
@ -699,7 +707,7 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
changed = false;
|
||||
iteration += 1;
|
||||
debug!("---- {} Iteration {}{}", "#", tag, iteration);
|
||||
for (constraint, origin) in &self.constraints {
|
||||
for (constraint, origin) in &self.data.constraints {
|
||||
let edge_changed = body(constraint, origin);
|
||||
if edge_changed {
|
||||
debug!("Updated due to constraint {:?}", constraint);
|
||||
|
@ -709,6 +717,27 @@ impl<'tcx> RegionConstraintData<'tcx> {
|
|||
}
|
||||
debug!("---- {} Complete after {} iteration(s)", tag, iteration);
|
||||
}
|
||||
|
||||
fn bound_is_met(
|
||||
&self,
|
||||
bound: &VerifyBound<'tcx>,
|
||||
var_values: &LexicalRegionResolutions<'tcx>,
|
||||
min: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
match bound {
|
||||
VerifyBound::AnyRegion(rs) => rs.iter()
|
||||
.map(|&r| var_values.normalize(r))
|
||||
.any(|r| self.region_rels.is_subregion_of(min, r)),
|
||||
|
||||
VerifyBound::AllRegions(rs) => rs.iter()
|
||||
.map(|&r| var_values.normalize(r))
|
||||
.all(|r| self.region_rels.is_subregion_of(min, r)),
|
||||
|
||||
VerifyBound::AnyBound(bs) => bs.iter().any(|b| self.bound_is_met(b, var_values, min)),
|
||||
|
||||
VerifyBound::AllBounds(bs) => bs.iter().all(|b| self.bound_is_met(b, var_values, min)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
|
||||
|
@ -718,29 +747,6 @@ impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
|
|||
}
|
||||
|
||||
|
||||
impl<'tcx> VerifyBound<'tcx> {
|
||||
fn is_met(
|
||||
&self,
|
||||
region_rels: &RegionRelations<'_, '_, 'tcx>,
|
||||
var_values: &LexicalRegionResolutions<'tcx>,
|
||||
min: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
match self {
|
||||
VerifyBound::AnyRegion(rs) => rs.iter()
|
||||
.map(|&r| var_values.normalize(r))
|
||||
.any(|r| region_rels.is_subregion_of(min, r)),
|
||||
|
||||
VerifyBound::AllRegions(rs) => rs.iter()
|
||||
.map(|&r| var_values.normalize(r))
|
||||
.all(|r| region_rels.is_subregion_of(min, r)),
|
||||
|
||||
VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.is_met(region_rels, var_values, min)),
|
||||
|
||||
VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.is_met(region_rels, var_values, min)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LexicalRegionResolutions<'tcx> {
|
||||
fn normalize(&self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match *r {
|
||||
|
|
|
@ -1128,15 +1128,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
"region_obligations not empty: {:#?}",
|
||||
self.region_obligations.borrow());
|
||||
|
||||
let region_rels = RegionRelations::new(self.tcx,
|
||||
region_context,
|
||||
region_map,
|
||||
free_regions);
|
||||
let region_data = self.region_constraints.borrow_mut()
|
||||
.take()
|
||||
.expect("regions already resolved")
|
||||
.into_data();
|
||||
let (lexical_region_resolutions, errors) = region_data.resolve_regions(®ion_rels);
|
||||
let region_rels = &RegionRelations::new(self.tcx,
|
||||
region_context,
|
||||
region_map,
|
||||
free_regions);
|
||||
let (var_origins, data) = self.region_constraints.borrow_mut()
|
||||
.take()
|
||||
.expect("regions already resolved")
|
||||
.into_origins_and_data();
|
||||
let (lexical_region_resolutions, errors) =
|
||||
lexical_region_resolve::resolve(region_rels, var_origins, data);
|
||||
|
||||
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
|
||||
assert!(old_value.is_none());
|
||||
|
|
|
@ -32,10 +32,26 @@ use std::u32;
|
|||
mod taint;
|
||||
|
||||
pub struct RegionConstraintCollector<'tcx> {
|
||||
/// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
|
||||
pub var_origins: IndexVec<RegionVid, RegionVariableOrigin>,
|
||||
|
||||
data: RegionConstraintData<'tcx>,
|
||||
|
||||
/// For a given pair of regions (R1, R2), maps to a region R3 that
|
||||
/// is designated as their LUB (edges R1 <= R3 and R2 <= R3
|
||||
/// exist). This prevents us from making many such regions.
|
||||
lubs: CombineMap<'tcx>,
|
||||
|
||||
/// For a given pair of regions (R1, R2), maps to a region R3 that
|
||||
/// is designated as their GLB (edges R3 <= R1 and R3 <= R2
|
||||
/// exist). This prevents us from making many such regions.
|
||||
glbs: CombineMap<'tcx>,
|
||||
|
||||
/// Number of skolemized variables currently active.
|
||||
skolemization_count: u32,
|
||||
|
||||
/// Global counter used during the GLB algorithm to create unique
|
||||
/// names for fresh bound regions
|
||||
bound_count: u32,
|
||||
|
||||
/// The undo log records actions that might later be undone.
|
||||
|
@ -49,20 +65,25 @@ pub struct RegionConstraintCollector<'tcx> {
|
|||
/// back.
|
||||
undo_log: Vec<UndoLogEntry<'tcx>>,
|
||||
|
||||
/// When we add a R1 == R2 constriant, we currently add (a) edges
|
||||
/// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this
|
||||
/// table. You can then call `opportunistic_resolve_var` early
|
||||
/// which will map R1 and R2 to some common region (i.e., either
|
||||
/// R1 or R2). This is important when dropck and other such code
|
||||
/// is iterating to a fixed point, because otherwise we sometimes
|
||||
/// would wind up with a fresh stream of region variables that
|
||||
/// have been equated but appear distinct.
|
||||
unification_table: UnificationTable<ty::RegionVid>,
|
||||
}
|
||||
|
||||
pub type VarOrigins = IndexVec<RegionVid, RegionVariableOrigin>;
|
||||
|
||||
/// The full set of region constraints gathered up by the collector.
|
||||
/// Describes a set of region variables ranging from 0..N (where N is
|
||||
/// the length of the `var_origins` vector), and various constraints
|
||||
/// between them.
|
||||
/// Describes constraints between the region variables and other
|
||||
/// regions, as well as other conditions that must be verified, or
|
||||
/// assumptions that can be made.
|
||||
#[derive(Default)]
|
||||
pub struct RegionConstraintData<'tcx> {
|
||||
/// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
|
||||
pub var_origins: IndexVec<RegionVid, RegionVariableOrigin>,
|
||||
|
||||
/// Constraints of the form `A <= B`, where either `A` or `B` can
|
||||
/// be a region variable (or neither, as it happens).
|
||||
pub constraints: BTreeMap<Constraint<'tcx>, SubregionOrigin<'tcx>>,
|
||||
|
@ -252,6 +273,7 @@ impl TaintDirections {
|
|||
impl<'tcx> RegionConstraintCollector<'tcx> {
|
||||
pub fn new() -> RegionConstraintCollector<'tcx> {
|
||||
RegionConstraintCollector {
|
||||
var_origins: VarOrigins::default(),
|
||||
data: RegionConstraintData::default(),
|
||||
lubs: FxHashMap(),
|
||||
glbs: FxHashMap(),
|
||||
|
@ -263,8 +285,8 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||
}
|
||||
|
||||
/// Once all the constraints have been gathered, extract out the final data.
|
||||
pub fn into_data(self) -> RegionConstraintData<'tcx> {
|
||||
self.data
|
||||
pub fn into_origins_and_data(self) -> (VarOrigins, RegionConstraintData<'tcx>) {
|
||||
(self.var_origins, self.data)
|
||||
}
|
||||
|
||||
fn in_snapshot(&self) -> bool {
|
||||
|
@ -324,8 +346,8 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||
// nothing to do here
|
||||
}
|
||||
AddVar(vid) => {
|
||||
self.data.var_origins.pop().unwrap();
|
||||
assert_eq!(self.data.var_origins.len(), vid.index as usize);
|
||||
self.var_origins.pop().unwrap();
|
||||
assert_eq!(self.var_origins.len(), vid.index as usize);
|
||||
}
|
||||
AddConstraint(ref constraint) => {
|
||||
self.data.constraints.remove(constraint);
|
||||
|
@ -347,7 +369,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||
}
|
||||
|
||||
pub fn new_region_var(&mut self, origin: RegionVariableOrigin) -> RegionVid {
|
||||
let vid = self.data.var_origins.push(origin.clone());
|
||||
let vid = self.var_origins.push(origin.clone());
|
||||
|
||||
let u_vid = self.unification_table
|
||||
.new_key(unify_key::RegionVidKey { min_vid: vid });
|
||||
|
@ -363,8 +385,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
|
|||
return vid;
|
||||
}
|
||||
|
||||
/// Returns the origin for the given variable.
|
||||
pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
|
||||
self.data.var_origins[vid].clone()
|
||||
self.var_origins[vid].clone()
|
||||
}
|
||||
|
||||
/// Creates a new skolemized region. Skolemized regions are fresh
|
||||
|
@ -862,9 +885,3 @@ impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionConstraintData<'tcx> {
|
||||
pub fn num_vars(&self) -> usize {
|
||||
self.var_origins.len()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue