Skip to content

Commit

Permalink
Make region inference use a dirty list
Browse files Browse the repository at this point in the history
Fixes #47602
  • Loading branch information
spastorino committed Jan 27, 2018
1 parent a97cd17 commit da545ce
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 24 deletions.
11 changes: 11 additions & 0 deletions src/librustc_data_structures/bitvec.rs
Expand Up @@ -51,6 +51,17 @@ impl BitVector {
new_value != value
}

/// Returns true if the bit has changed.
#[inline]
pub fn remove(&mut self, bit: usize) -> bool {
let (word, mask) = word_mask(bit);
let data = &mut self.data[word];
let value = *data;
let new_value = value & !mask;
*data = new_value;
new_value != value
}

#[inline]
pub fn insert_all(&mut self, all: &BitVector) -> bool {
assert!(self.data.len() == all.data.len());
Expand Down
72 changes: 48 additions & 24 deletions src/librustc_mir/borrow_check/nll/region_infer/mod.rs
Expand Up @@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::HashMap;

use super::universal_regions::UniversalRegions;
use rustc::hir::def_id::DefId;
use rustc::infer::InferCtxt;
Expand All @@ -22,6 +24,7 @@ use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegi
use rustc::traits::ObligationCause;
use rustc::ty::{self, RegionVid, Ty, TypeFoldable};
use rustc::util::common::ErrorReported;
use rustc_data_structures::bitvec::BitVector;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_errors::DiagnosticBuilder;
use std::fmt;
Expand Down Expand Up @@ -452,8 +455,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// satisfied. Note that some values may grow **too** large to be
/// feasible, but we check this later.
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
let mut changed = true;

debug!("propagate_constraints()");
debug!("propagate_constraints: constraints={:#?}", {
let mut constraints: Vec<_> = self.constraints.iter().collect();
Expand All @@ -465,37 +466,60 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// constraints we have accumulated.
let mut inferred_values = self.liveness_constraints.clone();

while changed {
changed = false;
debug!("propagate_constraints: --------------------");
for constraint in &self.constraints {
debug!("propagate_constraints: constraint={:?}", constraint);

// Grow the value as needed to accommodate the
// outlives constraint.
let Ok(made_changes) = self.dfs(
mir,
CopyFromSourceToTarget {
source_region: constraint.sub,
target_region: constraint.sup,
inferred_values: &mut inferred_values,
constraint_point: constraint.point,
constraint_span: constraint.span,
},
);
let dependency_map = self.build_dependency_map();
let mut dirty_list: Vec<_> = (0..self.constraints.len()).collect();
let mut dirty_bit_vec = BitVector::new(dirty_list.len());

debug!("propagate_constraints: --------------------");
while let Some(constraint_idx) = dirty_list.pop() {
dirty_bit_vec.remove(constraint_idx);

let constraint = &self.constraints[constraint_idx];
debug!("propagate_constraints: constraint={:?}", constraint);

// Grow the value as needed to accommodate the
// outlives constraint.
let Ok(made_changes) = self.dfs(
mir,
CopyFromSourceToTarget {
source_region: constraint.sub,
target_region: constraint.sup,
inferred_values: &mut inferred_values,
constraint_point: constraint.point,
constraint_span: constraint.span,
},
);

if made_changes {
debug!("propagate_constraints: sub={:?}", constraint.sub);
debug!("propagate_constraints: sup={:?}", constraint.sup);

if made_changes {
debug!("propagate_constraints: sub={:?}", constraint.sub);
debug!("propagate_constraints: sup={:?}", constraint.sup);
changed = true;
for &dep_idx in dependency_map.get(&constraint.sup).unwrap_or(&vec![]) {
if dirty_bit_vec.insert(dep_idx) {
dirty_list.push(dep_idx);
}
}
}

debug!("\n");
}

self.inferred_values = Some(inferred_values);
}

/// Builds up a map from each region variable X to a vector with the indices of constraints that
/// need to be re-evaluated when X changes. These are constraints like Y: X @ P -- so if X
/// changed, we may need to grow Y.
fn build_dependency_map(&self) -> HashMap<RegionVid, Vec<usize>> {
let mut map = HashMap::new();

for (idx, constraint) in self.constraints.iter().enumerate() {
map.entry(constraint.sub).or_insert(Vec::new()).push(idx);
}

map
}

/// Once regions have been propagated, this method is used to see
/// whether the "type tests" produced by typeck were satisfied;
/// type tests encode type-outlives relationships like `T:
Expand Down

0 comments on commit da545ce

Please sign in to comment.