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. That's the [PoloniusDiagnosticsContext].
43+ //! 4) transfer this back to the main borrowck procedure: it handles computing errors and
44+ //! diagnostics, debugging and MIR dumping concerns.
3545
3646mod constraints;
3747mod dump;
@@ -42,8 +52,10 @@ mod typeck_constraints;
4252
4353use std:: collections:: BTreeMap ;
4454
55+ use rustc_data_structures:: fx:: FxHashSet ;
4556use rustc_index:: bit_set:: SparseBitMatrix ;
46- use rustc_middle:: mir:: Body ;
57+ use rustc_index:: interval:: SparseIntervalMatrix ;
58+ use rustc_middle:: mir:: { Body , Local } ;
4759use rustc_middle:: ty:: { RegionVid , TyCtxt } ;
4860use rustc_mir_dataflow:: points:: PointIndex ;
4961
@@ -57,15 +69,40 @@ use crate::{BorrowSet, RegionInferenceContext};
5769
5870pub ( crate ) type LiveLoans = SparseBitMatrix < PointIndex , BorrowIndex > ;
5971
60- /// This struct holds the data needed to create the Polonius localized constraints.
72+ /// This struct holds the liveness data created during MIR typeck, and which will be used later in
73+ /// the process, to compute the polonius localized constraints.
74+ #[ derive( Default ) ]
75+ pub ( crate ) struct PoloniusLivenessContext {
76+ /// The expected edge direction per live region: the kind of directed edge we'll create as
77+ /// liveness constraints depends on the variance of types with respect to each contained region.
78+ live_region_variances : BTreeMap < RegionVid , ConstraintDirection > ,
79+
80+ /// The regions that outlive free regions are used to distinguish relevant live locals from
81+ /// boring locals. A boring local is one whose type contains only such regions. Polonius
82+ /// currently has more boring locals than NLLs so we record the latter to use in errors and
83+ /// diagnostics, to focus on the locals we consider relevant and match NLL diagnostics.
84+ pub ( crate ) boring_nll_locals : FxHashSet < Local > ,
85+ }
86+
87+ /// This struct holds the data needed to create the Polonius localized constraints. Its data is
88+ /// transferred and converted from the [PoloniusLivenessContext] at the end of MIR typeck.
6189pub ( crate ) struct PoloniusContext {
90+ /// The liveness data we recorded during MIR typeck.
91+ liveness_context : PoloniusLivenessContext ,
92+
6293 /// The set of regions that are live at a given point in the CFG, used to create localized
6394 /// outlives constraints between regions that are live at connected points in the CFG.
64- live_regions : Option < SparseBitMatrix < PointIndex , RegionVid > > ,
95+ live_regions : SparseBitMatrix < PointIndex , RegionVid > ,
96+ }
6597
66- /// The expected edge direction per live region: the kind of directed edge we'll create as
67- /// liveness constraints depends on the variance of types with respect to each contained region.
68- live_region_variances : BTreeMap < RegionVid , ConstraintDirection > ,
98+ /// This struct holds the data needed by the borrowck error computation and diagnostics. Its data is
99+ /// computed from the [PoloniusContext] when computing NLL regions.
100+ pub ( crate ) struct PoloniusDiagnosticsContext {
101+ /// The localized outlives constraints that were computed in the main analysis.
102+ localized_outlives_constraints : LocalizedOutlivesConstraintSet ,
103+
104+ /// The liveness data computed during MIR typeck: [PoloniusLivenessContext::boring_nll_locals].
105+ pub ( crate ) boring_nll_locals : FxHashSet < Local > ,
69106}
70107
71108/// The direction a constraint can flow into. Used to create liveness constraints according to
@@ -83,8 +120,24 @@ enum ConstraintDirection {
83120}
84121
85122impl PoloniusContext {
86- pub ( crate ) fn new ( ) -> PoloniusContext {
87- Self { live_region_variances : BTreeMap :: new ( ) , live_regions : None }
123+ /// Unlike NLLs, in polonius we traverse the cfg to look for regions live across an edge, so we
124+ /// need to transpose the "points where each region is live" matrix to a "live regions per point"
125+ /// matrix.
126+ // FIXME: avoid this conversion by always storing liveness data in this shape in the rest of
127+ // borrowck.
128+ pub ( crate ) fn create_from_liveness (
129+ liveness_context : PoloniusLivenessContext ,
130+ num_regions : usize ,
131+ points_per_live_region : & SparseIntervalMatrix < RegionVid , PointIndex > ,
132+ ) -> PoloniusContext {
133+ let mut live_regions_per_point = SparseBitMatrix :: new ( num_regions) ;
134+ for region in points_per_live_region. rows ( ) {
135+ for point in points_per_live_region. row ( region) . unwrap ( ) . iter ( ) {
136+ live_regions_per_point. insert ( point, region) ;
137+ }
138+ }
139+
140+ PoloniusContext { live_regions : live_regions_per_point, liveness_context }
88141 }
89142
90143 /// Computes live loans using the set of loans model for `-Zpolonius=next`.
@@ -95,13 +148,18 @@ impl PoloniusContext {
95148 ///
96149 /// Then, this graph is traversed, and combined with kills, reachability is recorded as loan
97150 /// liveness, to be used by the loan scope and active loans computations.
151+ ///
152+ /// The constraint data will be used to compute errors and diagnostics.
98153 pub ( crate ) fn compute_loan_liveness < ' tcx > (
99- & self ,
154+ self ,
100155 tcx : TyCtxt < ' tcx > ,
101156 regioncx : & mut RegionInferenceContext < ' tcx > ,
102157 body : & Body < ' tcx > ,
103158 borrow_set : & BorrowSet < ' tcx > ,
104- ) -> LocalizedOutlivesConstraintSet {
159+ ) -> PoloniusDiagnosticsContext {
160+ let PoloniusLivenessContext { live_region_variances, boring_nll_locals } =
161+ self . liveness_context ;
162+
105163 let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet :: default ( ) ;
106164 convert_typeck_constraints (
107165 tcx,
@@ -112,14 +170,11 @@ impl PoloniusContext {
112170 & mut localized_outlives_constraints,
113171 ) ;
114172
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- ) ;
118173 create_liveness_constraints (
119174 body,
120175 regioncx. liveness_constraints ( ) ,
121- live_regions,
122- & self . live_region_variances ,
176+ & self . live_regions ,
177+ & live_region_variances,
123178 regioncx. universal_regions ( ) ,
124179 & mut localized_outlives_constraints,
125180 ) ;
@@ -136,6 +191,6 @@ impl PoloniusContext {
136191 ) ;
137192 regioncx. record_live_loans ( live_loans) ;
138193
139- localized_outlives_constraints
194+ PoloniusDiagnosticsContext { localized_outlives_constraints, boring_nll_locals }
140195 }
141196}
0 commit comments