Skip to content
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

crater: assert_eq!(NLL, location-insensitive polonius); #117593

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 16 additions & 21 deletions compiler/rustc_borrowck/src/nll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,26 +182,22 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
let elements = &Rc::new(RegionValueElements::new(body));

// Run the MIR type-checker.
let MirTypeckResults {
constraints,
universal_region_relations,
opaque_type_values,
live_loans,
} = type_check::type_check(
infcx,
param_env,
body,
promoted,
&universal_regions,
location_table,
borrow_set,
&mut all_facts,
flow_inits,
move_data,
elements,
upvars,
polonius_input,
);
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
type_check::type_check(
infcx,
param_env,
body,
promoted,
&universal_regions,
location_table,
borrow_set,
&mut all_facts,
flow_inits,
move_data,
elements,
upvars,
polonius_input,
);

if let Some(all_facts) = &mut all_facts {
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation");
Expand Down Expand Up @@ -279,7 +275,6 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
type_tests,
liveness_constraints,
elements,
live_loans,
);

// Generate various additional constraints.
Expand Down
12 changes: 3 additions & 9 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::scc::Sccs;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_index::bit_set::SparseBitMatrix;
use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::outlives::test_type_match;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
Expand All @@ -31,8 +30,8 @@ use crate::{
nll::PoloniusOutput,
region_infer::reverse_sccs::ReverseSccGraph,
region_infer::values::{
LivenessValues, PlaceholderIndices, PointIndex, RegionElement, RegionValueElements,
RegionValues, ToElementIndex,
LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues,
ToElementIndex,
},
type_check::{free_region_relations::UniversalRegionRelations, Locations},
universal_regions::UniversalRegions,
Expand Down Expand Up @@ -120,9 +119,6 @@ pub struct RegionInferenceContext<'tcx> {
/// Information about how the universally quantified regions in
/// scope on this function relate to one another.
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,

/// The set of loans that are live at a given point in the CFG, when using `-Zpolonius=next`.
live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
}

/// Each time that `apply_member_constraint` is successful, it appends
Expand Down Expand Up @@ -335,7 +331,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
type_tests: Vec<TypeTest<'tcx>>,
liveness_constraints: LivenessValues<RegionVid>,
elements: &Rc<RegionValueElements>,
live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
) -> Self {
debug!("universal_regions: {:#?}", universal_regions);
debug!("outlives constraints: {:#?}", outlives_constraints);
Expand Down Expand Up @@ -389,7 +384,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
type_tests,
universal_regions,
universal_region_relations,
live_loans,
};

result.init_free_and_bound_regions();
Expand Down Expand Up @@ -2325,7 +2319,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`.
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool {
let point = self.liveness_constraints.point_from_location(location);
self.live_loans.contains(point, loan_idx)
self.liveness_constraints.is_loan_live_at(loan_idx, point)
}
}

Expand Down
64 changes: 63 additions & 1 deletion compiler/rustc_borrowck/src/region_infer/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use rustc_middle::ty::{self, RegionVid};
use std::fmt::Debug;
use std::rc::Rc;

use crate::dataflow::BorrowIndex;

/// Maps between a `Location` and a `PointIndex` (and vice versa).
pub(crate) struct RegionValueElements {
/// For each basic block, how many points are contained within?
Expand Down Expand Up @@ -119,16 +121,47 @@ pub(crate) enum RegionElement {
/// When we initially compute liveness, we use an interval matrix storing
/// liveness ranges for each region-vid.
pub(crate) struct LivenessValues<N: Idx> {
/// The map from locations to points.
elements: Rc<RegionValueElements>,

/// For each region: the points where it is live.
points: SparseIntervalMatrix<N, PointIndex>,

/// When using `-Zpolonius=next`, for each point: the loans flowing into the live regions at
/// that point.
pub(crate) loans: Option<LiveLoans<N>>,
}

/// Data used to compute the loans that are live at a given point in the CFG, when using
/// `-Zpolonius=next`.
pub(crate) struct LiveLoans<N: Idx> {
/// The set of loans that flow into a given region. When individual regions are marked as live
/// in the CFG, these inflowing loans are recorded as live.
pub(crate) inflowing_loans: SparseBitMatrix<N, BorrowIndex>,

/// The set of loans that are live at a given point in the CFG.
pub(crate) live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
}

impl<N: Idx> LiveLoans<N> {
pub(crate) fn new(num_loans: usize) -> Self {
LiveLoans {
live_loans: SparseBitMatrix::new(num_loans),
inflowing_loans: SparseBitMatrix::new(num_loans),
}
}
}

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.
pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
Self { points: SparseIntervalMatrix::new(elements.num_points), elements }
LivenessValues {
points: SparseIntervalMatrix::new(elements.num_points),
elements,
loans: None,
}
}

/// Iterate through each region that has a value in this set.
Expand All @@ -141,13 +174,33 @@ impl<N: Idx> LivenessValues<N> {
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);

// When available, record the loans flowing into this region as live at the given point.
if let Some(loans) = self.loans.as_mut() {
if let Some(inflowing) = loans.inflowing_loans.row(row) {
loans.live_loans.union_row(index, inflowing);
}
}

self.points.insert(row, index)
}

/// 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);

// When available, record the loans flowing into this region as live at the given points.
if let Some(loans) = self.loans.as_mut() {
if let Some(inflowing) = loans.inflowing_loans.row(row) {
if !inflowing.is_empty() {
for point in locations.iter() {
loans.live_loans.union_row(point, inflowing);
}
}
}
}

self.points.union_row(row, locations)
}

Expand Down Expand Up @@ -181,6 +234,15 @@ impl<N: Idx> LivenessValues<N> {
pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
self.elements.point_from_location(location)
}

/// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) -> bool {
self.loans
.as_ref()
.expect("Accessing live loans requires `-Zpolonius=next`")
.live_loans
.contains(point, loan_idx)
}
}

/// Maps from `ty::PlaceholderRegion` values that are used in the rest of
Expand Down
67 changes: 16 additions & 51 deletions compiler/rustc_borrowck/src/type_check/liveness/trace.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::WithSuccessors;
use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
use rustc_index::bit_set::HybridBitSet;
use rustc_index::interval::IntervalSet;
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::for_liveness;
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
use rustc_middle::traits::query::DropckOutlivesResult;
use rustc_middle::ty::{RegionVid, Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
Expand All @@ -16,9 +16,8 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
use rustc_mir_dataflow::ResultsCursor;

use crate::dataflow::BorrowIndex;
use crate::{
region_infer::values::{self, PointIndex, RegionValueElements},
region_infer::values::{self, LiveLoans, PointIndex, RegionValueElements},
type_check::liveness::local_use_map::LocalUseMap,
type_check::liveness::polonius,
type_check::NormalizeLocation,
Expand Down Expand Up @@ -54,17 +53,17 @@ pub(super) fn trace<'mir, 'tcx>(
let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body);

// When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
let num_loans = typeck.borrowck_context.borrow_set.len();
let mut inflowing_loans = SparseBitMatrix::new(num_loans);
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
let borrowck_context = &typeck.borrowck_context;
let borrowck_context = &mut typeck.borrowck_context;

let borrow_set = &borrowck_context.borrow_set;
let constraint_set = &borrowck_context.constraints.outlives_constraints;
let mut live_loans = LiveLoans::new(borrow_set.len());

let num_region_vars = typeck.infcx.num_region_vars();
let graph = constraint_set.graph(num_region_vars);
let outlives_constraints = &borrowck_context.constraints.outlives_constraints;
let graph = outlives_constraints.graph(num_region_vars);
let region_graph =
graph.region_graph(constraint_set, borrowck_context.universal_regions.fr_static);
graph.region_graph(outlives_constraints, borrowck_context.universal_regions.fr_static);

// Traverse each issuing region's constraints, and record the loan as flowing into the
// outlived region.
Expand All @@ -75,9 +74,13 @@ pub(super) fn trace<'mir, 'tcx>(
continue;
}

inflowing_loans.insert(succ, loan);
live_loans.inflowing_loans.insert(succ, loan);
}
}

// Store the inflowing loans in the liveness constraints: they will be used to compute live
// loans when liveness data is recorded there.
borrowck_context.constraints.liveness_constraints.loans = Some(live_loans);
};

let cx = LivenessContext {
Expand All @@ -88,7 +91,6 @@ pub(super) fn trace<'mir, 'tcx>(
local_use_map,
move_data,
drop_data: FxIndexMap::default(),
inflowing_loans,
};

let mut results = LivenessResults::new(cx);
Expand Down Expand Up @@ -126,9 +128,6 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
/// Index indicating where each variable is assigned, used, or
/// dropped.
local_use_map: &'me LocalUseMap,

/// Set of loans that flow into a given region, when using `-Zpolonius=next`.
inflowing_loans: SparseBitMatrix<RegionVid, BorrowIndex>,
}

struct DropData<'tcx> {
Expand Down Expand Up @@ -519,14 +518,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
live_at: &IntervalSet<PointIndex>,
) {
debug!("add_use_live_facts_for(value={:?})", value);

Self::make_all_regions_live(
self.elements,
self.typeck,
value,
live_at,
&self.inflowing_loans,
);
Self::make_all_regions_live(self.elements, self.typeck, value, live_at);
}

/// Some variable with type `live_ty` is "drop live" at `location`
Expand Down Expand Up @@ -577,14 +569,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
// All things in the `outlives` array may be touched by
// the destructor and must be live at this point.
for &kind in &drop_data.dropck_result.kinds {
Self::make_all_regions_live(
self.elements,
self.typeck,
kind,
live_at,
&self.inflowing_loans,
);

Self::make_all_regions_live(self.elements, self.typeck, kind, live_at);
polonius::add_drop_of_var_derefs_origin(self.typeck, dropped_local, &kind);
}
}
Expand All @@ -594,20 +579,13 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
typeck: &mut TypeChecker<'_, 'tcx>,
value: impl TypeVisitable<TyCtxt<'tcx>>,
live_at: &IntervalSet<PointIndex>,
inflowing_loans: &SparseBitMatrix<RegionVid, BorrowIndex>,
) {
debug!("make_all_regions_live(value={:?})", value);
debug!(
"make_all_regions_live: live_at={}",
values::location_set_str(elements, live_at.iter()),
);

// When using `-Zpolonius=next`, we want to record the loans that flow into this value's
// regions as being live at the given `live_at` points: this will be used to compute the
// location where a loan goes out of scope.
let num_loans = typeck.borrowck_context.borrow_set.len();
let value_loans = &mut HybridBitSet::new_empty(num_loans);

value.visit_with(&mut for_liveness::FreeRegionsVisitor {
tcx: typeck.tcx(),
param_env: typeck.param_env,
Expand All @@ -619,21 +597,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
.constraints
.liveness_constraints
.add_elements(live_region_vid, live_at);

// There can only be inflowing loans for this region when we are using
// `-Zpolonius=next`.
if let Some(inflowing) = inflowing_loans.row(live_region_vid) {
value_loans.union(inflowing);
}
},
});

// Record the loans reaching the value.
if !value_loans.is_empty() {
for point in live_at.iter() {
typeck.borrowck_context.live_loans.union_row(point, value_loans);
}
}
}

fn compute_drop_data(
Expand Down
Loading
Loading