@@ -12,7 +12,6 @@ use datafrog::Relation;
12
12
use rustc_hash:: { FxHashMap , FxHashSet } ;
13
13
use std:: borrow:: Cow ;
14
14
use std:: collections:: { BTreeMap , BTreeSet } ;
15
- use std:: mem;
16
15
17
16
use crate :: facts:: { AllFacts , Atom , FactTypes } ;
18
17
@@ -94,61 +93,102 @@ pub struct Output<T: FactTypes> {
94
93
pub var_maybe_initialized_on_exit : FxHashMap < T :: Point , Vec < T :: Variable > > ,
95
94
}
96
95
97
- struct Context < T : FactTypes > {
98
- all_facts : AllFacts < T > ,
96
+ /// Subset of `AllFacts` dedicated to initialization
97
+ struct InitializationContext < T : FactTypes > {
98
+ child : Vec < ( T :: Path , T :: Path ) > ,
99
+ path_belongs_to_var : Vec < ( T :: Path , T :: Variable ) > ,
100
+ initialized_at : Vec < ( T :: Path , T :: Point ) > ,
101
+ moved_out_at : Vec < ( T :: Path , T :: Point ) > ,
102
+ path_accessed_at : Vec < ( T :: Path , T :: Point ) > ,
103
+ }
104
+
105
+ /// Subset of `AllFacts` dedicated to liveness
106
+ struct LivenessContext < T : FactTypes > {
107
+ var_used : Vec < ( T :: Variable , T :: Point ) > ,
108
+ var_defined : Vec < ( T :: Variable , T :: Point ) > ,
109
+ var_drop_used : Vec < ( T :: Variable , T :: Point ) > ,
110
+ var_uses_region : Vec < ( T :: Variable , T :: Origin ) > ,
111
+ var_drops_region : Vec < ( T :: Variable , T :: Origin ) > ,
112
+ }
99
113
100
- // `Relation`s used by multiple variants as static inputs
114
+ /// Subset of `AllFacts` dedicated to borrow checking, and data ready to use by the variants
115
+ struct Context < ' ctx , T : FactTypes > {
116
+ // `Relation`s used as static inputs, by all variants
101
117
region_live_at : Relation < ( T :: Origin , T :: Point ) > ,
102
118
invalidates : Relation < ( T :: Loan , T :: Point ) > ,
103
- cfg_edge : Relation < ( T :: Point , T :: Point ) > ,
119
+
120
+ // static inputs used via `Variable`s, by all variants
121
+ outlives : & ' ctx Vec < ( T :: Origin , T :: Origin , T :: Point ) > ,
122
+ borrow_region : & ' ctx Vec < ( T :: Origin , T :: Loan , T :: Point ) > ,
123
+
124
+ // static inputs used by variants other than `LocationInsensitive`
104
125
killed : Relation < ( T :: Loan , T :: Point ) > ,
105
126
127
+ // while this static input is unused by `LocationInsensitive`, it's depended on by initialization
128
+ // and liveness, so already computed by the time we get to borrowcking.
129
+ cfg_edge : Relation < ( T :: Point , T :: Point ) > ,
130
+
106
131
// Partial results possibly used by other variants as input
107
- potential_errors : FxHashSet < T :: Loan > ,
132
+ potential_errors : Option < FxHashSet < T :: Loan > > ,
108
133
}
109
134
110
135
impl < T : FactTypes > Output < T > {
136
+ /// All variants require the same initial preparations, done in multiple
137
+ /// successive steps:
138
+ /// - compute initialization data
139
+ /// - compute liveness
140
+ /// - prepare static inputs as shared `Relation`s
141
+ /// - in cases where `LocationInsensitive` variant is ran as a filtering pre-pass,
142
+ /// partial results can also be stored in the context, so that the following
143
+ /// variant can use it to prune its own input data
111
144
pub fn compute ( all_facts : & AllFacts < T > , algorithm : Algorithm , dump_enabled : bool ) -> Self {
112
- // All variants require the same initial preparations, done in multiple
113
- // successive steps:
114
- // - compute initialization data
115
- // - compute liveness
116
- // - prepare static inputs as shared `Relation`s
117
- // - in cases where `LocationInsensitive` variant is ran as a filtering pre-pass,
118
- // partial results can also be stored in the context, so that the following
119
- // variant can use it to prune its own input data
120
-
121
- // TODO: remove the need for this clone in concert here and in rustc
122
- let mut all_facts = all_facts. clone ( ) ;
123
-
124
145
let mut result = Output :: new ( dump_enabled) ;
125
146
126
- let cfg_edge = mem:: replace ( & mut all_facts. cfg_edge , Vec :: new ( ) ) . into ( ) ;
147
+ // TODO: remove all the cloning thereafter, but that needs to be done in concert with rustc
148
+
149
+ let cfg_edge = all_facts. cfg_edge . clone ( ) . into ( ) ;
150
+
151
+ // 1) Initialization
152
+ let initialization_ctx = InitializationContext {
153
+ child : all_facts. child . clone ( ) ,
154
+ path_belongs_to_var : all_facts. path_belongs_to_var . clone ( ) ,
155
+ initialized_at : all_facts. initialized_at . clone ( ) ,
156
+ moved_out_at : all_facts. moved_out_at . clone ( ) ,
157
+ path_accessed_at : all_facts. path_accessed_at . clone ( ) ,
158
+ } ;
127
159
128
- // Initialization
129
160
let var_maybe_initialized_on_exit = initialization:: init_var_maybe_initialized_on_exit (
130
- mem:: replace ( & mut all_facts. child , Vec :: new ( ) ) ,
131
- mem:: replace ( & mut all_facts. path_belongs_to_var , Vec :: new ( ) ) ,
132
- mem:: replace ( & mut all_facts. initialized_at , Vec :: new ( ) ) ,
133
- mem:: replace ( & mut all_facts. moved_out_at , Vec :: new ( ) ) ,
134
- mem:: replace ( & mut all_facts. path_accessed_at , Vec :: new ( ) ) ,
161
+ initialization_ctx,
135
162
& cfg_edge,
136
163
& mut result,
137
164
) ;
138
165
139
- // Liveness
140
- let region_live_at = liveness:: init_region_live_at (
141
- mem:: replace ( & mut all_facts. var_used , Vec :: new ( ) ) ,
142
- mem:: replace ( & mut all_facts. var_drop_used , Vec :: new ( ) ) ,
143
- mem:: replace ( & mut all_facts. var_defined , Vec :: new ( ) ) ,
144
- mem:: replace ( & mut all_facts. var_uses_region , Vec :: new ( ) ) ,
145
- mem:: replace ( & mut all_facts. var_drops_region , Vec :: new ( ) ) ,
146
- var_maybe_initialized_on_exit,
166
+ // 2) Liveness
167
+ let universal_regions = all_facts. universal_region . clone ( ) ;
168
+
169
+ let liveness_ctx = LivenessContext {
170
+ var_used : all_facts. var_used . clone ( ) ,
171
+ var_defined : all_facts. var_defined . clone ( ) ,
172
+ var_drop_used : all_facts. var_drop_used . clone ( ) ,
173
+ var_uses_region : all_facts. var_uses_region . clone ( ) ,
174
+ var_drops_region : all_facts. var_drops_region . clone ( ) ,
175
+ } ;
176
+
177
+ let mut region_live_at = liveness:: compute_live_regions (
178
+ liveness_ctx,
147
179
& cfg_edge,
148
- mem :: replace ( & mut all_facts . universal_region , Vec :: new ( ) ) ,
180
+ var_maybe_initialized_on_exit ,
149
181
& mut result,
150
182
) ;
151
183
184
+ liveness:: make_universal_regions_live :: < T > (
185
+ & mut region_live_at,
186
+ & cfg_edge,
187
+ universal_regions,
188
+ ) ;
189
+
190
+ // 3) Borrow checking
191
+
152
192
// Prepare data as datafrog relations, ready to join.
153
193
//
154
194
// Note: if rustc and polonius had more interaction, we could also delay or avoid
@@ -160,26 +200,28 @@ impl<T: FactTypes> Output<T> {
160
200
// be recorded in separate MIR walks, we might also avoid generating those facts.
161
201
162
202
let region_live_at = region_live_at. into ( ) ;
163
- let killed = mem:: replace ( & mut all_facts. killed , Vec :: new ( ) ) . into ( ) ;
164
203
165
- // TODO: flip the order of this relation's arguments in rustc
166
- // from `invalidates(loan, point )` to `invalidates(point, loan )`.
204
+ // TODO: also flip the order of this relation's arguments in rustc
205
+ // from `invalidates(point, loan )` to `invalidates(loan, point )`.
167
206
// to avoid this allocation.
168
207
let invalidates = Relation :: from_iter (
169
208
all_facts
170
209
. invalidates
171
210
. iter ( )
172
- . map ( |& ( loan , point ) | ( point , loan ) ) ,
211
+ . map ( |& ( point , loan ) | ( loan , point ) ) ,
173
212
) ;
174
213
214
+ let killed = all_facts. killed . clone ( ) . into ( ) ;
215
+
175
216
// Ask the variants to compute errors in their own way
176
217
let mut ctx = Context {
177
- all_facts,
178
218
region_live_at,
179
- cfg_edge,
180
219
invalidates,
220
+ cfg_edge,
221
+ outlives : & all_facts. outlives ,
222
+ borrow_region : & all_facts. borrow_region ,
181
223
killed,
182
- potential_errors : FxHashSet :: default ( ) ,
224
+ potential_errors : None ,
183
225
} ;
184
226
185
227
let errors = match algorithm {
@@ -196,8 +238,8 @@ impl<T: FactTypes> Output<T> {
196
238
} else {
197
239
// Record these potential errors as they can be used to limit the next
198
240
// variant's work to only these loans.
199
- ctx. potential_errors
200
- . extend ( potential_errors. iter ( ) . map ( |& ( loan, _) | loan) ) ;
241
+ ctx. potential_errors =
242
+ Some ( potential_errors. iter ( ) . map ( |& ( loan, _) | loan) . collect ( ) ) ;
201
243
202
244
datafrog_opt:: compute ( & ctx, & mut result)
203
245
}
0 commit comments