separate out the liveness constraints from the final value
It will be useful later for diagnostics to be able to remember where things were live.
This commit is contained in:
parent
c16f480fa6
commit
932452ecc7
1 changed files with 47 additions and 34 deletions
|
|
@ -28,6 +28,16 @@ pub struct RegionInferenceContext<'tcx> {
|
|||
/// from as well as its final inferred value.
|
||||
definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
|
||||
|
||||
/// The liveness constraints added to each region. For most
|
||||
/// regions, these start out empty and steadily grow, though for
|
||||
/// each free region R they start out containing the entire CFG
|
||||
/// and `end(R)`.
|
||||
liveness_constraints: IndexVec<RegionVid, Region>,
|
||||
|
||||
/// The final inferred values of the inference variables; `None`
|
||||
/// until `solve` is invoked.
|
||||
inferred_values: Option<IndexVec<RegionVid, Region>>,
|
||||
|
||||
/// The constraints we have accumulated and used during solving.
|
||||
constraints: Vec<Constraint>,
|
||||
}
|
||||
|
|
@ -46,11 +56,6 @@ struct RegionDefinition<'tcx> {
|
|||
/// If true, this is a constant region which cannot grow larger.
|
||||
/// This is used for named regions as well as `'static`.
|
||||
constant: bool,
|
||||
|
||||
/// The current value of this inference variable. This starts out
|
||||
/// empty, but grows as we add constraints. The final value is
|
||||
/// determined when `solve()` is executed.
|
||||
value: Region,
|
||||
}
|
||||
|
||||
/// The value of an individual region variable. Region variables
|
||||
|
|
@ -115,6 +120,8 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
|||
/// of those will be constant regions representing the free
|
||||
/// regions defined in `free_regions`.
|
||||
pub fn new(var_origins: VarOrigins, free_regions: &FreeRegions<'tcx>, mir: &Mir<'tcx>) -> Self {
|
||||
let num_region_variables = var_origins.len();
|
||||
|
||||
// Create a RegionDefinition for each inference variable.
|
||||
let definitions = var_origins
|
||||
.into_iter()
|
||||
|
|
@ -123,6 +130,8 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
let mut result = Self {
|
||||
definitions: definitions,
|
||||
liveness_constraints: IndexVec::from_elem_n(Region::default(), num_region_variables),
|
||||
inferred_values: None,
|
||||
constraints: Vec::new(),
|
||||
};
|
||||
|
||||
|
|
@ -170,24 +179,23 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
// Add all nodes in the CFG to `definition.value`.
|
||||
for (block, block_data) in mir.basic_blocks().iter_enumerated() {
|
||||
let definition = &mut self.definitions[variable];
|
||||
let liveness_constraint = &mut self.liveness_constraints[variable];
|
||||
for statement_index in 0..block_data.statements.len() + 1 {
|
||||
let location = Location {
|
||||
block,
|
||||
statement_index,
|
||||
};
|
||||
definition.value.add_point(location);
|
||||
liveness_constraint.add_point(location);
|
||||
}
|
||||
}
|
||||
|
||||
// Add `end(X)` into the set for X.
|
||||
self.definitions[variable].value.add_free_region(variable);
|
||||
self.liveness_constraints[variable].add_free_region(variable);
|
||||
|
||||
// `'static` outlives all other free regions as well.
|
||||
if let ty::ReStatic = free_region {
|
||||
for &other_variable in indices.values() {
|
||||
self.definitions[variable]
|
||||
.value
|
||||
self.liveness_constraints[variable]
|
||||
.add_free_region(other_variable);
|
||||
}
|
||||
}
|
||||
|
|
@ -196,16 +204,14 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
|||
// Y: X is true). Add `end(X)` into the set for `Y`.
|
||||
for superregion in free_region_map.regions_that_outlive(&free_region) {
|
||||
let superregion_index = indices[superregion];
|
||||
self.definitions[superregion_index]
|
||||
.value
|
||||
.add_free_region(variable);
|
||||
self.liveness_constraints[superregion_index].add_free_region(variable);
|
||||
}
|
||||
|
||||
debug!(
|
||||
"init_free_regions: region variable for `{:?}` is `{:?}` with value `{:?}`",
|
||||
free_region,
|
||||
variable,
|
||||
self.definitions[variable].value
|
||||
self.liveness_constraints[variable],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -219,25 +225,25 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
|||
///
|
||||
/// Until `solve()` executes, this value is not particularly meaningful.
|
||||
pub fn region_contains_point(&self, r: RegionVid, p: Location) -> bool {
|
||||
self.definitions[r].value.contains_point(p)
|
||||
let inferred_values = self.inferred_values
|
||||
.as_ref()
|
||||
.expect("region values not yet inferred");
|
||||
inferred_values[r].contains_point(p)
|
||||
}
|
||||
|
||||
/// Returns access to the value of `r` for debugging purposes.
|
||||
pub(super) fn region_value(&self, r: RegionVid) -> &fmt::Debug {
|
||||
&self.definitions[r].value
|
||||
let inferred_values = self.inferred_values
|
||||
.as_ref()
|
||||
.expect("region values not yet inferred");
|
||||
&inferred_values[r]
|
||||
}
|
||||
|
||||
/// Indicates that the region variable `v` is live at the point `point`.
|
||||
pub(super) fn add_live_point(&mut self, v: RegionVid, point: Location) {
|
||||
debug!("add_live_point({:?}, {:?})", v, point);
|
||||
let definition = &mut self.definitions[v];
|
||||
if !definition.constant {
|
||||
definition.value.add_point(point);
|
||||
} else {
|
||||
// Constants are used for free regions, which already
|
||||
// contain all the points in the control-flow graph.
|
||||
assert!(definition.value.contains_point(point));
|
||||
}
|
||||
assert!(self.inferred_values.is_none(), "values already inferred");
|
||||
self.liveness_constraints[v].add_point(point);
|
||||
}
|
||||
|
||||
/// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
|
||||
|
|
@ -249,6 +255,7 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
|||
point: Location,
|
||||
) {
|
||||
debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point);
|
||||
assert!(self.inferred_values.is_none(), "values already inferred");
|
||||
self.constraints.push(Constraint {
|
||||
span,
|
||||
sup,
|
||||
|
|
@ -259,6 +266,7 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
/// Perform region inference.
|
||||
pub(super) fn solve(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>) {
|
||||
assert!(self.inferred_values.is_none(), "values already inferred");
|
||||
let errors = self.propagate_constraints(mir);
|
||||
|
||||
// worst error msg ever
|
||||
|
|
@ -291,39 +299,43 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
|||
constraints
|
||||
});
|
||||
|
||||
// The initial values for each region are derived from the liveness
|
||||
// constraints we have accumulated.
|
||||
let mut inferred_values = self.liveness_constraints.clone();
|
||||
|
||||
while changed {
|
||||
changed = false;
|
||||
for constraint in &self.constraints {
|
||||
debug!("propagate_constraints: constraint={:?}", constraint);
|
||||
let sub = &self.definitions[constraint.sub].value.clone();
|
||||
let sup_def = &mut self.definitions[constraint.sup];
|
||||
let sub = &inferred_values[constraint.sub].clone();
|
||||
let sup_value = &mut inferred_values[constraint.sup];
|
||||
|
||||
debug!("propagate_constraints: sub (before): {:?}", sub);
|
||||
debug!("propagate_constraints: sup (before): {:?}", sup_def.value);
|
||||
debug!("propagate_constraints: sup (before): {:?}", sup_value);
|
||||
|
||||
if !sup_def.constant {
|
||||
if !self.definitions[constraint.sup].constant {
|
||||
// If this is not a constant, then grow the value as needed to
|
||||
// accommodate the outlives constraint.
|
||||
|
||||
if dfs.copy(sub, &mut sup_def.value, constraint.point) {
|
||||
if dfs.copy(sub, sup_value, constraint.point) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
debug!("propagate_constraints: sup (after) : {:?}", sup_def.value);
|
||||
debug!("propagate_constraints: sup (after) : {:?}", sup_value);
|
||||
debug!("propagate_constraints: changed : {:?}", changed);
|
||||
} else {
|
||||
// If this is a constant, check whether it *would
|
||||
// have* to grow in order for the constraint to be
|
||||
// satisfied. If so, create an error.
|
||||
|
||||
let mut sup_value = sup_def.value.clone();
|
||||
if dfs.copy(sub, &mut sup_value, constraint.point) {
|
||||
let sup_value = &mut sup_value.clone();
|
||||
if dfs.copy(sub, sup_value, constraint.point) {
|
||||
// Constant values start out with the entire
|
||||
// CFG, so it must be some new free region
|
||||
// that was added. Find one.
|
||||
let &new_region = sup_value
|
||||
.free_regions
|
||||
.difference(&sup_def.value.free_regions)
|
||||
.difference(&sup_value.free_regions)
|
||||
.next()
|
||||
.unwrap();
|
||||
debug!("propagate_constraints: new_region : {:?}", new_region);
|
||||
|
|
@ -335,6 +347,8 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
debug!("\n");
|
||||
}
|
||||
|
||||
self.inferred_values = Some(inferred_values);
|
||||
errors
|
||||
}
|
||||
}
|
||||
|
|
@ -424,7 +438,6 @@ impl<'tcx> RegionDefinition<'tcx> {
|
|||
origin,
|
||||
name: None,
|
||||
constant: false,
|
||||
value: Region::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue