Skip to content

Commit 70f7d58

Browse files
committed
Auto merge of #47766 - spastorino:inference-dirty-list, r=nikomatsakis
Make region inference use a dirty list r? @nikomatsakis
2 parents 679f30e + 205eba8 commit 70f7d58

File tree

2 files changed

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

2 files changed

+64
-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

+53-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,65 @@ 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+
471+
// Constraints that may need to be repropagated (initially all):
472+
let mut dirty_list: Vec<_> = (0..self.constraints.len()).collect();
473+
474+
// Set to 0 for each constraint that is on the dirty list:
475+
let mut clean_bit_vec = BitVector::new(dirty_list.len());
476+
477+
debug!("propagate_constraints: --------------------");
478+
while let Some(constraint_idx) = dirty_list.pop() {
479+
clean_bit_vec.insert(constraint_idx);
480+
481+
let constraint = &self.constraints[constraint_idx];
482+
debug!("propagate_constraints: constraint={:?}", constraint);
486483

487-
if made_changes {
488-
debug!("propagate_constraints: sub={:?}", constraint.sub);
489-
debug!("propagate_constraints: sup={:?}", constraint.sup);
490-
changed = true;
484+
// Grow the value as needed to accommodate the
485+
// outlives constraint.
486+
let Ok(made_changes) = self.dfs(
487+
mir,
488+
CopyFromSourceToTarget {
489+
source_region: constraint.sub,
490+
target_region: constraint.sup,
491+
inferred_values: &mut inferred_values,
492+
constraint_point: constraint.point,
493+
constraint_span: constraint.span,
494+
},
495+
);
496+
497+
if made_changes {
498+
debug!("propagate_constraints: sub={:?}", constraint.sub);
499+
debug!("propagate_constraints: sup={:?}", constraint.sup);
500+
501+
for &dep_idx in dependency_map.get(&constraint.sup).unwrap_or(&vec![]) {
502+
if clean_bit_vec.remove(dep_idx) {
503+
dirty_list.push(dep_idx);
504+
}
491505
}
492506
}
507+
493508
debug!("\n");
494509
}
495510

496511
self.inferred_values = Some(inferred_values);
497512
}
498513

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

0 commit comments

Comments
 (0)