encapsulate the Region struct within region inference

This commit is contained in:
Niko Matsakis 2017-10-30 05:14:40 -04:00
parent bfc696ad8a
commit b772827350
3 changed files with 62 additions and 44 deletions

View file

@ -139,11 +139,21 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
location: Location) {
if let Some(regioncx) = self.nonlexical_regioncx {
for (borrow_index, borrow_data) in self.borrows.iter_enumerated() {
let borrow_region = regioncx.region_value(borrow_data.region.to_region_index());
if !borrow_region.may_contain_point(location) && location != borrow_data.location {
debug!("kill_loans_out_of_scope_at_location: kill{:?} \
location={:?} borrow_data={:?}", borrow_index, location, borrow_data);
sets.kill(&borrow_index);
let borrow_region = borrow_data.region.to_region_index();
if !regioncx.region_contains_point(borrow_region, location) {
// The region checker really considers the borrow
// to start at the point **after** the location of
// the borrow, but the borrow checker puts the gen
// directly **on** the location of the
// borrow. This results in a gen/kill both being
// generated for same point if we are not
// careful. Probably we should change the point of
// the gen, but for now we hackily account for the
// mismatch here by not generating a kill for the
// location on the borrow itself.
if location != borrow_data.location {
sets.kill(&borrow_index);
}
}
}
}

View file

@ -9,13 +9,12 @@
// except according to those terms.
use rustc::ty::{self, RegionKind};
use rustc::mir::{Location, Mir};
use rustc::mir::Mir;
use rustc::mir::transform::MirSource;
use rustc::infer::InferCtxt;
use rustc::util::nodemap::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
use std::collections::BTreeSet;
use std::fmt;
use util::liveness::{self, LivenessMode, LivenessResult, LocalSet};
use util as mir_util;
@ -151,39 +150,6 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
});
}
#[derive(Clone, Default, PartialEq, Eq)]
pub struct Region {
points: BTreeSet<Location>,
free_regions: BTreeSet<RegionIndex>,
}
impl fmt::Debug for Region {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
formatter.debug_set()
.entries(&self.points)
.entries(&self.free_regions)
.finish()
}
}
impl Region {
pub fn add_point(&mut self, point: Location) -> bool {
self.points.insert(point)
}
pub fn add_free_region(&mut self, region: RegionIndex) -> bool {
self.free_regions.insert(region)
}
pub fn may_contain_point(&self, point: Location) -> bool {
self.points.contains(&point)
}
pub fn may_contain_free_region(&self, region: RegionIndex) -> bool {
self.free_regions.contains(&region)
}
}
newtype_index!(RegionIndex {
DEBUG_FORMAT = "'_#{}r",
});

View file

@ -8,13 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::{Region, RegionIndex};
use super::RegionIndex;
use super::free_regions::FreeRegions;
use rustc::infer::InferCtxt;
use rustc::mir::{Location, Mir};
use rustc::ty;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::fx::FxHashSet;
use std::collections::BTreeSet;
use std::fmt;
pub struct RegionInferenceContext<'tcx> {
/// Contains the definition for every region variable. Region
@ -54,6 +56,41 @@ struct RegionDefinition<'tcx> {
value: Region,
}
/// The value of an individual region variable. Region variables
/// consist of a set of points in the CFG as well as a set of "free
/// regions", which are sometimes written as `end(R)`. These
/// correspond to the named lifetimes and refer to portions of the
/// caller's control-flow graph -- specifically some portion that can
/// be reached after we return.
#[derive(Clone, Default, PartialEq, Eq)]
struct Region {
points: BTreeSet<Location>,
free_regions: BTreeSet<RegionIndex>,
}
impl fmt::Debug for Region {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
formatter.debug_set()
.entries(&self.points)
.entries(&self.free_regions)
.finish()
}
}
impl Region {
fn add_point(&mut self, point: Location) -> bool {
self.points.insert(point)
}
fn add_free_region(&mut self, region: RegionIndex) -> bool {
self.free_regions.insert(region)
}
fn contains_point(&self, point: Location) -> bool {
self.points.contains(&point)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Constraint {
sub: RegionIndex,
@ -157,10 +194,15 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
self.definitions.indices()
}
/// Returns the inferred value for the region `r`.
/// Returns true if the region `r` contains the point `p`.
///
/// Until `solve()` executes, this value is not particularly meaningful.
pub fn region_value(&self, r: RegionIndex) -> &Region {
pub fn region_contains_point(&self, r: RegionIndex, p: Location) -> bool {
self.definitions[r].value.contains_point(p)
}
/// Returns access to the value of `r` for debugging purposes.
pub(super) fn region_value(&self, r: RegionIndex) -> &fmt::Debug {
&self.definitions[r].value
}
@ -235,7 +277,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> Dfs<'a, 'gcx, 'tcx> {
while let Some(p) = stack.pop() {
debug!(" dfs: p={:?}", p);
if !from_region.may_contain_point(p) {
if !from_region.contains_point(p) {
debug!(" not in from-region");
continue;
}