Skip to content

Commit da545ce

Browse files
committed
Make region inference use a dirty list
Fixes #47602
1 parent a97cd17 commit da545ce

File tree

2 files changed

+59
-24
lines changed
  • src
    • librustc_data_structures
    • librustc_mir/borrow_check/nll/region_infer

2 files changed

+59
-24
lines changed

src/librustc_data_structures/bitvec.rs

+11
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ impl BitVector {
5151
new_value != value
5252
}
5353

54+
/// Returns true if the bit has changed.
55+
#[inline]
56+
pub fn remove(&mut self, bit: usize) -> bool {
57+
let (word, mask) = word_mask(bit);
58+
let data = &mut self.data[word];
59+
let value = *data;
60+
let new_value = value & !mask;
61+
*data = new_value;
62+
new_value != value
63+
}
64+
5465
#[inline]
5566
pub fn insert_all(&mut self, all: &BitVector) -> bool {
5667
assert!(self.data.len() == all.data.len());

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

+48-24
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use std::collections::HashMap;
12+
1113
use super::universal_regions::UniversalRegions;
1214
use rustc::hir::def_id::DefId;
1315
use rustc::infer::InferCtxt;
@@ -22,6 +24,7 @@ use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegi
2224
use rustc::traits::ObligationCause;
2325
use rustc::ty::{self, RegionVid, Ty, TypeFoldable};
2426
use rustc::util::common::ErrorReported;
27+
use rustc_data_structures::bitvec::BitVector;
2528
use rustc_data_structures::indexed_vec::IndexVec;
2629
use rustc_errors::DiagnosticBuilder;
2730
use std::fmt;
@@ -452,8 +455,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
452455
/// satisfied. Note that some values may grow **too** large to be
453456
/// feasible, but we check this later.
454457
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
455-
let mut changed = true;
456-
457458
debug!("propagate_constraints()");
458459
debug!("propagate_constraints: constraints={:#?}", {
459460
let mut constraints: Vec<_> = self.constraints.iter().collect();
@@ -465,37 +466,60 @@ impl<'tcx> RegionInferenceContext<'tcx> {
465466
// constraints we have accumulated.
466467
let mut inferred_values = self.liveness_constraints.clone();
467468

468-
while changed {
469-
changed = false;
470-
debug!("propagate_constraints: --------------------");
471-
for constraint in &self.constraints {
472-
debug!("propagate_constraints: constraint={:?}", constraint);
473-
474-
// Grow the value as needed to accommodate the
475-
// outlives constraint.
476-
let Ok(made_changes) = self.dfs(
477-
mir,
478-
CopyFromSourceToTarget {
479-
source_region: constraint.sub,
480-
target_region: constraint.sup,
481-
inferred_values: &mut inferred_values,
482-
constraint_point: constraint.point,
483-
constraint_span: constraint.span,
484-
},
485-
);
469+
let dependency_map = self.build_dependency_map();
470+
let mut dirty_list: Vec<_> = (0..self.constraints.len()).collect();
471+
let mut dirty_bit_vec = BitVector::new(dirty_list.len());
472+
473+
debug!("propagate_constraints: --------------------");
474+
while let Some(constraint_idx) = dirty_list.pop() {
475+
dirty_bit_vec.remove(constraint_idx);
476+
477+
let constraint = &self.constraints[constraint_idx];
478+
debug!("propagate_constraints: constraint={:?}", constraint);
479+
480+
// Grow the value as needed to accommodate the
481+
// outlives constraint.
482+
let Ok(made_changes) = self.dfs(
483+
mir,
484+
CopyFromSourceToTarget {
485+
source_region: constraint.sub,
486+
target_region: constraint.sup,
487+
inferred_values: &mut inferred_values,
488+
constraint_point: constraint.point,
489+
constraint_span: constraint.span,
490+
},
491+
);
492+
493+
if made_changes {
494+
debug!("propagate_constraints: sub={:?}", constraint.sub);
495+
debug!("propagate_constraints: sup={:?}", constraint.sup);
486496

487-
if made_changes {
488-
debug!("propagate_constraints: sub={:?}", constraint.sub);
489-
debug!("propagate_constraints: sup={:?}", constraint.sup);
490-
changed = true;
497+
for &dep_idx in dependency_map.get(&constraint.sup).unwrap_or(&vec![]) {
498+
if dirty_bit_vec.insert(dep_idx) {
499+
dirty_list.push(dep_idx);
500+
}
491501
}
492502
}
503+
493504
debug!("\n");
494505
}
495506

496507
self.inferred_values = Some(inferred_values);
497508
}
498509

510+
/// Builds up a map from each region variable X to a vector with the indices of constraints that
511+
/// need to be re-evaluated when X changes. These are constraints like Y: X @ P -- so if X
512+
/// changed, we may need to grow Y.
513+
fn build_dependency_map(&self) -> HashMap<RegionVid, Vec<usize>> {
514+
let mut map = HashMap::new();
515+
516+
for (idx, constraint) in self.constraints.iter().enumerate() {
517+
map.entry(constraint.sub).or_insert(Vec::new()).push(idx);
518+
}
519+
520+
map
521+
}
522+
499523
/// Once regions have been propagated, this method is used to see
500524
/// whether the "type tests" produced by typeck were satisfied;
501525
/// type tests encode type-outlives relationships like `T:

0 commit comments

Comments
 (0)