about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-07-17 11:31:53 +0000
committerbors <bors@rust-lang.org>2018-07-17 11:31:53 +0000
commit025e04e1bc51807d3e9d733f4af57d2624b9080d (patch)
treef787e640643c34f057c5a87a3d5c1d1dde4e1647
parent2ddc0cbd56ff1695f24b4f5daa14642bd21e4af0 (diff)
parent8b94d1605be5a73a7e0362d26bdabfeca1250719 (diff)
Auto merge of #52190 - davidtwco:issue-52028, r=nikomatsakis
html5ever in the rustc-perf repository is memory-intensive

Part of #52028. Rebased atop of #51987.

r? @nikomatsakis
-rw-r--r--src/librustc_data_structures/bitvec.rs56
-rw-r--r--src/librustc_data_structures/indexed_vec.rs18
-rw-r--r--src/librustc_data_structures/lib.rs1
-rw-r--r--src/librustc_mir/borrow_check/nll/constraint_generation.rs40
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs9
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs27
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/values.rs31
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/liveness.rs13
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs100
9 files changed, 174 insertions, 121 deletions
diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs
index a22dd1fecec..617153d5765 100644
--- a/src/librustc_data_structures/bitvec.rs
+++ b/src/librustc_data_structures/bitvec.rs
@@ -281,10 +281,10 @@ where
 }
 
 impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
-    /// Create a new `rows x columns` matrix, initially empty.
-    pub fn new(rows: R, _columns: C) -> SparseBitMatrix<R, C> {
-        SparseBitMatrix {
-            vector: IndexVec::from_elem_n(SparseBitSet::new(), rows.index()),
+    /// Create a new empty sparse bit matrix with no rows or columns.
+    pub fn new() -> Self {
+        Self {
+            vector: IndexVec::new(),
         }
     }
 
@@ -293,6 +293,14 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
     ///
     /// Returns true if this changed the matrix, and false otherwise.
     pub fn add(&mut self, row: R, column: C) -> bool {
+        debug!(
+            "add(row={:?}, column={:?}, current_len={})",
+            row,
+            column,
+            self.vector.len()
+        );
+        self.vector
+            .ensure_contains_elem(row, || SparseBitSet::new());
         self.vector[row].insert(column)
     }
 
@@ -301,7 +309,7 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
     /// if the matrix represents (transitive) reachability, can
     /// `row` reach `column`?
     pub fn contains(&self, row: R, column: C) -> bool {
-        self.vector[row].contains(column)
+        self.vector.get(row).map_or(false, |r| r.contains(column))
     }
 
     /// Add the bits from row `read` to the bits from row `write`,
@@ -315,16 +323,27 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
         let mut changed = false;
 
         if read != write {
-            let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write);
+            if self.vector.get(read).is_some() {
+                self.vector
+                    .ensure_contains_elem(write, || SparseBitSet::new());
+                let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write);
 
-            for read_chunk in bit_set_read.chunks() {
-                changed = changed | bit_set_write.insert_chunk(read_chunk).any();
+                for read_chunk in bit_set_read.chunks() {
+                    changed = changed | bit_set_write.insert_chunk(read_chunk).any();
+                }
             }
         }
 
         changed
     }
 
+    /// Merge a row, `from`, into the `into` row.
+    pub fn merge_into(&mut self, into: R, from: &SparseBitSet<C>) -> bool {
+        self.vector
+            .ensure_contains_elem(into, || SparseBitSet::new());
+        self.vector[into].insert_from(from)
+    }
+
     /// True if `sub` is a subset of `sup`
     pub fn is_subset(&self, sub: R, sup: R) -> bool {
         sub == sup || {
@@ -336,10 +355,20 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
         }
     }
 
+    /// Number of elements in the matrix.
+    pub fn len(&self) -> usize {
+        self.vector.len()
+    }
+
     /// Iterates through all the columns set to true in a given row of
     /// the matrix.
     pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
-        self.vector[row].iter()
+        self.vector.get(row).into_iter().flat_map(|r| r.iter())
+    }
+
+    /// Iterates through each row and the accompanying bit set.
+    pub fn iter_enumerated<'a>(&'a self) -> impl Iterator<Item = (R, &'a SparseBitSet<C>)> + 'a {
+        self.vector.iter_enumerated()
     }
 }
 
@@ -445,6 +474,15 @@ impl<I: Idx> SparseBitSet<I> {
         }
     }
 
+    /// Insert into bit set from another bit set.
+    pub fn insert_from(&mut self, from: &SparseBitSet<I>) -> bool {
+        let mut changed = false;
+        for read_chunk in from.chunks() {
+            changed = changed | self.insert_chunk(read_chunk).any();
+        }
+        changed
+    }
+
     pub fn remove_chunk(&mut self, chunk: SparseChunk<I>) -> SparseChunk<I> {
         if chunk.bits == 0 {
             return chunk;
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
index 26de2191090..e7a75c149cc 100644
--- a/src/librustc_data_structures/indexed_vec.rs
+++ b/src/librustc_data_structures/indexed_vec.rs
@@ -518,10 +518,28 @@ impl<I: Idx, T> IndexVec<I, T> {
 }
 
 impl<I: Idx, T: Clone> IndexVec<I, T> {
+    /// Grows the index vector so that it contains an entry for
+    /// `elem`; if that is already true, then has no
+    /// effect. Otherwise, inserts new values as needed by invoking
+    /// `fill_value`.
+    #[inline]
+    pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) {
+        let min_new_len = elem.index() + 1;
+        if self.len() < min_new_len {
+            self.raw.resize_with(min_new_len, fill_value);
+        }
+    }
+
     #[inline]
     pub fn resize(&mut self, new_len: usize, value: T) {
         self.raw.resize(new_len, value)
     }
+
+    #[inline]
+    pub fn resize_to_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) {
+        let min_new_len = elem.index() + 1;
+        self.raw.resize_with(min_new_len, fill_value);
+    }
 }
 
 impl<I: Idx, T: Ord> IndexVec<I, T> {
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 508dc567fa0..b386f887d77 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -30,6 +30,7 @@
 #![feature(optin_builtin_traits)]
 #![feature(macro_vis_matcher)]
 #![feature(allow_internal_unstable)]
+#![feature(vec_resize_with)]
 
 #![cfg_attr(unix, feature(libc))]
 #![cfg_attr(test, feature(test))]
diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
index 68484888477..f274f8e9189 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
@@ -21,7 +21,6 @@ use rustc::mir::{Local, Statement, Terminator};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts};
-use std::iter;
 
 pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
     infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
@@ -30,7 +29,6 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
     location_table: &LocationTable,
     mir: &Mir<'tcx>,
     borrow_set: &BorrowSet<'tcx>,
-    liveness_set_from_typeck: &[(ty::Region<'tcx>, Location)],
 ) {
     let mut cg = ConstraintGeneration {
         borrow_set,
@@ -40,8 +38,6 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
         all_facts,
     };
 
-    cg.add_region_liveness_constraints_from_type_check(liveness_set_from_typeck);
-
     for (bb, data) in mir.basic_blocks().iter_enumerated() {
         cg.visit_basic_block_data(bb, data);
     }
@@ -189,42 +185,6 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
 }
 
 impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
-    /// The MIR type checker generates region liveness constraints
-    /// that we also have to respect.
-    fn add_region_liveness_constraints_from_type_check(
-        &mut self,
-        liveness_set: &[(ty::Region<'tcx>, Location)],
-    ) {
-        debug!(
-            "add_region_liveness_constraints_from_type_check(liveness_set={} items)",
-            liveness_set.len(),
-        );
-
-        let ConstraintGeneration {
-            regioncx,
-            location_table,
-            all_facts,
-            ..
-        } = self;
-
-        for (region, location) in liveness_set {
-            debug!("generate: {:#?} is live at {:#?}", region, location);
-            let region_vid = regioncx.to_region_vid(region);
-            regioncx.add_live_element(region_vid, *location);
-        }
-
-        if let Some(all_facts) = all_facts {
-            all_facts
-                .region_live_at
-                .extend(liveness_set.into_iter().flat_map(|(region, location)| {
-                    let r = regioncx.to_region_vid(region);
-                    let p1 = location_table.start_index(*location);
-                    let p2 = location_table.mid_index(*location);
-                    iter::once((r, p1)).chain(iter::once((r, p2)))
-                }));
-        }
-    }
-
     /// Some variable with type `live_ty` is "regular live" at
     /// `location` -- i.e., it may be used later. This means that all
     /// regions appearing in the type `live_ty` must be live at
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index acd9223e425..5fcf46f6903 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -12,6 +12,7 @@ use borrow_check::borrow_set::BorrowSet;
 use borrow_check::location::{LocationIndex, LocationTable};
 use borrow_check::nll::facts::AllFactsExt;
 use borrow_check::nll::type_check::MirTypeckRegionConstraints;
+use borrow_check::nll::region_infer::values::RegionValueElements;
 use dataflow::indexes::BorrowIndex;
 use dataflow::move_paths::MoveData;
 use dataflow::FlowAtLocation;
@@ -99,6 +100,8 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
         None
     };
 
+    let elements = &Rc::new(RegionValueElements::new(mir, universal_regions.len()));
+
     // Run the MIR type-checker.
     let liveness = &LivenessResults::compute(mir);
     let constraint_sets = type_check::type_check(
@@ -113,6 +116,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
         &mut all_facts,
         flow_inits,
         move_data,
+        elements,
     );
 
     if let Some(all_facts) = &mut all_facts {
@@ -126,7 +130,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
     // base constraints generated by the type-check.
     let var_origins = infcx.take_region_var_origins();
     let MirTypeckRegionConstraints {
-        liveness_set,
+        liveness_constraints,
         outlives_constraints,
         type_tests,
     } = constraint_sets;
@@ -136,6 +140,8 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
         mir,
         outlives_constraints,
         type_tests,
+        liveness_constraints,
+        elements,
     );
 
     // Generate various additional constraints.
@@ -146,7 +152,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
         location_table,
         &mir,
         borrow_set,
-        &liveness_set,
     );
     invalidation::generate_invalidates(
         infcx,
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 369f6bd36f8..5159fdc9fba 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -37,7 +37,7 @@ mod annotation;
 mod dump_mir;
 mod error_reporting;
 mod graphviz;
-mod values;
+pub mod values;
 use self::values::{RegionValueElements, RegionValues};
 
 use super::ToRegionVid;
@@ -66,8 +66,8 @@ pub struct RegionInferenceContext<'tcx> {
     /// the SCC (see `constraint_sccs`) and for error reporting.
     constraint_graph: Rc<ConstraintGraph>,
 
-    /// The SCC computed from `constraints` and
-    /// `constraint_graph`. Used to compute the values of each region.
+    /// The SCC computed from `constraints` and the constraint graph. Used to compute the values
+    /// of each region.
     constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
 
     /// The final inferred values of the region variables; we compute
@@ -207,15 +207,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     pub(crate) fn new(
         var_infos: VarInfos,
         universal_regions: UniversalRegions<'tcx>,
-        mir: &Mir<'tcx>,
+        _mir: &Mir<'tcx>,
         outlives_constraints: ConstraintSet,
         type_tests: Vec<TypeTest<'tcx>>,
+        liveness_constraints: RegionValues<RegionVid>,
+        elements: &Rc<RegionValueElements>,
     ) -> Self {
         let universal_regions = Rc::new(universal_regions);
-        let num_region_variables = var_infos.len();
-        let num_universal_regions = universal_regions.len();
-
-        let elements = &Rc::new(RegionValueElements::new(mir, num_universal_regions));
 
         // Create a RegionDefinition for each inference variable.
         let definitions: IndexVec<_, _> = var_infos
@@ -227,15 +225,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         let constraint_graph = Rc::new(constraints.graph(definitions.len()));
         let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph));
 
-        let scc_values = RegionValues::new(elements, constraint_sccs.num_sccs());
+        let mut scc_values = RegionValues::new(elements);
+
+        for (region, location_set) in liveness_constraints.iter_enumerated() {
+            let scc = constraint_sccs.scc(region);
+            scc_values.merge_into(scc, location_set);
+        }
 
         let mut result = Self {
             definitions,
             elements: elements.clone(),
-            liveness_constraints: RegionValues::new(elements, num_region_variables),
+            liveness_constraints,
             constraints,
-            constraint_sccs,
             constraint_graph,
+            constraint_sccs,
             scc_values,
             type_tests,
             universal_regions,
@@ -414,7 +417,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             constraints
         });
 
-        // To propagate constriants, we walk the DAG induced by the
+        // To propagate constraints, we walk the DAG induced by the
         // SCC. For each SCC, we visit its successors and compute
         // their values, then we union all those values to get our
         // own.
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
index c5bfb1fc6a5..f041483a8ff 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
@@ -10,7 +10,7 @@
 
 use rustc::mir::{BasicBlock, Location, Mir};
 use rustc::ty::RegionVid;
-use rustc_data_structures::bitvec::SparseBitMatrix;
+use rustc_data_structures::bitvec::{SparseBitMatrix, SparseBitSet};
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::fmt::Debug;
@@ -55,11 +55,6 @@ impl RegionValueElements {
         }
     }
 
-    /// Total number of element indices that exist.
-    crate fn num_elements(&self) -> usize {
-        self.num_points + self.num_universal_regions
-    }
-
     /// Converts an element of a region value into a `RegionElementIndex`.
     crate fn index<T: ToElementIndex>(&self, elem: T) -> RegionElementIndex {
         elem.to_element_index(self)
@@ -188,18 +183,10 @@ impl<N: Idx> RegionValues<N> {
     /// Creates a new set of "region values" that tracks causal information.
     /// Each of the regions in num_region_variables will be initialized with an
     /// empty set of points and no causal information.
-    crate fn new(elements: &Rc<RegionValueElements>, num_region_variables: usize) -> Self {
-        assert!(
-            elements.num_universal_regions <= num_region_variables,
-            "universal regions are a subset of the region variables"
-        );
-
+    crate fn new(elements: &Rc<RegionValueElements>) -> Self {
         Self {
             elements: elements.clone(),
-            matrix: SparseBitMatrix::new(
-                N::new(num_region_variables),
-                RegionElementIndex::new(elements.num_elements()),
-            ),
+            matrix: SparseBitMatrix::new(),
         }
     }
 
@@ -227,6 +214,18 @@ impl<N: Idx> RegionValues<N> {
         self.matrix.contains(r, i)
     }
 
+    /// Iterates through each row and the accompanying bit set.
+    pub fn iter_enumerated<'a>(
+        &'a self
+    ) -> impl Iterator<Item = (N, &'a SparseBitSet<RegionElementIndex>)> + 'a {
+        self.matrix.iter_enumerated()
+    }
+
+    /// Merge a row, `from`, originating in another `RegionValues` into the `into` row.
+    pub fn merge_into(&mut self, into: N, from: &SparseBitSet<RegionElementIndex>) -> bool {
+        self.matrix.merge_into(into, from)
+    }
+
     /// True if `sup_region` contains all the CFG points that
     /// `sub_region` contains. Ignores universal regions.
     crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs
index 91025e3f4af..cd468eabd5f 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs
@@ -168,7 +168,18 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
         );
 
         cx.tcx().for_each_free_region(&value, |live_region| {
-            cx.constraints.liveness_set.push((live_region, location));
+            if let Some(ref mut borrowck_context) = cx.borrowck_context {
+                let region_vid = borrowck_context.universal_regions.to_region_vid(live_region);
+                borrowck_context.constraints.liveness_constraints.add_element(region_vid, location);
+
+                if let Some(all_facts) = borrowck_context.all_facts {
+                    let start_index = borrowck_context.location_table.start_index(location);
+                    all_facts.region_live_at.push((region_vid, start_index));
+
+                    let mid_index = borrowck_context.location_table.mid_index(location);
+                    all_facts.region_live_at.push((region_vid, mid_index));
+                }
+            }
         });
     }
 
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 25f2be23177..e188c9d7559 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -16,6 +16,7 @@ use borrow_check::location::LocationTable;
 use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
 use borrow_check::nll::facts::AllFacts;
 use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
+use borrow_check::nll::region_infer::values::{RegionValues, RegionValueElements};
 use borrow_check::nll::universal_regions::UniversalRegions;
 use borrow_check::nll::ToRegionVid;
 use dataflow::move_paths::MoveData;
@@ -33,8 +34,9 @@ use rustc::mir::*;
 use rustc::traits::query::type_op;
 use rustc::traits::query::{Fallible, NoSolution};
 use rustc::ty::fold::TypeFoldable;
-use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
+use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants, RegionVid};
 use std::fmt;
+use std::rc::Rc;
 use syntax_pos::{Span, DUMMY_SP};
 use transform::{MirPass, MirSource};
 use util::liveness::LivenessResults;
@@ -111,39 +113,55 @@ pub(crate) fn type_check<'gcx, 'tcx>(
     all_facts: &mut Option<AllFacts>,
     flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
+    elements: &Rc<RegionValueElements>,
 ) -> MirTypeckRegionConstraints<'tcx> {
     let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
-    type_check_internal(
-        infcx,
-        mir_def_id,
-        param_env,
-        mir,
-        &universal_regions.region_bound_pairs,
-        Some(implicit_region_bound),
-        Some(BorrowCheckContext {
+    let mut constraints = MirTypeckRegionConstraints {
+        liveness_constraints: RegionValues::new(elements),
+        outlives_constraints: ConstraintSet::default(),
+        type_tests: Vec::default(),
+    };
+
+    {
+        let mut borrowck_context = BorrowCheckContext {
             universal_regions,
             location_table,
             borrow_set,
             all_facts,
-        }),
-        &mut |cx| {
-            liveness::generate(cx, mir, liveness, flow_inits, move_data);
+            constraints: &mut constraints,
+        };
+
+        type_check_internal(
+            infcx,
+            mir_def_id,
+            param_env,
+            mir,
+            &universal_regions.region_bound_pairs,
+            Some(implicit_region_bound),
+            Some(&mut borrowck_context),
+            |cx| {
+                liveness::generate(cx, mir, liveness, flow_inits, move_data);
 
-            cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions);
-        },
-    )
+                cx.equate_inputs_and_outputs(mir, mir_def_id, universal_regions);
+            },
+        );
+    }
+
+    constraints
 }
 
-fn type_check_internal<'gcx, 'tcx>(
-    infcx: &InferCtxt<'_, 'gcx, 'tcx>,
+fn type_check_internal<'a, 'gcx, 'tcx, F>(
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
     mir_def_id: DefId,
     param_env: ty::ParamEnv<'gcx>,
-    mir: &Mir<'tcx>,
-    region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
+    mir: &'a Mir<'tcx>,
+    region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
     implicit_region_bound: Option<ty::Region<'tcx>>,
-    borrowck_context: Option<BorrowCheckContext<'_, 'tcx>>,
-    extra: &mut dyn FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>),
-) -> MirTypeckRegionConstraints<'tcx> {
+    borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
+    mut extra: F,
+)
+    where F: FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>)
+{
     let mut checker = TypeChecker::new(
         infcx,
         mir,
@@ -165,8 +183,6 @@ fn type_check_internal<'gcx, 'tcx>(
     }
 
     extra(&mut checker);
-
-    checker.constraints
 }
 
 fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
@@ -603,8 +619,7 @@ struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
     implicit_region_bound: Option<ty::Region<'tcx>>,
     reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
-    constraints: MirTypeckRegionConstraints<'tcx>,
-    borrowck_context: Option<BorrowCheckContext<'a, 'tcx>>,
+    borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
 }
 
 struct BorrowCheckContext<'a, 'tcx: 'a> {
@@ -612,11 +627,11 @@ struct BorrowCheckContext<'a, 'tcx: 'a> {
     location_table: &'a LocationTable,
     all_facts: &'a mut Option<AllFacts>,
     borrow_set: &'a BorrowSet<'tcx>,
+    constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
 }
 
 /// A collection of region constraints that must be satisfied for the
 /// program to be considered well-typed.
-#[derive(Default)]
 crate struct MirTypeckRegionConstraints<'tcx> {
     /// In general, the type-checker is not responsible for enforcing
     /// liveness constraints; this job falls to the region inferencer,
@@ -625,7 +640,7 @@ crate struct MirTypeckRegionConstraints<'tcx> {
     /// not otherwise appear in the MIR -- in particular, the
     /// late-bound regions that it instantiates at call-sites -- and
     /// hence it must report on their liveness constraints.
-    crate liveness_set: Vec<(ty::Region<'tcx>, Location)>,
+    crate liveness_constraints: RegionValues<RegionVid>,
 
     crate outlives_constraints: ConstraintSet,
 
@@ -717,7 +732,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         param_env: ty::ParamEnv<'gcx>,
         region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
         implicit_region_bound: Option<ty::Region<'tcx>>,
-        borrowck_context: Option<BorrowCheckContext<'a, 'tcx>>,
+        borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
     ) -> Self {
         TypeChecker {
             infcx,
@@ -729,7 +744,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             implicit_region_bound,
             borrowck_context,
             reported_errors: FxHashSet(),
-            constraints: MirTypeckRegionConstraints::default(),
         }
     }
 
@@ -767,7 +781,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             locations, data
         );
 
-        if let Some(borrowck_context) = &mut self.borrowck_context {
+        if let Some(ref mut borrowck_context) = self.borrowck_context {
             constraint_conversion::ConstraintConversion::new(
                 self.infcx.tcx,
                 borrowck_context.universal_regions,
@@ -776,8 +790,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 self.implicit_region_bound,
                 self.param_env,
                 locations,
-                &mut self.constraints.outlives_constraints,
-                &mut self.constraints.type_tests,
+                &mut borrowck_context.constraints.outlives_constraints,
+                &mut borrowck_context.constraints.type_tests,
                 &mut borrowck_context.all_facts,
             ).convert_all(&data);
         }
@@ -993,9 +1007,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 // output) types in the signature must be live, since
                 // all the inputs that fed into it were live.
                 for &late_bound_region in map.values() {
-                    self.constraints
-                        .liveness_set
-                        .push((late_bound_region, term_location));
+                    if let Some(ref mut borrowck_context) = self.borrowck_context {
+                        let region_vid = borrowck_context.universal_regions.to_region_vid(
+                            late_bound_region);
+                        borrowck_context.constraints
+                            .liveness_constraints
+                            .add_element(region_vid, term_location);
+                    }
                 }
 
                 self.check_call_inputs(mir, term, &sig, args, term_location);
@@ -1487,9 +1505,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             borrow_set,
             location_table,
             all_facts,
+            constraints,
             ..
-        } = match &mut self.borrowck_context {
-            Some(borrowck_context) => borrowck_context,
+        } = match self.borrowck_context {
+            Some(ref mut borrowck_context) => borrowck_context,
             None => return,
         };
 
@@ -1531,7 +1550,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
                     match base_ty.sty {
                         ty::TyRef(ref_region, _, mutbl) => {
-                            self.constraints
+                            constraints
                                 .outlives_constraints
                                 .push(OutlivesConstraint {
                                     sup: ref_region.to_region_vid(),
@@ -1792,8 +1811,7 @@ impl MirPass for TypeckMir {
 
         let param_env = tcx.param_env(def_id);
         tcx.infer_ctxt().enter(|infcx| {
-            let _ =
-                type_check_internal(&infcx, def_id, param_env, mir, &[], None, None, &mut |_| ());
+            type_check_internal(&infcx, def_id, param_env, mir, &[], None, None, |_| ());
 
             // For verification purposes, we just ignore the resulting
             // region constraint sets. Not our problem. =)