Skip to content

Commit a1ebcd2

Browse files
committed
replace location-insensitive analysis with location-sensitive analysis
we're in in the endgame now set up the location-sensitive analysis end to end: - stop recording inflowing loans and loan liveness in liveness - replace location-insensitive liveness data with live loans computed by reachability - remove equivalence between polonius scopes and NLL scopes, and only run one scope computation
1 parent 6edd002 commit a1ebcd2

File tree

6 files changed

+58
-139
lines changed

6 files changed

+58
-139
lines changed

compiler/rustc_borrowck/src/dataflow.rs

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -325,10 +325,17 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
325325
let sccs = self.regioncx.constraint_sccs();
326326
let universal_regions = self.regioncx.universal_regions();
327327

328+
// The loop below was useful for the location-insensitive analysis but shouldn't be
329+
// impactful in the location-sensitive case. It seems that it does, however, as without it a
330+
// handful of tests fail. That likely means some liveness or outlives data related to choice
331+
// regions is missing
332+
// FIXME: investigate the impact of loans traversing applied member constraints and why some
333+
// tests fail otherwise.
334+
//
328335
// We first handle the cases where the loan doesn't go out of scope, depending on the
329336
// issuing region's successors.
330337
for successor in graph::depth_first_search(&self.regioncx.region_graph(), issuing_region) {
331-
// 1. Via applied member constraints
338+
// Via applied member constraints
332339
//
333340
// The issuing region can flow into the choice regions, and they are either:
334341
// - placeholders or free regions themselves,
@@ -346,14 +353,6 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
346353
return;
347354
}
348355
}
349-
350-
// 2. Via regions that are live at all points: placeholders and free regions.
351-
//
352-
// If the issuing region outlives such a region, its loan escapes the function and
353-
// cannot go out of scope. We can early return.
354-
if self.regioncx.is_region_live_at_all_points(successor) {
355-
return;
356-
}
357356
}
358357

359358
let first_block = loan_issued_at.block;
@@ -461,34 +460,26 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
461460
regioncx: &RegionInferenceContext<'tcx>,
462461
borrow_set: &'a BorrowSet<'tcx>,
463462
) -> Self {
464-
let mut borrows_out_of_scope_at_location =
465-
calculate_borrows_out_of_scope_at_location(body, regioncx, borrow_set);
466-
467-
// The in-tree polonius analysis computes loans going out of scope using the set-of-loans
468-
// model, and makes sure they're identical to the existing computation of the set-of-points
469-
// model.
470-
if tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
471-
let mut polonius_prec = PoloniusOutOfScopePrecomputer::new(body, regioncx);
472-
for (loan_idx, loan_data) in borrow_set.iter_enumerated() {
473-
let issuing_region = loan_data.region;
474-
let loan_issued_at = loan_data.reserve_location;
475-
476-
polonius_prec.precompute_loans_out_of_scope(
477-
loan_idx,
478-
issuing_region,
479-
loan_issued_at,
480-
);
481-
}
482-
483-
assert_eq!(
484-
borrows_out_of_scope_at_location, polonius_prec.loans_out_of_scope_at_location,
485-
"polonius loan scopes differ from NLL borrow scopes, for body {:?}",
486-
body.span,
487-
);
488-
489-
borrows_out_of_scope_at_location = polonius_prec.loans_out_of_scope_at_location;
490-
}
463+
let borrows_out_of_scope_at_location =
464+
if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
465+
calculate_borrows_out_of_scope_at_location(body, regioncx, borrow_set)
466+
} else {
467+
// The in-tree polonius analysis computes loans going out of scope using the
468+
// set-of-loans model.
469+
let mut polonius_prec = PoloniusOutOfScopePrecomputer::new(body, regioncx);
470+
for (loan_idx, loan_data) in borrow_set.iter_enumerated() {
471+
let issuing_region = loan_data.region;
472+
let loan_issued_at = loan_data.reserve_location;
473+
474+
polonius_prec.precompute_loans_out_of_scope(
475+
loan_idx,
476+
issuing_region,
477+
loan_issued_at,
478+
);
479+
}
491480

481+
polonius_prec.loans_out_of_scope_at_location
482+
};
492483
Borrows { tcx, body, borrow_set, borrows_out_of_scope_at_location }
493484
}
494485

compiler/rustc_borrowck/src/nll.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
146146
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
147147
// and use them to compute loan liveness.
148148
let localized_outlives_constraints = polonius_context.as_ref().map(|polonius_context| {
149-
polonius_context.compute_loan_liveness(infcx.tcx, &regioncx, body, borrow_set)
149+
polonius_context.compute_loan_liveness(infcx.tcx, &mut regioncx, body, borrow_set)
150150
});
151151

152152
// If requested: dump NLL facts, and run legacy polonius analysis.

compiler/rustc_borrowck/src/polonius/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ impl PoloniusContext {
9898
pub(crate) fn compute_loan_liveness<'tcx>(
9999
&self,
100100
tcx: TyCtxt<'tcx>,
101-
regioncx: &RegionInferenceContext<'tcx>,
101+
regioncx: &mut RegionInferenceContext<'tcx>,
102102
body: &Body<'tcx>,
103103
borrow_set: &BorrowSet<'tcx>,
104104
) -> LocalizedOutlivesConstraintSet {
@@ -135,8 +135,7 @@ impl PoloniusContext {
135135
&localized_outlives_constraints,
136136
&mut live_loans,
137137
);
138-
// FIXME: record the live loans in the regioncx's liveness constraints, where the
139-
// location-insensitive variant's data is stored.
138+
regioncx.record_live_loans(live_loans);
140139

141140
localized_outlives_constraints
142141
}

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use crate::dataflow::BorrowIndex;
3131
use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo};
3232
use crate::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex};
3333
use crate::nll::PoloniusOutput;
34+
use crate::polonius::LiveLoans;
3435
use crate::region_infer::reverse_sccs::ReverseSccGraph;
3536
use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues, ToElementIndex};
3637
use crate::type_check::free_region_relations::UniversalRegionRelations;
@@ -2202,28 +2203,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
22022203
self.constraint_graph.region_graph(&self.constraints, self.universal_regions().fr_static)
22032204
}
22042205

2205-
/// Returns whether the given region is considered live at all points: whether it is a
2206-
/// placeholder or a free region.
2207-
pub(crate) fn is_region_live_at_all_points(&self, region: RegionVid) -> bool {
2208-
// FIXME: there must be a cleaner way to find this information. At least, when
2209-
// higher-ranked subtyping is abstracted away from the borrowck main path, we'll only
2210-
// need to check whether this is a universal region.
2211-
let origin = self.region_definition(region).origin;
2212-
let live_at_all_points = matches!(
2213-
origin,
2214-
NllRegionVariableOrigin::Placeholder(_) | NllRegionVariableOrigin::FreeRegion
2215-
);
2216-
live_at_all_points
2217-
}
2218-
2219-
/// Returns whether the `loan_idx` is live at the given `location`: whether its issuing
2220-
/// region is contained within the type of a variable that is live at this point.
2221-
/// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`.
2222-
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool {
2223-
let point = self.liveness_constraints.point_from_location(location);
2224-
self.liveness_constraints.is_loan_live_at(loan_idx, point)
2225-
}
2226-
22272206
/// Returns the representative `RegionVid` for a given SCC.
22282207
/// See `RegionTracker` for how a region variable ID is chosen.
22292208
///
@@ -2239,6 +2218,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
22392218
pub(crate) fn liveness_constraints(&self) -> &LivenessValues {
22402219
&self.liveness_constraints
22412220
}
2221+
2222+
/// When using `-Zpolonius=next`, records the given live loans for the loan scopes and active
2223+
/// loans dataflow computations.
2224+
pub(crate) fn record_live_loans(&mut self, live_loans: LiveLoans) {
2225+
self.liveness_constraints.record_live_loans(live_loans);
2226+
}
2227+
2228+
/// Returns whether the `loan_idx` is live at the given `location`: whether its issuing
2229+
/// region is contained within the type of a variable that is live at this point.
2230+
/// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`.
2231+
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool {
2232+
let point = self.liveness_constraints.point_from_location(location);
2233+
self.liveness_constraints.is_loan_live_at(loan_idx, point)
2234+
}
22422235
}
22432236

22442237
impl<'tcx> RegionDefinition<'tcx> {

compiler/rustc_borrowck/src/region_infer/values.rs

Lines changed: 12 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
1111
use tracing::debug;
1212

1313
use crate::BorrowIndex;
14+
use crate::polonius::LiveLoans;
1415

1516
rustc_index::newtype_index! {
1617
/// A single integer representing a `ty::Placeholder`.
@@ -50,29 +51,8 @@ pub(crate) struct LivenessValues {
5051
/// region is live, only that it is.
5152
points: Option<SparseIntervalMatrix<RegionVid, PointIndex>>,
5253

53-
/// When using `-Zpolonius=next`, for each point: the loans flowing into the live regions at
54-
/// that point.
55-
pub(crate) loans: Option<LiveLoans>,
56-
}
57-
58-
/// Data used to compute the loans that are live at a given point in the CFG, when using
59-
/// `-Zpolonius=next`.
60-
pub(crate) struct LiveLoans {
61-
/// The set of loans that flow into a given region. When individual regions are marked as live
62-
/// in the CFG, these inflowing loans are recorded as live.
63-
pub(crate) inflowing_loans: SparseBitMatrix<RegionVid, BorrowIndex>,
64-
65-
/// The set of loans that are live at a given point in the CFG.
66-
pub(crate) live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
67-
}
68-
69-
impl LiveLoans {
70-
pub(crate) fn new(num_loans: usize) -> Self {
71-
LiveLoans {
72-
live_loans: SparseBitMatrix::new(num_loans),
73-
inflowing_loans: SparseBitMatrix::new(num_loans),
74-
}
75-
}
54+
/// When using `-Zpolonius=next`, the set of loans that are live at a given point in the CFG.
55+
live_loans: Option<LiveLoans>,
7656
}
7757

7858
impl LivenessValues {
@@ -82,7 +62,7 @@ impl LivenessValues {
8262
live_regions: None,
8363
points: Some(SparseIntervalMatrix::new(elements.num_points())),
8464
elements,
85-
loans: None,
65+
live_loans: None,
8666
}
8767
}
8868

@@ -95,7 +75,7 @@ impl LivenessValues {
9575
live_regions: Some(Default::default()),
9676
points: None,
9777
elements,
98-
loans: None,
78+
live_loans: None,
9979
}
10080
}
10181

@@ -129,13 +109,6 @@ impl LivenessValues {
129109
} else if self.elements.point_in_range(point) {
130110
self.live_regions.as_mut().unwrap().insert(region);
131111
}
132-
133-
// When available, record the loans flowing into this region as live at the given point.
134-
if let Some(loans) = self.loans.as_mut() {
135-
if let Some(inflowing) = loans.inflowing_loans.row(region) {
136-
loans.live_loans.union_row(point, inflowing);
137-
}
138-
}
139112
}
140113

141114
/// Records `region` as being live at all the given `points`.
@@ -146,17 +119,6 @@ impl LivenessValues {
146119
} else if points.iter().any(|point| self.elements.point_in_range(point)) {
147120
self.live_regions.as_mut().unwrap().insert(region);
148121
}
149-
150-
// When available, record the loans flowing into this region as live at the given points.
151-
if let Some(loans) = self.loans.as_mut() {
152-
if let Some(inflowing) = loans.inflowing_loans.row(region) {
153-
if !inflowing.is_empty() {
154-
for point in points.iter() {
155-
loans.live_loans.union_row(point, inflowing);
156-
}
157-
}
158-
}
159-
}
160122
}
161123

162124
/// Records `region` as being live at all the control-flow points.
@@ -212,12 +174,17 @@ impl LivenessValues {
212174
self.elements.to_location(point)
213175
}
214176

177+
/// When using `-Zpolonius=next`, records the given live loans for the loan scopes and active
178+
/// loans dataflow computations.
179+
pub(crate) fn record_live_loans(&mut self, live_loans: LiveLoans) {
180+
self.live_loans = Some(live_loans);
181+
}
182+
215183
/// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
216184
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) -> bool {
217-
self.loans
185+
self.live_loans
218186
.as_ref()
219187
.expect("Accessing live loans requires `-Zpolonius=next`")
220-
.live_loans
221188
.contains(point, loan_idx)
222189
}
223190
}

compiler/rustc_borrowck/src/type_check/liveness/trace.rs

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use tracing::debug;
1717

1818
use crate::location::RichLocation;
1919
use crate::polonius;
20-
use crate::region_infer::values::{self, LiveLoans};
20+
use crate::region_infer::values;
2121
use crate::type_check::liveness::local_use_map::LocalUseMap;
2222
use crate::type_check::{NormalizeLocation, TypeChecker};
2323

@@ -45,37 +45,6 @@ pub(super) fn trace<'a, 'tcx>(
4545
boring_locals: Vec<Local>,
4646
) {
4747
let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body);
48-
49-
// When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
50-
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
51-
let borrow_set = &typeck.borrow_set;
52-
let mut live_loans = LiveLoans::new(borrow_set.len());
53-
let outlives_constraints = &typeck.constraints.outlives_constraints;
54-
let graph = outlives_constraints.graph(typeck.infcx.num_region_vars());
55-
let region_graph =
56-
graph.region_graph(outlives_constraints, typeck.universal_regions.fr_static);
57-
58-
// Traverse each issuing region's constraints, and record the loan as flowing into the
59-
// outlived region.
60-
for (loan, issuing_region_data) in borrow_set.iter_enumerated() {
61-
for succ in rustc_data_structures::graph::depth_first_search(
62-
&region_graph,
63-
issuing_region_data.region,
64-
) {
65-
// We don't need to mention that a loan flows into its issuing region.
66-
if succ == issuing_region_data.region {
67-
continue;
68-
}
69-
70-
live_loans.inflowing_loans.insert(succ, loan);
71-
}
72-
}
73-
74-
// Store the inflowing loans in the liveness constraints: they will be used to compute live
75-
// loans when liveness data is recorded there.
76-
typeck.constraints.liveness_constraints.loans = Some(live_loans);
77-
};
78-
7948
let cx = LivenessContext {
8049
typeck,
8150
body,

0 commit comments

Comments
 (0)