Skip to content

Commit 67a1bb1

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 0c978bc commit 67a1bb1

File tree

6 files changed

+59
-140
lines changed

6 files changed

+59
-140
lines changed

compiler/rustc_borrowck/src/dataflow.rs

+27-36
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

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

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

compiler/rustc_borrowck/src/polonius/mod.rs

+3-4
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 {
@@ -126,15 +126,14 @@ impl PoloniusContext {
126126

127127
// Now that we have a complete graph, we can compute reachability to trace the liveness of
128128
// loans for the next step in the chain, the NLL loan scope and active loans computations.
129-
let _live_loans = compute_loan_liveness(
129+
let live_loans = compute_loan_liveness(
130130
tcx,
131131
body,
132132
regioncx.liveness_constraints(),
133133
borrow_set,
134134
&localized_outlives_constraints,
135135
);
136-
// FIXME: record the live loans in the regioncx's liveness constraints, where the
137-
// location-insensitive variant's data is stored.
136+
regioncx.record_live_loans(live_loans);
138137

139138
localized_outlives_constraints
140139
}

compiler/rustc_borrowck/src/region_infer/mod.rs

+15-22
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use crate::constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstra
3131
use crate::dataflow::BorrowIndex;
3232
use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo};
3333
use crate::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex};
34+
use crate::polonius::LiveLoans;
3435
use crate::polonius::legacy::PoloniusOutput;
3536
use crate::region_infer::reverse_sccs::ReverseSccGraph;
3637
use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues, ToElementIndex};
@@ -2171,28 +2172,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
21712172
self.constraint_graph.region_graph(&self.constraints, self.universal_regions().fr_static)
21722173
}
21732174

2174-
/// Returns whether the given region is considered live at all points: whether it is a
2175-
/// placeholder or a free region.
2176-
pub(crate) fn is_region_live_at_all_points(&self, region: RegionVid) -> bool {
2177-
// FIXME: there must be a cleaner way to find this information. At least, when
2178-
// higher-ranked subtyping is abstracted away from the borrowck main path, we'll only
2179-
// need to check whether this is a universal region.
2180-
let origin = self.region_definition(region).origin;
2181-
let live_at_all_points = matches!(
2182-
origin,
2183-
NllRegionVariableOrigin::Placeholder(_) | NllRegionVariableOrigin::FreeRegion
2184-
);
2185-
live_at_all_points
2186-
}
2187-
2188-
/// Returns whether the `loan_idx` is live at the given `location`: whether its issuing
2189-
/// region is contained within the type of a variable that is live at this point.
2190-
/// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`.
2191-
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool {
2192-
let point = self.liveness_constraints.point_from_location(location);
2193-
self.liveness_constraints.is_loan_live_at(loan_idx, point)
2194-
}
2195-
21962175
/// Returns the representative `RegionVid` for a given SCC.
21972176
/// See `RegionTracker` for how a region variable ID is chosen.
21982177
///
@@ -2208,6 +2187,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
22082187
pub(crate) fn liveness_constraints(&self) -> &LivenessValues {
22092188
&self.liveness_constraints
22102189
}
2190+
2191+
/// When using `-Zpolonius=next`, records the given live loans for the loan scopes and active
2192+
/// loans dataflow computations.
2193+
pub(crate) fn record_live_loans(&mut self, live_loans: LiveLoans) {
2194+
self.liveness_constraints.record_live_loans(live_loans);
2195+
}
2196+
2197+
/// Returns whether the `loan_idx` is live at the given `location`: whether its issuing
2198+
/// region is contained within the type of a variable that is live at this point.
2199+
/// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`.
2200+
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool {
2201+
let point = self.liveness_constraints.point_from_location(location);
2202+
self.liveness_constraints.is_loan_live_at(loan_idx, point)
2203+
}
22112204
}
22122205

22132206
impl<'tcx> RegionDefinition<'tcx> {

compiler/rustc_borrowck/src/region_infer/values.rs

+12-45
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(location_map.num_points())),
8464
location_map,
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
location_map,
98-
loans: None,
78+
live_loans: None,
9979
}
10080
}
10181

@@ -129,13 +109,6 @@ impl LivenessValues {
129109
} else if self.location_map.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.location_map.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.
@@ -213,12 +175,17 @@ impl LivenessValues {
213175
self.location_map.to_location(point)
214176
}
215177

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

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

+1-32
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOp, Type
1616
use tracing::debug;
1717

1818
use crate::polonius;
19-
use crate::region_infer::values::{self, LiveLoans};
19+
use crate::region_infer::values;
2020
use crate::type_check::liveness::local_use_map::LocalUseMap;
2121
use crate::type_check::{NormalizeLocation, TypeChecker};
2222

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

0 commit comments

Comments
 (0)