about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSantiago Pastorino <spastorino@gmail.com>2018-01-26 02:14:54 -0300
committerSantiago Pastorino <spastorino@gmail.com>2018-01-26 21:56:49 -0300
commitda545cee6057eddc0cf64767870a1cdc087ade1f (patch)
tree669afc706bd24bf470d5b2ca412c2357e60452bd
parenta97cd17f5d71fb4ec362f4fbd79373a6e7ed7b82 (diff)
downloadrust-da545cee6057eddc0cf64767870a1cdc087ade1f.tar.gz
rust-da545cee6057eddc0cf64767870a1cdc087ade1f.zip
Make region inference use a dirty list
Fixes #47602
-rw-r--r--src/librustc_data_structures/bitvec.rs11
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs72
2 files changed, 59 insertions, 24 deletions
diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs
index 94edaa746f9..80cdb0e4417 100644
--- a/src/librustc_data_structures/bitvec.rs
+++ b/src/librustc_data_structures/bitvec.rs
@@ -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());
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 9a2f98d4622..f316a8b480d 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -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;
@@ -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;
@@ -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();
@@ -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: