use borrow_check::location::LocationTable;
use borrow_check::nll::ToRegionVid;
use borrow_check::nll::facts::AllFacts;
-use borrow_check::nll::region_infer::values::RegionValues;
+use borrow_check::nll::region_infer::values::LivenessValues;
use rustc::infer::InferCtxt;
use rustc::mir::visit::TyContext;
use rustc::mir::visit::Visitor;
pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
- liveness_constraints: &mut RegionValues<RegionVid>,
+ liveness_constraints: &mut LivenessValues<RegionVid>,
all_facts: &mut Option<AllFacts>,
location_table: &LocationTable,
mir: &Mir<'tcx>,
infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>,
all_facts: &'cg mut Option<AllFacts>,
location_table: &'cg LocationTable,
- liveness_constraints: &'cg mut RegionValues<RegionVid>,
+ liveness_constraints: &'cg mut LivenessValues<RegionVid>,
borrow_set: &'cg BorrowSet<'tcx>,
}
mod error_reporting;
mod graphviz;
pub mod values;
-use self::values::{RegionValueElements, RegionValues};
+use self::values::{RegionValueElements, RegionValues, LivenessValues};
use super::ToRegionVid;
/// regions, these start out empty and steadily grow, though for
/// each universally quantified region R they start out containing
/// the entire CFG and `end(R)`.
- liveness_constraints: RegionValues<RegionVid>,
+ liveness_constraints: LivenessValues<RegionVid>,
/// The outlives constraints computed by the type-check.
constraints: Rc<ConstraintSet>,
_mir: &Mir<'tcx>,
outlives_constraints: ConstraintSet,
type_tests: Vec<TypeTest<'tcx>>,
- liveness_constraints: RegionValues<RegionVid>,
+ liveness_constraints: LivenessValues<RegionVid>,
elements: &Rc<RegionValueElements>,
) -> Self {
let universal_regions = Rc::new(universal_regions);
let mut scc_values = RegionValues::new(elements);
- for region in liveness_constraints.regions_with_points() {
+ for region in liveness_constraints.rows() {
let scc = constraint_sccs.scc(region);
- scc_values.merge_row(scc, region, &liveness_constraints);
+ scc_values.merge_liveness(scc, region, &liveness_constraints);
}
let mut result = Self {
self.scc_values.add_all_points(variable_scc);
// Add `end(X)` into the set for X.
- self.add_live_element(variable, variable);
+ self.add_element_to_scc_of(variable, variable);
}
}
self.scc_values.region_value_str(scc)
}
- /// Indicates that the region variable `v` is live at the point `point`.
- ///
- /// Returns `true` if this constraint is new and `false` is the
- /// constraint was already present.
- pub(super) fn add_live_element(
- &mut self,
- v: RegionVid,
- elem: impl ToElementIndex,
- ) -> bool {
+ /// Adds `elem` to the value of the SCC in which `v` appears.
+ fn add_element_to_scc_of(&mut self, v: RegionVid, elem: impl ToElementIndex) {
debug!("add_live_element({:?}, {:?})", v, elem);
-
- // Add to the liveness values for `v`...
- if self.liveness_constraints.add_element(v, elem) {
- // ...but also add to the SCC in which `v` appears.
- let scc = self.constraint_sccs.scc(v);
- self.scc_values.add_element(scc, elem);
-
- true
- } else {
- false
- }
+ let scc = self.constraint_sccs.scc(v);
+ self.scc_values.add_element(scc, elem);
}
/// Perform region inference and report errors if we see any
RootUniversalRegion(RegionVid),
}
+/// When we initially compute liveness, we use a bit matrix storing
+/// points for each region-vid.
+crate struct LivenessValues<N: Idx> {
+ elements: Rc<RegionValueElements>,
+ points: SparseBitMatrix<N, PointIndex>,
+}
+
+impl<N: Idx> LivenessValues<N> {
+ /// Creates a new set of "region values" that tracks causal information.
+ /// Each of the regions in num_region_variables will be initialized with an
+ /// empty set of points and no causal information.
+ crate fn new(elements: &Rc<RegionValueElements>) -> Self {
+ Self {
+ elements: elements.clone(),
+ points: SparseBitMatrix::new(elements.num_points),
+ }
+ }
+
+ /// Iterate through each region that has a value in this set.
+ crate fn rows<'a>(&'a self) -> impl Iterator<Item = N> {
+ self.points.rows()
+ }
+
+ /// Adds the given element to the value for the given region. Returns true if
+ /// the element is newly added (i.e., was not already present).
+ crate fn add_element(
+ &mut self,
+ row: N,
+ location: Location,
+ ) -> bool {
+ debug!("LivenessValues::add(r={:?}, location={:?})", row, location);
+ let index = self.elements.point_from_location(location);
+ self.points.add(row, index)
+ }
+
+ /// Adds all the control-flow points to the values for `r`.
+ crate fn add_all_points(&mut self, row: N) {
+ self.points.add_all(row);
+ }
+
+ /// True if the region `r` contains the given element.
+ crate fn contains(&self, row: N, location: Location) -> bool {
+ let index = self.elements.point_from_location(location);
+ self.points.contains(row, index)
+ }
+
+ /// Returns a "pretty" string value of the region. Meant for debugging.
+ crate fn region_value_str(&self, r: N) -> String {
+ region_value_str(
+ self.points
+ .row(r)
+ .into_iter()
+ .flat_map(|set| set.iter())
+ .map(|p| self.elements.to_location(p))
+ .map(RegionElement::Location)
+ )
+ }
+}
+
/// Stores the values for a set of regions. These are stored in a
/// compact `SparseBitMatrix` representation, with one row per region
/// variable. The columns consist of either universal regions or
elem.contained_in_row(self, r)
}
- /// Iterate through each region that has a value in this set.
- crate fn regions_with_points<'a>(&'a self) -> impl Iterator<Item = N> {
- self.points.rows()
- }
-
/// `self[to] |= values[from]`, essentially: that is, take all the
/// elements for the region `from` from `values` and add them to
/// the region `to` in `self`.
- crate fn merge_row<M: Idx>(&mut self, to: N, from: M, values: &RegionValues<M>) {
+ crate fn merge_liveness<M: Idx>(&mut self, to: N, from: M, values: &LivenessValues<M>) {
if let Some(set) = values.points.row(from) {
self.points.merge_into(to, set);
}
-
- if let Some(set) = values.free_regions.row(from) {
- self.free_regions.merge_into(to, set);
- }
}
/// True if `sup_region` contains all the CFG points that
use borrow_check::location::LocationTable;
use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
use borrow_check::nll::facts::AllFacts;
+use borrow_check::nll::region_infer::values::{RegionValueElements, LivenessValues};
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
-use borrow_check::nll::region_infer::values::{RegionValues, RegionValueElements};
use borrow_check::nll::universal_regions::UniversalRegions;
use borrow_check::nll::ToRegionVid;
use borrow_check::nll::LocalWithRegion;
) -> MirTypeckRegionConstraints<'tcx> {
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
let mut constraints = MirTypeckRegionConstraints {
- liveness_constraints: RegionValues::new(elements),
+ liveness_constraints: LivenessValues::new(elements),
outlives_constraints: ConstraintSet::default(),
type_tests: Vec::default(),
};
/// not otherwise appear in the MIR -- in particular, the
/// late-bound regions that it instantiates at call-sites -- and
/// hence it must report on their liveness constraints.
- crate liveness_constraints: RegionValues<RegionVid>,
+ crate liveness_constraints: LivenessValues<RegionVid>,
crate outlives_constraints: ConstraintSet,