Skip to content

Commit 2df6952

Browse files
committed
separate out the liveness constraints from the final value
It will be useful later for diagnostics to be able to remember where things were live.
1 parent c0d326f commit 2df6952

File tree

1 file changed

+46
-35
lines changed

1 file changed

+46
-35
lines changed

src/librustc_mir/transform/nll/region_infer.rs

+46-35
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ pub struct RegionInferenceContext<'tcx> {
2626
/// from as well as its final inferred value.
2727
definitions: IndexVec<RegionIndex, RegionDefinition<'tcx>>,
2828

29+
/// The liveness constraints added to each region. For most
30+
/// regions, these start out empty and steadily grow, though for
31+
/// each free region R they start out containing the entire CFG
32+
/// and `end(R)`.
33+
liveness_constraints: IndexVec<RegionIndex, Region>,
34+
35+
/// The final inferred values of the inference variables; `None`
36+
/// until `solve` is invoked.
37+
inferred_values: Option<IndexVec<RegionIndex, Region>>,
38+
2939
/// The indices of all "free regions" in scope. These are the
3040
/// lifetime parameters (anonymous and named) declared in the
3141
/// function signature:
@@ -50,11 +60,6 @@ struct RegionDefinition<'tcx> {
5060
/// If true, this is a constant region which cannot grow larger.
5161
/// This is used for named regions as well as `'static`.
5262
constant: bool,
53-
54-
/// The current value of this inference variable. This starts out
55-
/// empty, but grows as we add constraints. The final value is
56-
/// determined when `solve()` is executed.
57-
value: Region,
5863
}
5964

6065
/// The value of an individual region variable. Region variables
@@ -122,6 +127,8 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
122127
definitions: (0..num_region_variables)
123128
.map(|_| RegionDefinition::default())
124129
.collect(),
130+
liveness_constraints: IndexVec::from_elem_n(Region::default(), num_region_variables),
131+
inferred_values: None,
125132
constraints: Vec::new(),
126133
free_regions: Vec::new(),
127134
};
@@ -168,33 +175,31 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
168175

169176
// Add all nodes in the CFG to `definition.value`.
170177
for (block, block_data) in mir.basic_blocks().iter_enumerated() {
171-
let definition = &mut self.definitions[variable];
178+
let liveness_constraint = &mut self.liveness_constraints[variable];
172179
for statement_index in 0..block_data.statements.len() + 1 {
173180
let location = Location {
174181
block,
175182
statement_index,
176183
};
177-
definition.value.add_point(location);
184+
liveness_constraint.add_point(location);
178185
}
179186
}
180187

181188
// Add `end(X)` into the set for X.
182-
self.definitions[variable].value.add_free_region(variable);
189+
self.liveness_constraints[variable].add_free_region(variable);
183190

184191
// Go through each region Y that outlives X (i.e., where
185192
// Y: X is true). Add `end(X)` into the set for `Y`.
186193
for superregion in free_region_map.regions_that_outlive(&free_region) {
187194
let superregion_index = RegionIndex::new(indices[superregion]);
188-
self.definitions[superregion_index]
189-
.value
190-
.add_free_region(variable);
195+
self.liveness_constraints[superregion_index].add_free_region(variable);
191196
}
192197

193198
debug!(
194199
"init_free_regions: region variable for `{:?}` is `{:?}` with value `{:?}`",
195200
free_region,
196201
variable,
197-
self.definitions[variable].value
202+
self.liveness_constraints[variable],
198203
);
199204
}
200205
}
@@ -208,25 +213,25 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
208213
///
209214
/// Until `solve()` executes, this value is not particularly meaningful.
210215
pub fn region_contains_point(&self, r: RegionIndex, p: Location) -> bool {
211-
self.definitions[r].value.contains_point(p)
216+
let inferred_values = self.inferred_values
217+
.as_ref()
218+
.expect("region values not yet inferred");
219+
inferred_values[r].contains_point(p)
212220
}
213221

214222
/// Returns access to the value of `r` for debugging purposes.
215223
pub(super) fn region_value(&self, r: RegionIndex) -> &fmt::Debug {
216-
&self.definitions[r].value
224+
let inferred_values = self.inferred_values
225+
.as_ref()
226+
.expect("region values not yet inferred");
227+
&inferred_values[r]
217228
}
218229

219230
/// Indicates that the region variable `v` is live at the point `point`.
220231
pub(super) fn add_live_point(&mut self, v: RegionIndex, point: Location) {
221232
debug!("add_live_point({:?}, {:?})", v, point);
222-
let definition = &mut self.definitions[v];
223-
if !definition.constant {
224-
definition.value.add_point(point);
225-
} else {
226-
// Constants are used for free regions, which already
227-
// contain all the points in the control-flow graph.
228-
assert!(definition.value.contains_point(point));
229-
}
233+
assert!(self.inferred_values.is_none(), "values already inferred");
234+
self.liveness_constraints[v].add_point(point);
230235
}
231236

232237
/// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
@@ -238,6 +243,7 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
238243
point: Location,
239244
) {
240245
debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point);
246+
assert!(self.inferred_values.is_none(), "values already inferred");
241247
self.constraints.push(Constraint {
242248
span,
243249
sup,
@@ -248,6 +254,7 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
248254

249255
/// Perform region inference.
250256
pub(super) fn solve(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>) {
257+
assert!(self.inferred_values.is_none(), "values already inferred");
251258
let errors = self.propagate_constraints(mir);
252259

253260
// worst error msg ever
@@ -267,47 +274,49 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
267274
/// for each region variable until all the constraints are
268275
/// satisfied. Note that some values may grow **too** large to be
269276
/// feasible, but we check this later.
270-
fn propagate_constraints(
271-
&mut self,
272-
mir: &Mir<'tcx>,
273-
) -> Vec<(RegionIndex, Span, RegionIndex)> {
277+
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) -> Vec<(RegionIndex, Span, RegionIndex)> {
274278
let mut changed = true;
275279
let mut dfs = Dfs::new(mir);
276280
let mut error_regions = FxHashSet();
277281
let mut errors = vec![];
282+
283+
// The initial values for each region are derived from the liveness
284+
// constraints we have accumulated.
285+
let mut inferred_values = self.liveness_constraints.clone();
286+
278287
while changed {
279288
changed = false;
280289
for constraint in &self.constraints {
281290
debug!("constraint: {:?}", constraint);
282-
let sub = &self.definitions[constraint.sub].value.clone();
283-
let sup_def = &mut self.definitions[constraint.sup];
291+
let sub = &inferred_values[constraint.sub].clone();
292+
let sup_value = &mut inferred_values[constraint.sup];
284293

285294
debug!(" sub (before): {:?}", sub);
286-
debug!(" sup (before): {:?}", sup_def.value);
295+
debug!(" sup (before): {:?}", sup_value);
287296

288-
if !sup_def.constant {
297+
if !self.definitions[constraint.sup].constant {
289298
// If this is not a constant, then grow the value as needed to
290299
// accommodate the outlives constraint.
291300

292-
if dfs.copy(sub, &mut sup_def.value, constraint.point) {
301+
if dfs.copy(sub, sup_value, constraint.point) {
293302
changed = true;
294303
}
295304

296-
debug!(" sup (after) : {:?}", sup_def.value);
305+
debug!(" sup (after) : {:?}", sup_value);
297306
debug!(" changed : {:?}", changed);
298307
} else {
299308
// If this is a constant, check whether it *would
300309
// have* to grow in order for the constraint to be
301310
// satisfied. If so, create an error.
302311

303-
let mut sup_value = sup_def.value.clone();
304-
if dfs.copy(sub, &mut sup_value, constraint.point) {
312+
let mut sup_value = &mut sup_value.clone();
313+
if dfs.copy(sub, sup_value, constraint.point) {
305314
// Constant values start out with the entire
306315
// CFG, so it must be some new free region
307316
// that was added. Find one.
308317
let &new_region = sup_value
309318
.free_regions
310-
.difference(&sup_def.value.free_regions)
319+
.difference(&sup_value.free_regions)
311320
.next()
312321
.unwrap();
313322
debug!(" new_region : {:?}", new_region);
@@ -319,6 +328,8 @@ impl<'a, 'gcx, 'tcx> RegionInferenceContext<'tcx> {
319328
}
320329
debug!("\n");
321330
}
331+
332+
self.inferred_values = Some(inferred_values);
322333
errors
323334
}
324335
}

0 commit comments

Comments
 (0)