32
32
//! - <https://smallcultfollowing.com/babysteps/blog/2023/09/22/polonius-part-1/>
33
33
//! - <https://smallcultfollowing.com/babysteps/blog/2023/09/29/polonius-part-2/>
34
34
//!
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.
35
45
36
46
mod constraints;
37
47
mod dump;
@@ -42,8 +52,10 @@ mod typeck_constraints;
42
52
43
53
use std:: collections:: BTreeMap ;
44
54
55
+ use rustc_data_structures:: fx:: FxHashSet ;
45
56
use rustc_index:: bit_set:: SparseBitMatrix ;
46
- use rustc_middle:: mir:: Body ;
57
+ use rustc_index:: interval:: SparseIntervalMatrix ;
58
+ use rustc_middle:: mir:: { Body , Local } ;
47
59
use rustc_middle:: ty:: { RegionVid , TyCtxt } ;
48
60
use rustc_mir_dataflow:: points:: PointIndex ;
49
61
@@ -57,15 +69,40 @@ use crate::{BorrowSet, RegionInferenceContext};
57
69
58
70
pub ( crate ) type LiveLoans = SparseBitMatrix < PointIndex , BorrowIndex > ;
59
71
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.
61
89
pub ( crate ) struct PoloniusContext {
90
+ /// The liveness data we recorded during MIR typeck.
91
+ liveness_context : PoloniusLivenessContext ,
92
+
62
93
/// The set of regions that are live at a given point in the CFG, used to create localized
63
94
/// 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
+ }
65
97
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 > ,
69
106
}
70
107
71
108
/// The direction a constraint can flow into. Used to create liveness constraints according to
@@ -83,8 +120,24 @@ enum ConstraintDirection {
83
120
}
84
121
85
122
impl 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 }
88
141
}
89
142
90
143
/// Computes live loans using the set of loans model for `-Zpolonius=next`.
@@ -95,13 +148,18 @@ impl PoloniusContext {
95
148
///
96
149
/// Then, this graph is traversed, and combined with kills, reachability is recorded as loan
97
150
/// 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.
98
153
pub ( crate ) fn compute_loan_liveness < ' tcx > (
99
- & self ,
154
+ self ,
100
155
tcx : TyCtxt < ' tcx > ,
101
156
regioncx : & mut RegionInferenceContext < ' tcx > ,
102
157
body : & Body < ' tcx > ,
103
158
borrow_set : & BorrowSet < ' tcx > ,
104
- ) -> LocalizedOutlivesConstraintSet {
159
+ ) -> PoloniusDiagnosticsContext {
160
+ let PoloniusLivenessContext { live_region_variances, boring_nll_locals } =
161
+ self . liveness_context ;
162
+
105
163
let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet :: default ( ) ;
106
164
convert_typeck_constraints (
107
165
tcx,
@@ -112,14 +170,11 @@ impl PoloniusContext {
112
170
& mut localized_outlives_constraints,
113
171
) ;
114
172
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
- ) ;
118
173
create_liveness_constraints (
119
174
body,
120
175
regioncx. liveness_constraints ( ) ,
121
- live_regions,
122
- & self . live_region_variances ,
176
+ & self . live_regions ,
177
+ & live_region_variances,
123
178
regioncx. universal_regions ( ) ,
124
179
& mut localized_outlives_constraints,
125
180
) ;
@@ -136,6 +191,6 @@ impl PoloniusContext {
136
191
) ;
137
192
regioncx. record_live_loans ( live_loans) ;
138
193
139
- localized_outlives_constraints
194
+ PoloniusDiagnosticsContext { localized_outlives_constraints, boring_nll_locals }
140
195
}
141
196
}
0 commit comments