Skip to content

Refactor borrowck liveness values #117880

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 26, 2023
Merged
8 changes: 4 additions & 4 deletions compiler/rustc_borrowck/src/constraint_generation.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ use rustc_middle::mir::{
};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
use rustc_middle::ty::{self, Ty, TyCtxt};

use crate::{
borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, places_conflict,
@@ -18,7 +18,7 @@ use crate::{

pub(super) fn generate_constraints<'tcx>(
infcx: &InferCtxt<'tcx>,
liveness_constraints: &mut LivenessValues<RegionVid>,
liveness_constraints: &mut LivenessValues,
all_facts: &mut Option<AllFacts>,
location_table: &LocationTable,
body: &Body<'tcx>,
@@ -43,7 +43,7 @@ struct ConstraintGeneration<'cg, 'tcx> {
infcx: &'cg InferCtxt<'tcx>,
all_facts: &'cg mut Option<AllFacts>,
location_table: &'cg LocationTable,
liveness_constraints: &'cg mut LivenessValues<RegionVid>,
liveness_constraints: &'cg mut LivenessValues,
borrow_set: &'cg BorrowSet<'tcx>,
body: &'cg Body<'tcx>,
}
@@ -167,7 +167,7 @@ impl<'cx, 'tcx> ConstraintGeneration<'cx, 'tcx> {

self.infcx.tcx.for_each_free_region(&live_ty, |live_region| {
let vid = live_region.as_var();
self.liveness_constraints.add_element(vid, location);
self.liveness_constraints.add_location(vid, location);
});
}

2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/region_infer/dump_mir.rs
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
with_msg: &mut dyn FnMut(&str) -> io::Result<()>,
) -> io::Result<()> {
for region in self.definitions.indices() {
let value = self.liveness_constraints.region_value_str(region);
let value = self.liveness_constraints.pretty_print_live_points(region);
if value != "{}" {
with_msg(&format!("{region:?} live at {value}"))?;
}
16 changes: 8 additions & 8 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@ pub struct RegionInferenceContext<'tcx> {
/// 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: LivenessValues<RegionVid>,
liveness_constraints: LivenessValues,

/// The outlives constraints computed by the type-check.
constraints: Frozen<OutlivesConstraintSet<'tcx>>,
@@ -332,7 +332,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
type_tests: Vec<TypeTest<'tcx>>,
liveness_constraints: LivenessValues<RegionVid>,
liveness_constraints: LivenessValues,
elements: &Rc<RegionValueElements>,
live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
) -> Self {
@@ -359,7 +359,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let mut scc_values =
RegionValues::new(elements, universal_regions.len(), &placeholder_indices);

for region in liveness_constraints.rows() {
for region in liveness_constraints.regions() {
let scc = constraint_sccs.scc(region);
scc_values.merge_liveness(scc, region, &liveness_constraints);
}
@@ -1963,15 +1963,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
None
}

/// Finds some region R such that `fr1: R` and `R` is live at `elem`.
/// Finds some region R such that `fr1: R` and `R` is live at `location`.
#[instrument(skip(self), level = "trace", ret)]
pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, location: Location) -> RegionVid {
trace!(scc = ?self.constraint_sccs.scc(fr1));
trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]);
self.find_constraint_paths_between_regions(fr1, |r| {
// First look for some `r` such that `fr1: r` and `r` is live at `elem`
trace!(?r, liveness_constraints=?self.liveness_constraints.region_value_str(r));
self.liveness_constraints.contains(r, elem)
// First look for some `r` such that `fr1: r` and `r` is live at `location`
trace!(?r, liveness_constraints=?self.liveness_constraints.pretty_print_live_points(r));
self.liveness_constraints.is_live_at(r, location)
})
.or_else(|| {
// If we fail to find that, we may find some `r` such that
85 changes: 45 additions & 40 deletions compiler/rustc_borrowck/src/region_infer/values.rs
Original file line number Diff line number Diff line change
@@ -116,65 +116,68 @@ pub(crate) enum RegionElement {
PlaceholderRegion(ty::PlaceholderRegion),
}

/// When we initially compute liveness, we use an interval matrix storing
/// liveness ranges for each region-vid.
pub(crate) struct LivenessValues<N: Idx> {
/// Records the CFG locations where each region is live. When we initially compute liveness, we use
/// an interval matrix storing liveness ranges for each region-vid.
pub(crate) struct LivenessValues {
elements: Rc<RegionValueElements>,
points: SparseIntervalMatrix<N, PointIndex>,
points: SparseIntervalMatrix<RegionVid, 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.
impl LivenessValues {
/// Create an empty map of regions to locations where they're live.
pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
Self { points: SparseIntervalMatrix::new(elements.num_points), elements }
}

/// Iterate through each region that has a value in this set.
pub(crate) fn rows(&self) -> impl Iterator<Item = N> {
pub(crate) fn regions(&self) -> impl Iterator<Item = RegionVid> {
self.points.rows()
}

/// Adds the given element to the value for the given region. Returns whether
/// the element is newly added (i.e., was not already present).
pub(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.insert(row, index)
/// Records `region` as being live at the given `location`.
pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) {
debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
let point = self.elements.point_from_location(location);
self.points.insert(region, point);
}

/// Adds all the elements in the given bit array into the given
/// region. Returns whether any of them are newly added.
pub(crate) fn add_elements(&mut self, row: N, locations: &IntervalSet<PointIndex>) -> bool {
debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
self.points.union_row(row, locations)
/// Records `region` as being live at all the given `points`.
pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet<PointIndex>) {
debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
self.points.union_row(region, points);
}

/// Adds all the control-flow points to the values for `r`.
pub(crate) fn add_all_points(&mut self, row: N) {
self.points.insert_all_into_row(row);
/// Records `region` as being live at all the control-flow points.
pub(crate) fn add_all_points(&mut self, region: RegionVid) {
self.points.insert_all_into_row(region);
}

/// Returns `true` if the region `r` contains the given element.
pub(crate) fn contains(&self, row: N, location: Location) -> bool {
let index = self.elements.point_from_location(location);
self.points.row(row).is_some_and(|r| r.contains(index))
/// Returns whether `region` is marked live at the given `location`.
pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
let point = self.elements.point_from_location(location);
self.points.row(region).is_some_and(|r| r.contains(point))
}

/// Returns whether `region` is marked live at any location.
pub(crate) fn is_live_anywhere(&self, region: RegionVid) -> bool {
self.live_points(region).next().is_some()
}

/// Returns an iterator of all the elements contained by the region `r`
pub(crate) fn get_elements(&self, row: N) -> impl Iterator<Item = Location> + '_ {
/// Returns an iterator of all the points where `region` is live.
fn live_points(&self, region: RegionVid) -> impl Iterator<Item = PointIndex> + '_ {
self.points
.row(row)
.row(region)
.into_iter()
.flat_map(|set| set.iter())
.take_while(move |&p| self.elements.point_in_range(p))
.map(move |p| self.elements.to_location(p))
.take_while(|&p| self.elements.point_in_range(p))
}

/// Returns a "pretty" string value of the region. Meant for debugging.
pub(crate) fn region_value_str(&self, r: N) -> String {
region_value_str(self.get_elements(r).map(RegionElement::Location))
/// For debugging purposes, returns a pretty-printed string of the points where the `region` is
/// live.
pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String {
pretty_print_region_elements(
self.live_points(region).map(|p| RegionElement::Location(self.elements.to_location(p))),
)
}

#[inline]
@@ -307,7 +310,7 @@ impl<N: Idx> RegionValues<N> {
/// `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`.
pub(crate) fn merge_liveness<M: Idx>(&mut self, to: N, from: M, values: &LivenessValues<M>) {
pub(crate) fn merge_liveness(&mut self, to: N, from: RegionVid, values: &LivenessValues) {
if let Some(set) = values.points.row(from) {
self.points.union_row(to, set);
}
@@ -376,7 +379,7 @@ impl<N: Idx> RegionValues<N> {

/// Returns a "pretty" string value of the region. Meant for debugging.
pub(crate) fn region_value_str(&self, r: N) -> String {
region_value_str(self.elements_contained_in(r))
pretty_print_region_elements(self.elements_contained_in(r))
}
}

@@ -420,11 +423,12 @@ impl ToElementIndex for ty::PlaceholderRegion {
}
}

pub(crate) fn location_set_str(
/// For debugging purposes, returns a pretty-printed string of the given points.
pub(crate) fn pretty_print_points(
elements: &RegionValueElements,
points: impl IntoIterator<Item = PointIndex>,
) -> String {
region_value_str(
pretty_print_region_elements(
points
.into_iter()
.take_while(|&p| elements.point_in_range(p))
@@ -433,7 +437,8 @@ pub(crate) fn location_set_str(
)
}

fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String {
/// For debugging purposes, returns a pretty-printed string of the given region elements.
fn pretty_print_region_elements(elements: impl IntoIterator<Item = RegionElement>) -> String {
let mut result = String::new();
result.push('{');

6 changes: 3 additions & 3 deletions compiler/rustc_borrowck/src/type_check/liveness/trace.rs
Original file line number Diff line number Diff line change
@@ -550,7 +550,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
dropped_local,
dropped_ty,
drop_locations,
values::location_set_str(self.elements, live_at.iter()),
values::pretty_print_points(self.elements, live_at.iter()),
);

let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
@@ -599,7 +599,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
debug!("make_all_regions_live(value={:?})", value);
debug!(
"make_all_regions_live: live_at={}",
values::location_set_str(elements, live_at.iter()),
values::pretty_print_points(elements, live_at.iter()),
);

// When using `-Zpolonius=next`, we want to record the loans that flow into this value's
@@ -618,7 +618,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
.borrowck_context
.constraints
.liveness_constraints
.add_elements(live_region_vid, live_at);
.add_points(live_region_vid, live_at);

// There can only be inflowing loans for this region when we are using
// `-Zpolonius=next`.
12 changes: 6 additions & 6 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
@@ -318,7 +318,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
.borrowck_context
.constraints
.liveness_constraints
.add_element(live_region_vid, location);
.add_location(live_region_vid, location);
});

// HACK(compiler-errors): Constants that are gathered into Body.required_consts
@@ -592,16 +592,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
self.cx.borrowck_context.constraints.outlives_constraints.push(constraint)
}
for region in liveness_constraints.rows() {
for region in liveness_constraints.regions() {
// If the region is live at at least one location in the promoted MIR,
// then add a liveness constraint to the main MIR for this region
// at the location provided as an argument to this method
if liveness_constraints.get_elements(region).next().is_some() {
if liveness_constraints.is_live_anywhere(region) {
self.cx
.borrowck_context
.constraints
.liveness_constraints
.add_element(region, location);
.add_location(region, location);
}
}
}
@@ -899,7 +899,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
/// 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.
pub(crate) liveness_constraints: LivenessValues<RegionVid>,
pub(crate) liveness_constraints: LivenessValues,

pub(crate) outlives_constraints: OutlivesConstraintSet<'tcx>,

@@ -1443,7 +1443,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.borrowck_context
.constraints
.liveness_constraints
.add_element(region_vid, term_location);
.add_location(region_vid, term_location);
}

self.check_call_inputs(body, term, func, &sig, args, term_location, *call_source);