Skip to content

Make region inference use a dirty list #47766

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/librustc_data_structures/bitvec.rs
Original file line number Diff line number Diff line change
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
77 changes: 53 additions & 24 deletions src/librustc_mir/borrow_check/nll/region_infer/mod.rs
Original file line number Diff line number Diff line change
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,65 @@ 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();

// Constraints that may need to be repropagated (initially all):
let mut dirty_list: Vec<_> = (0..self.constraints.len()).collect();

// Set to 0 for each constraint that is on the dirty list:
let mut clean_bit_vec = BitVector::new(dirty_list.len());

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

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

if made_changes {
debug!("propagate_constraints: sub={:?}", constraint.sub);
debug!("propagate_constraints: sup={:?}", constraint.sup);
changed = true;
// 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);

for &dep_idx in dependency_map.get(&constraint.sup).unwrap_or(&vec![]) {
if clean_bit_vec.remove(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