Skip to content

Commit 6054a33

Browse files
committed
split polonius context into per-phase data
- describe how that data flows during borrowck - prepares for recording some liveness data for diagnostics, not just for the main analysis
1 parent 25a1657 commit 6054a33

File tree

5 files changed

+70
-50
lines changed

5 files changed

+70
-50
lines changed

compiler/rustc_borrowck/src/polonius/liveness_constraints.rs

+2-22
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
use std::collections::BTreeMap;
22

33
use rustc_index::bit_set::SparseBitMatrix;
4-
use rustc_index::interval::SparseIntervalMatrix;
54
use rustc_middle::mir::{Body, Location};
65
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
76
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};
87
use rustc_mir_dataflow::points::PointIndex;
98

109
use super::{
1110
ConstraintDirection, LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet,
12-
PoloniusContext,
11+
PoloniusLivenessContext,
1312
};
1413
use crate::region_infer::values::LivenessValues;
1514
use crate::universal_regions::UniversalRegions;
1615

17-
impl PoloniusContext {
16+
impl PoloniusLivenessContext {
1817
/// Record the variance of each region contained within the given value.
1918
pub(crate) fn record_live_region_variance<'tcx>(
2019
&mut self,
@@ -30,25 +29,6 @@ impl PoloniusContext {
3029
};
3130
extractor.relate(value, value).expect("Can't have a type error relating to itself");
3231
}
33-
34-
/// Unlike NLLs, in polonius we traverse the cfg to look for regions live across an edge, so we
35-
/// need to transpose the "points where each region is live" matrix to a "live regions per point"
36-
/// matrix.
37-
// FIXME: avoid this conversion by always storing liveness data in this shape in the rest of
38-
// borrowck.
39-
pub(crate) fn record_live_regions_per_point(
40-
&mut self,
41-
num_regions: usize,
42-
points_per_live_region: &SparseIntervalMatrix<RegionVid, PointIndex>,
43-
) {
44-
let mut live_regions_per_point = SparseBitMatrix::new(num_regions);
45-
for region in points_per_live_region.rows() {
46-
for point in points_per_live_region.row(region).unwrap().iter() {
47-
live_regions_per_point.insert(point, region);
48-
}
49-
}
50-
self.live_regions = Some(live_regions_per_point);
51-
}
5232
}
5333

5434
/// Propagate loans throughout the CFG: for each statement in the MIR, create localized outlives

compiler/rustc_borrowck/src/polonius/mod.rs

+45-8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@
3232
//! - <https://smallcultfollowing.com/babysteps/blog/2023/09/22/polonius-part-1/>
3333
//! - <https://smallcultfollowing.com/babysteps/blog/2023/09/29/polonius-part-2/>
3434
//!
35+
//!
36+
//! Data flows like this:
37+
//! 1) during MIR typeck, record liveness data needed later: live region variances, as well as the
38+
//! usual NLL liveness data (just computed on more locals). That's the [PoloniusLivenessContext].
39+
//! 2) once that is done, variance data is transferred, and the NLL region liveness is converted to
40+
//! the polonius shape. That's the main [PoloniusContext].
41+
//! 3) during region inference, that data and the NLL outlives constraints are used to create the
42+
//! localized outlives constraints, as described above.
43+
//! 4) transfer these constraints back to the main borrowck procedure: it handles computing errors
44+
//! and diagnostics, debugging and MIR dumping concerns.
3545
3646
mod constraints;
3747
mod dump;
@@ -43,6 +53,7 @@ mod typeck_constraints;
4353
use std::collections::BTreeMap;
4454

4555
use rustc_index::bit_set::SparseBitMatrix;
56+
use rustc_index::interval::SparseIntervalMatrix;
4657
use rustc_middle::mir::Body;
4758
use rustc_middle::ty::{RegionVid, TyCtxt};
4859
use rustc_mir_dataflow::points::PointIndex;
@@ -57,11 +68,21 @@ use crate::{BorrowSet, RegionInferenceContext};
5768

5869
pub(crate) type LiveLoans = SparseBitMatrix<PointIndex, BorrowIndex>;
5970

60-
/// This struct holds the data needed to create the Polonius localized constraints.
71+
/// This struct holds the liveness data created during MIR typeck, and which will be used later in
72+
/// the process, to compute the polonius localized constraints.
73+
#[derive(Default)]
74+
pub(crate) struct PoloniusLivenessContext {
75+
/// The expected edge direction per live region: the kind of directed edge we'll create as
76+
/// liveness constraints depends on the variance of types with respect to each contained region.
77+
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
78+
}
79+
80+
/// This struct holds the data needed to create the Polonius localized constraints. Its data is
81+
/// transferred and converted from the [PoloniusLivenessContext] at the end of MIR typeck.
6182
pub(crate) struct PoloniusContext {
6283
/// The set of regions that are live at a given point in the CFG, used to create localized
6384
/// outlives constraints between regions that are live at connected points in the CFG.
64-
live_regions: Option<SparseBitMatrix<PointIndex, RegionVid>>,
85+
live_regions: SparseBitMatrix<PointIndex, RegionVid>,
6586

6687
/// The expected edge direction per live region: the kind of directed edge we'll create as
6788
/// liveness constraints depends on the variance of types with respect to each contained region.
@@ -83,8 +104,27 @@ enum ConstraintDirection {
83104
}
84105

85106
impl PoloniusContext {
86-
pub(crate) fn new() -> PoloniusContext {
87-
Self { live_region_variances: BTreeMap::new(), live_regions: None }
107+
/// Unlike NLLs, in polonius we traverse the cfg to look for regions live across an edge, so we
108+
/// need to transpose the "points where each region is live" matrix to a "live regions per point"
109+
/// matrix.
110+
// FIXME: avoid this conversion by always storing liveness data in this shape in the rest of
111+
// borrowck.
112+
pub(crate) fn create_from_liveness(
113+
liveness_context: PoloniusLivenessContext,
114+
num_regions: usize,
115+
points_per_live_region: &SparseIntervalMatrix<RegionVid, PointIndex>,
116+
) -> PoloniusContext {
117+
let mut live_regions_per_point = SparseBitMatrix::new(num_regions);
118+
for region in points_per_live_region.rows() {
119+
for point in points_per_live_region.row(region).unwrap().iter() {
120+
live_regions_per_point.insert(point, region);
121+
}
122+
}
123+
124+
PoloniusContext {
125+
live_regions: live_regions_per_point,
126+
live_region_variances: liveness_context.live_region_variances,
127+
}
88128
}
89129

90130
/// Computes live loans using the set of loans model for `-Zpolonius=next`.
@@ -112,13 +152,10 @@ impl PoloniusContext {
112152
&mut localized_outlives_constraints,
113153
);
114154

115-
let live_regions = self.live_regions.as_ref().expect(
116-
"live regions per-point data should have been created at the end of MIR typeck",
117-
);
118155
create_liveness_constraints(
119156
body,
120157
regioncx.liveness_constraints(),
121-
live_regions,
158+
&self.live_regions,
122159
&self.live_region_variances,
123160
regioncx.universal_regions(),
124161
&mut localized_outlives_constraints,

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

+7-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use tracing::debug;
1414

1515
use super::TypeChecker;
1616
use crate::constraints::OutlivesConstraintSet;
17-
use crate::polonius::PoloniusContext;
17+
use crate::polonius::PoloniusLivenessContext;
1818
use crate::region_infer::values::LivenessValues;
1919
use crate::universal_regions::UniversalRegions;
2020

@@ -70,7 +70,7 @@ pub(super) fn generate<'a, 'tcx>(
7070
typeck.tcx(),
7171
&mut typeck.constraints.liveness_constraints,
7272
&typeck.universal_regions,
73-
&mut typeck.polonius_context,
73+
&mut typeck.polonius_liveness,
7474
body,
7575
);
7676
}
@@ -147,11 +147,11 @@ fn record_regular_live_regions<'tcx>(
147147
tcx: TyCtxt<'tcx>,
148148
liveness_constraints: &mut LivenessValues,
149149
universal_regions: &UniversalRegions<'tcx>,
150-
polonius_context: &mut Option<PoloniusContext>,
150+
polonius_liveness: &mut Option<PoloniusLivenessContext>,
151151
body: &Body<'tcx>,
152152
) {
153153
let mut visitor =
154-
LiveVariablesVisitor { tcx, liveness_constraints, universal_regions, polonius_context };
154+
LiveVariablesVisitor { tcx, liveness_constraints, universal_regions, polonius_liveness };
155155
for (bb, data) in body.basic_blocks.iter_enumerated() {
156156
visitor.visit_basic_block_data(bb, data);
157157
}
@@ -162,7 +162,7 @@ struct LiveVariablesVisitor<'a, 'tcx> {
162162
tcx: TyCtxt<'tcx>,
163163
liveness_constraints: &'a mut LivenessValues,
164164
universal_regions: &'a UniversalRegions<'tcx>,
165-
polonius_context: &'a mut Option<PoloniusContext>,
165+
polonius_liveness: &'a mut Option<PoloniusLivenessContext>,
166166
}
167167

168168
impl<'a, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'a, 'tcx> {
@@ -214,8 +214,8 @@ impl<'a, 'tcx> LiveVariablesVisitor<'a, 'tcx> {
214214
});
215215

216216
// When using `-Zpolonius=next`, we record the variance of each live region.
217-
if let Some(polonius_context) = self.polonius_context {
218-
polonius_context.record_live_region_variance(self.tcx, self.universal_regions, value);
217+
if let Some(polonius_liveness) = self.polonius_liveness {
218+
polonius_liveness.record_live_region_variance(self.tcx, self.universal_regions, value);
219219
}
220220
}
221221
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -580,8 +580,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
580580
});
581581

582582
// When using `-Zpolonius=next`, we record the variance of each live region.
583-
if let Some(polonius_context) = typeck.polonius_context {
584-
polonius_context.record_live_region_variance(
583+
if let Some(polonius_liveness) = typeck.polonius_liveness.as_mut() {
584+
polonius_liveness.record_live_region_variance(
585585
typeck.infcx.tcx,
586586
typeck.universal_regions,
587587
value,

compiler/rustc_borrowck/src/type_check/mod.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ use crate::borrow_set::BorrowSet;
4848
use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet};
4949
use crate::diagnostics::UniverseInfo;
5050
use crate::member_constraints::MemberConstraintSet;
51-
use crate::polonius::PoloniusContext;
5251
use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable};
52+
use crate::polonius::{PoloniusContext, PoloniusLivenessContext};
5353
use crate::region_infer::TypeTest;
5454
use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices};
5555
use crate::renumber::RegionCtxt;
@@ -148,8 +148,8 @@ pub(crate) fn type_check<'a, 'tcx>(
148148

149149
debug!(?normalized_inputs_and_output);
150150

151-
let mut polonius_context = if infcx.tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
152-
Some(PoloniusContext::new())
151+
let polonius_liveness = if infcx.tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
152+
Some(PoloniusLivenessContext::default())
153153
} else {
154154
None
155155
};
@@ -168,7 +168,7 @@ pub(crate) fn type_check<'a, 'tcx>(
168168
polonius_facts,
169169
borrow_set,
170170
constraints: &mut constraints,
171-
polonius_context: &mut polonius_context,
171+
polonius_liveness,
172172
};
173173

174174
typeck.check_user_type_annotations();
@@ -185,11 +185,14 @@ pub(crate) fn type_check<'a, 'tcx>(
185185
let opaque_type_values =
186186
opaque_types::take_opaques_and_register_member_constraints(&mut typeck);
187187

188-
if let Some(polonius_context) = typeck.polonius_context.as_mut() {
189-
let num_regions = infcx.num_region_vars();
190-
let points_per_live_region = typeck.constraints.liveness_constraints.points();
191-
polonius_context.record_live_regions_per_point(num_regions, points_per_live_region);
192-
}
188+
// We're done with typeck, we can finalize the polonius liveness context for region inference.
189+
let polonius_context = typeck.polonius_liveness.take().map(|liveness_context| {
190+
PoloniusContext::create_from_liveness(
191+
liveness_context,
192+
infcx.num_region_vars(),
193+
typeck.constraints.liveness_constraints.points(),
194+
)
195+
});
193196

194197
MirTypeckResults {
195198
constraints,
@@ -564,8 +567,8 @@ struct TypeChecker<'a, 'tcx> {
564567
polonius_facts: &'a mut Option<PoloniusFacts>,
565568
borrow_set: &'a BorrowSet<'tcx>,
566569
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
567-
/// When using `-Zpolonius=next`, the helper data used to create polonius constraints.
568-
polonius_context: &'a mut Option<PoloniusContext>,
570+
/// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints.
571+
polonius_liveness: Option<PoloniusLivenessContext>,
569572
}
570573

571574
/// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions

0 commit comments

Comments
 (0)