]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_infer/infer/mod.rs
perf: Lazily recive the Rollback argument in rollback_to
[rust.git] / src / librustc_infer / infer / mod.rs
index 267f1e7e2dc892406049804c7afa95aeee736802..fbba96fbe99cf9983aaba5c20f74e3bdcd56101a 100644 (file)
@@ -10,7 +10,9 @@
 
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::snapshot_vec as sv;
 use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::undo_log::{Rollback, Snapshots, UndoLogs};
 use rustc_data_structures::unify as ut;
 use rustc_errors::DiagnosticBuilder;
 use rustc_hir as hir;
 use std::cell::{Cell, Ref, RefCell};
 use std::collections::BTreeMap;
 use std::fmt;
+use std::marker::PhantomData;
 
 use self::combine::CombineFields;
 use self::free_regions::RegionRelations;
 use self::lexical_region_resolve::LexicalRegionResolutions;
 use self::outlives::env::OutlivesEnvironment;
 use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
-use self::region_constraints::{RegionConstraintCollector, RegionSnapshot};
+use self::region_constraints::{
+    RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
+};
 use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 
 pub mod at;
@@ -136,28 +141,29 @@ pub struct InferCtxtInner<'tcx> {
     /// Cache for projections. This cache is snapshotted along with the infcx.
     ///
     /// Public so that `traits::project` can use it.
-    pub projection_cache: traits::ProjectionCache<'tcx>,
+    pub projection_cache: traits::ProjectionCacheStorage<'tcx>,
 
     /// We instantiate `UnificationTable` with `bounds<Ty>` because the types
     /// that might instantiate a general type variable have an order,
     /// represented by its upper and lower bounds.
-    type_variables: type_variable::TypeVariableTable<'tcx>,
+    type_variables: type_variable::TypeVariableStorage<'tcx>,
+    undo_log: Logs<'tcx>,
 
     /// Map from const parameter variable to the kind of const it represents.
-    const_unification_table: ut::UnificationTable<ut::InPlace<ty::ConstVid<'tcx>>>,
+    const_unification_table: ut::UnificationStorage<ty::ConstVid<'tcx>>,
 
     /// Map from integral variable to the kind of integer it represents.
-    int_unification_table: ut::UnificationTable<ut::InPlace<ty::IntVid>>,
+    int_unification_table: ut::UnificationStorage<ty::IntVid>,
 
     /// Map from floating variable to the kind of float it represents.
-    float_unification_table: ut::UnificationTable<ut::InPlace<ty::FloatVid>>,
+    float_unification_table: ut::UnificationStorage<ty::FloatVid>,
 
     /// Tracks the set of region variables and the constraints between them.
     /// This is initially `Some(_)` but when
     /// `resolve_regions_and_report_errors` is invoked, this gets set to `None`
     /// -- further attempts to perform unification, etc., may fail if new
     /// region constraints would've been added.
-    region_constraints: Option<RegionConstraintCollector<'tcx>>,
+    region_constraints: Option<RegionConstraintStorage<'tcx>>,
 
     /// A set of constraints that regionck must validate. Each
     /// constraint has the form `T:'a`, meaning "some type `T` must
@@ -197,17 +203,272 @@ impl<'tcx> InferCtxtInner<'tcx> {
     fn new() -> InferCtxtInner<'tcx> {
         InferCtxtInner {
             projection_cache: Default::default(),
-            type_variables: type_variable::TypeVariableTable::new(),
-            const_unification_table: ut::UnificationTable::new(),
-            int_unification_table: ut::UnificationTable::new(),
-            float_unification_table: ut::UnificationTable::new(),
-            region_constraints: Some(RegionConstraintCollector::new()),
+            type_variables: type_variable::TypeVariableStorage::new(),
+            undo_log: Logs::default(),
+            const_unification_table: ut::UnificationStorage::new(),
+            int_unification_table: ut::UnificationStorage::new(),
+            float_unification_table: ut::UnificationStorage::new(),
+            region_constraints: Some(RegionConstraintStorage::new()),
             region_obligations: vec![],
         }
     }
 
-    pub fn unwrap_region_constraints(&mut self) -> &mut RegionConstraintCollector<'tcx> {
-        self.region_constraints.as_mut().expect("region constraints already solved")
+    pub(crate) fn projection_cache(&mut self) -> traits::ProjectionCache<'tcx, '_> {
+        self.projection_cache.with_log(&mut self.undo_log)
+    }
+
+    fn type_variables(&mut self) -> type_variable::TypeVariableTable<'tcx, '_> {
+        self.type_variables.with_log(&mut self.undo_log)
+    }
+
+    fn int_unification_table(
+        &mut self,
+    ) -> ut::UnificationTable<
+        ut::InPlace<ty::IntVid, &mut ut::UnificationStorage<ty::IntVid>, &mut Logs<'tcx>>,
+    > {
+        ut::UnificationTable::with_log(&mut self.int_unification_table, &mut self.undo_log)
+    }
+
+    fn float_unification_table(
+        &mut self,
+    ) -> ut::UnificationTable<
+        ut::InPlace<ty::FloatVid, &mut ut::UnificationStorage<ty::FloatVid>, &mut Logs<'tcx>>,
+    > {
+        ut::UnificationTable::with_log(&mut self.float_unification_table, &mut self.undo_log)
+    }
+
+    fn const_unification_table(
+        &mut self,
+    ) -> ut::UnificationTable<
+        ut::InPlace<
+            ty::ConstVid<'tcx>,
+            &mut ut::UnificationStorage<ty::ConstVid<'tcx>>,
+            &mut Logs<'tcx>,
+        >,
+    > {
+        ut::UnificationTable::with_log(&mut self.const_unification_table, &mut self.undo_log)
+    }
+
+    pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'tcx, '_> {
+        self.region_constraints
+            .as_mut()
+            .expect("region constraints already solved")
+            .with_log(&mut self.undo_log)
+    }
+}
+
+pub struct Snapshot<'tcx> {
+    undo_len: usize,
+    _marker: PhantomData<&'tcx ()>,
+}
+
+pub(crate) enum UndoLog<'tcx> {
+    TypeVariables(type_variable::UndoLog<'tcx>),
+    ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
+    IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
+    FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
+    RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
+    RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>),
+    ProjectionCache(traits::UndoLog<'tcx>),
+}
+
+impl<'tcx> From<region_constraints::UndoLog<'tcx>> for UndoLog<'tcx> {
+    fn from(l: region_constraints::UndoLog<'tcx>) -> Self {
+        UndoLog::RegionConstraintCollector(l)
+    }
+}
+
+impl<'tcx> From<sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>> for UndoLog<'tcx> {
+    fn from(l: sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>) -> Self {
+        UndoLog::TypeVariables(type_variable::UndoLog::EqRelation(l))
+    }
+}
+
+impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::TyVid>>> for UndoLog<'tcx> {
+    fn from(l: sv::UndoLog<ut::Delegate<ty::TyVid>>) -> Self {
+        UndoLog::TypeVariables(type_variable::UndoLog::SubRelation(l))
+    }
+}
+
+impl<'tcx> From<sv::UndoLog<type_variable::Delegate>> for UndoLog<'tcx> {
+    fn from(l: sv::UndoLog<type_variable::Delegate>) -> Self {
+        UndoLog::TypeVariables(type_variable::UndoLog::Values(l))
+    }
+}
+
+impl<'tcx> From<type_variable::Instantiate> for UndoLog<'tcx> {
+    fn from(l: type_variable::Instantiate) -> Self {
+        UndoLog::TypeVariables(type_variable::UndoLog::from(l))
+    }
+}
+
+impl From<type_variable::UndoLog<'tcx>> for UndoLog<'tcx> {
+    fn from(t: type_variable::UndoLog<'tcx>) -> Self {
+        Self::TypeVariables(t)
+    }
+}
+
+impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>> for UndoLog<'tcx> {
+    fn from(l: sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>) -> Self {
+        Self::ConstUnificationTable(l)
+    }
+}
+
+impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::IntVid>>> for UndoLog<'tcx> {
+    fn from(l: sv::UndoLog<ut::Delegate<ty::IntVid>>) -> Self {
+        Self::IntUnificationTable(l)
+    }
+}
+
+impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::FloatVid>>> for UndoLog<'tcx> {
+    fn from(l: sv::UndoLog<ut::Delegate<ty::FloatVid>>) -> Self {
+        Self::FloatUnificationTable(l)
+    }
+}
+
+impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::RegionVid>>> for UndoLog<'tcx> {
+    fn from(l: sv::UndoLog<ut::Delegate<ty::RegionVid>>) -> Self {
+        Self::RegionUnificationTable(l)
+    }
+}
+
+impl<'tcx> From<traits::UndoLog<'tcx>> for UndoLog<'tcx> {
+    fn from(l: traits::UndoLog<'tcx>) -> Self {
+        Self::ProjectionCache(l)
+    }
+}
+
+pub(crate) type UnificationTable<'a, 'tcx, T> =
+    ut::UnificationTable<ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut Logs<'tcx>>>;
+
+struct RollbackView<'tcx, 'a> {
+    type_variables: type_variable::RollbackView<'tcx, 'a>,
+    const_unification_table: &'a mut ut::UnificationStorage<ty::ConstVid<'tcx>>,
+    int_unification_table: &'a mut ut::UnificationStorage<ty::IntVid>,
+    float_unification_table: &'a mut ut::UnificationStorage<ty::FloatVid>,
+    region_constraints: &'a mut RegionConstraintStorage<'tcx>,
+    projection_cache: &'a mut traits::ProjectionCacheStorage<'tcx>,
+}
+
+impl<'tcx> Rollback<UndoLog<'tcx>> for RollbackView<'tcx, '_> {
+    fn reverse(&mut self, undo: UndoLog<'tcx>) {
+        match undo {
+            UndoLog::TypeVariables(undo) => self.type_variables.reverse(undo),
+            UndoLog::ConstUnificationTable(undo) => self.const_unification_table.reverse(undo),
+            UndoLog::IntUnificationTable(undo) => self.int_unification_table.reverse(undo),
+            UndoLog::FloatUnificationTable(undo) => self.float_unification_table.reverse(undo),
+            UndoLog::RegionConstraintCollector(undo) => self.region_constraints.reverse(undo),
+            UndoLog::RegionUnificationTable(undo) => {
+                self.region_constraints.unification_table.reverse(undo)
+            }
+            UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo),
+        }
+    }
+}
+
+pub(crate) struct Logs<'tcx> {
+    logs: Vec<UndoLog<'tcx>>,
+    num_open_snapshots: usize,
+}
+
+impl Default for Logs<'_> {
+    fn default() -> Self {
+        Self { logs: Default::default(), num_open_snapshots: Default::default() }
+    }
+}
+
+impl<'tcx, T> UndoLogs<T> for Logs<'tcx>
+where
+    UndoLog<'tcx>: From<T>,
+{
+    fn num_open_snapshots(&self) -> usize {
+        self.num_open_snapshots
+    }
+    fn push(&mut self, undo: T) {
+        if self.in_snapshot() {
+            self.logs.push(undo.into())
+        }
+    }
+    fn clear(&mut self) {
+        self.logs.clear();
+        self.num_open_snapshots = 0;
+    }
+    fn extend<J>(&mut self, undos: J)
+    where
+        Self: Sized,
+        J: IntoIterator<Item = T>,
+    {
+        if self.in_snapshot() {
+            self.logs.extend(undos.into_iter().map(UndoLog::from))
+        }
+    }
+}
+
+impl<'tcx> Snapshots<UndoLog<'tcx>> for Logs<'tcx> {
+    type Snapshot = Snapshot<'tcx>;
+    fn actions_since_snapshot(&self, snapshot: &Self::Snapshot) -> &[UndoLog<'tcx>] {
+        &self.logs[snapshot.undo_len..]
+    }
+
+    fn start_snapshot(&mut self) -> Self::Snapshot {
+        unreachable!()
+    }
+
+    fn rollback_to<R>(&mut self, values: impl FnOnce() -> R, snapshot: Self::Snapshot)
+    where
+        R: Rollback<UndoLog<'tcx>>,
+    {
+        debug!("rollback_to({})", snapshot.undo_len);
+        self.assert_open_snapshot(&snapshot);
+
+        if self.logs.len() > snapshot.undo_len {
+            let mut values = values();
+            while self.logs.len() > snapshot.undo_len {
+                values.reverse(self.logs.pop().unwrap());
+            }
+        }
+
+        if self.num_open_snapshots == 1 {
+            // The root snapshot. It's safe to clear the undo log because
+            // there's no snapshot further out that we might need to roll back
+            // to.
+            assert!(snapshot.undo_len == 0);
+            self.logs.clear();
+        }
+
+        self.num_open_snapshots -= 1;
+    }
+
+    fn commit(&mut self, snapshot: Self::Snapshot) {
+        debug!("commit({})", snapshot.undo_len);
+
+        if self.num_open_snapshots == 1 {
+            // The root snapshot. It's safe to clear the undo log because
+            // there's no snapshot further out that we might need to roll back
+            // to.
+            assert!(snapshot.undo_len == 0);
+            self.logs.clear();
+        }
+
+        self.num_open_snapshots -= 1;
+    }
+}
+
+impl<'tcx> Logs<'tcx> {
+    pub(crate) fn region_constraints(
+        &self,
+        after: usize,
+    ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone {
+        self.logs[after..].iter().filter_map(|log| match log {
+            UndoLog::RegionConstraintCollector(log) => Some(log),
+            _ => None,
+        })
+    }
+
+    fn assert_open_snapshot(&self, snapshot: &Snapshot<'tcx>) {
+        // Failures here may indicate a failure to follow a stack discipline.
+        assert!(self.logs.len() >= snapshot.undo_len);
+        assert!(self.num_open_snapshots > 0);
     }
 }
 
@@ -642,13 +903,18 @@ pub fn into_obligations(self) -> PredicateObligations<'tcx> {
 }
 
 #[must_use = "once you start a snapshot, you should always consume it"]
-pub struct CombinedSnapshot<'a, 'tcx> {
-    projection_cache_snapshot: traits::ProjectionCacheSnapshot,
-    type_snapshot: type_variable::Snapshot<'tcx>,
-    const_snapshot: ut::Snapshot<ut::InPlace<ty::ConstVid<'tcx>>>,
-    int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>,
-    float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>,
+pub struct FullSnapshot<'a, 'tcx> {
+    snapshot: CombinedSnapshot<'a, 'tcx>,
     region_constraints_snapshot: RegionSnapshot,
+    type_snapshot: type_variable::Snapshot<'tcx>,
+    const_snapshot: usize,
+    int_snapshot: usize,
+    float_snapshot: usize,
+}
+
+#[must_use = "once you start a snapshot, you should always consume it"]
+pub struct CombinedSnapshot<'a, 'tcx> {
+    undo_snapshot: Snapshot<'tcx>,
     region_obligations_snapshot: usize,
     universe: ty::UniverseIndex,
     was_in_snapshot: bool,
@@ -667,7 +933,7 @@ pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T {
 
     pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool {
         match ty.kind {
-            ty::Infer(ty::TyVar(vid)) => self.inner.borrow().type_variables.var_diverges(vid),
+            ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid),
             _ => false,
         }
     }
@@ -681,14 +947,14 @@ pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumer
         use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
         match ty.kind {
             ty::Infer(ty::IntVar(vid)) => {
-                if self.inner.borrow_mut().int_unification_table.probe_value(vid).is_some() {
+                if self.inner.borrow_mut().int_unification_table().probe_value(vid).is_some() {
                     Neither
                 } else {
                     UnconstrainedInt
                 }
             }
             ty::Infer(ty::FloatVar(vid)) => {
-                if self.inner.borrow_mut().float_unification_table.probe_value(vid).is_some() {
+                if self.inner.borrow_mut().float_unification_table().probe_value(vid).is_some() {
                     Neither
                 } else {
                     UnconstrainedFloat
@@ -703,21 +969,21 @@ pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
         // FIXME(const_generics): should there be an equivalent function for const variables?
 
         let mut vars: Vec<Ty<'_>> = inner
-            .type_variables
+            .type_variables()
             .unsolved_variables()
             .into_iter()
             .map(|t| self.tcx.mk_ty_var(t))
             .collect();
         vars.extend(
-            (0..inner.int_unification_table.len())
+            (0..inner.int_unification_table().len())
                 .map(|i| ty::IntVid { index: i as u32 })
-                .filter(|&vid| inner.int_unification_table.probe_value(vid).is_none())
+                .filter(|&vid| inner.int_unification_table().probe_value(vid).is_none())
                 .map(|v| self.tcx.mk_int_var(v)),
         );
         vars.extend(
-            (0..inner.float_unification_table.len())
+            (0..inner.float_unification_table().len())
                 .map(|i| ty::FloatVid { index: i as u32 })
-                .filter(|&vid| inner.float_unification_table.probe_value(vid).is_none())
+                .filter(|&vid| inner.float_unification_table().probe_value(vid).is_none())
                 .map(|v| self.tcx.mk_float_var(v)),
         );
         vars
@@ -763,19 +1029,30 @@ pub fn save_and_restore_in_snapshot_flag<F, R>(&self, func: F) -> R
         result
     }
 
+    fn start_full_snapshot(&self) -> FullSnapshot<'a, 'tcx> {
+        let snapshot = self.start_snapshot();
+        let mut inner = self.inner.borrow_mut();
+        FullSnapshot {
+            snapshot,
+            type_snapshot: inner.type_variables().snapshot(),
+            const_snapshot: inner.const_unification_table().len(),
+            int_snapshot: inner.int_unification_table().len(),
+            float_snapshot: inner.float_unification_table().len(),
+            region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
+        }
+    }
+
     fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> {
         debug!("start_snapshot()");
 
         let in_snapshot = self.in_snapshot.replace(true);
 
         let mut inner = self.inner.borrow_mut();
+
+        inner.undo_log.num_open_snapshots += 1;
+        let undo_snapshot = Snapshot { undo_len: inner.undo_log.logs.len(), _marker: PhantomData };
         CombinedSnapshot {
-            projection_cache_snapshot: inner.projection_cache.snapshot(),
-            type_snapshot: inner.type_variables.snapshot(),
-            const_snapshot: inner.const_unification_table.snapshot(),
-            int_snapshot: inner.int_unification_table.snapshot(),
-            float_snapshot: inner.float_unification_table.snapshot(),
-            region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
+            undo_snapshot,
             region_obligations_snapshot: inner.region_obligations.len(),
             universe: self.universe(),
             was_in_snapshot: in_snapshot,
@@ -789,12 +1066,7 @@ fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> {
     fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
         debug!("rollback_to(cause={})", cause);
         let CombinedSnapshot {
-            projection_cache_snapshot,
-            type_snapshot,
-            const_snapshot,
-            int_snapshot,
-            float_snapshot,
-            region_constraints_snapshot,
+            undo_snapshot,
             region_obligations_snapshot,
             universe,
             was_in_snapshot,
@@ -806,25 +1078,35 @@ fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
         self.universe.set(universe);
         self.skip_leak_check.set(was_skip_leak_check);
 
-        let mut inner = self.inner.borrow_mut();
-        inner.projection_cache.rollback_to(projection_cache_snapshot);
-        inner.type_variables.rollback_to(type_snapshot);
-        inner.const_unification_table.rollback_to(const_snapshot);
-        inner.int_unification_table.rollback_to(int_snapshot);
-        inner.float_unification_table.rollback_to(float_snapshot);
-        inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot);
-        inner.region_obligations.truncate(region_obligations_snapshot);
+        let InferCtxtInner {
+            type_variables,
+            const_unification_table,
+            int_unification_table,
+            float_unification_table,
+            region_constraints,
+            projection_cache,
+            region_obligations,
+            undo_log,
+            ..
+        } = &mut *self.inner.borrow_mut();
+        undo_log.rollback_to(
+            || RollbackView {
+                type_variables: type_variable::RollbackView::from(type_variables),
+                const_unification_table,
+                int_unification_table,
+                float_unification_table,
+                region_constraints: region_constraints.as_mut().unwrap(),
+                projection_cache,
+            },
+            undo_snapshot,
+        );
+        region_obligations.truncate(region_obligations_snapshot);
     }
 
     fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
         debug!("commit_from()");
         let CombinedSnapshot {
-            projection_cache_snapshot,
-            type_snapshot,
-            const_snapshot,
-            int_snapshot,
-            float_snapshot,
-            region_constraints_snapshot,
+            undo_snapshot,
             region_obligations_snapshot: _,
             universe: _,
             was_in_snapshot,
@@ -836,12 +1118,7 @@ fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
         self.skip_leak_check.set(was_skip_leak_check);
 
         let mut inner = self.inner.borrow_mut();
-        inner.projection_cache.commit(projection_cache_snapshot);
-        inner.type_variables.commit(type_snapshot);
-        inner.const_unification_table.commit(const_snapshot);
-        inner.int_unification_table.commit(int_snapshot);
-        inner.float_unification_table.commit(float_snapshot);
-        inner.unwrap_region_constraints().commit(region_constraints_snapshot);
+        inner.undo_log.commit(undo_snapshot);
     }
 
     /// Executes `f` and commit the bindings.
@@ -888,6 +1165,17 @@ pub fn probe<R, F>(&self, f: F) -> R
         r
     }
 
+    pub fn probe_full<R, F>(&self, f: F) -> R
+    where
+        F: FnOnce(&FullSnapshot<'a, 'tcx>) -> R,
+    {
+        debug!("probe()");
+        let snapshot = self.start_full_snapshot();
+        let r = f(&snapshot);
+        self.rollback_to("probe", snapshot.snapshot);
+        r
+    }
+
     /// If `should_skip` is true, then execute `f` then unroll any bindings it creates.
     pub fn probe_maybe_skip_leak_check<R, F>(&self, should_skip: bool, f: F) -> R
     where
@@ -914,7 +1202,7 @@ pub fn region_constraints_added_in_snapshot(
         self.inner
             .borrow_mut()
             .unwrap_region_constraints()
-            .region_constraints_added_in_snapshot(&snapshot.region_constraints_snapshot)
+            .region_constraints_added_in_snapshot(&snapshot.undo_snapshot)
     }
 
     pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
@@ -1032,7 +1320,7 @@ pub fn region_outlives_predicate(
     }
 
     pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
-        self.inner.borrow_mut().type_variables.new_var(self.universe(), diverging, origin)
+        self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin)
     }
 
     pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
@@ -1044,7 +1332,7 @@ pub fn next_ty_var_in_universe(
         origin: TypeVariableOrigin,
         universe: ty::UniverseIndex,
     ) -> Ty<'tcx> {
-        let vid = self.inner.borrow_mut().type_variables.new_var(universe, false, origin);
+        let vid = self.inner.borrow_mut().type_variables().new_var(universe, false, origin);
         self.tcx.mk_ty_var(vid)
     }
 
@@ -1069,20 +1357,20 @@ pub fn next_const_var_in_universe(
         let vid = self
             .inner
             .borrow_mut()
-            .const_unification_table
+            .const_unification_table()
             .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } });
         self.tcx.mk_const_var(vid, ty)
     }
 
     pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> {
-        self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue {
+        self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue {
             origin,
             val: ConstVariableValue::Unknown { universe: self.universe() },
         })
     }
 
     fn next_int_var_id(&self) -> IntVid {
-        self.inner.borrow_mut().int_unification_table.new_key(None)
+        self.inner.borrow_mut().int_unification_table().new_key(None)
     }
 
     pub fn next_int_var(&self) -> Ty<'tcx> {
@@ -1090,7 +1378,7 @@ pub fn next_int_var(&self) -> Ty<'tcx> {
     }
 
     fn next_float_var_id(&self) -> FloatVid {
-        self.inner.borrow_mut().float_unification_table.new_key(None)
+        self.inner.borrow_mut().float_unification_table().new_key(None)
     }
 
     pub fn next_float_var(&self) -> Ty<'tcx> {
@@ -1161,7 +1449,7 @@ pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> GenericArg
                 // used in a path such as `Foo::<T, U>::new()` will
                 // use an inference variable for `C` with `[T, U]`
                 // as the substitutions for the default, `(T, U)`.
-                let ty_var_id = self.inner.borrow_mut().type_variables.new_var(
+                let ty_var_id = self.inner.borrow_mut().type_variables().new_var(
                     self.universe(),
                     false,
                     TypeVariableOrigin {
@@ -1181,7 +1469,7 @@ pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> GenericArg
                     span,
                 };
                 let const_var_id =
-                    self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue {
+                    self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue {
                         origin,
                         val: ConstVariableValue::Unknown { universe: self.universe() },
                     });
@@ -1245,6 +1533,7 @@ pub fn resolve_regions_and_report_errors(
             .region_constraints
             .take()
             .expect("regions already resolved")
+            .with_log(&mut inner.undo_log)
             .into_infos_and_data();
 
         let region_rels = &RegionRelations::new(
@@ -1306,12 +1595,12 @@ pub fn with_region_constraints<R>(
     /// called. This is used only during NLL processing to "hand off" ownership
     /// of the set of region variables into the NLL region context.
     pub fn take_region_var_origins(&self) -> VarInfos {
-        let (var_infos, data) = self
-            .inner
-            .borrow_mut()
+        let mut inner = self.inner.borrow_mut();
+        let (var_infos, data) = inner
             .region_constraints
             .take()
             .expect("regions already resolved")
+            .with_log(&mut inner.undo_log)
             .into_infos_and_data();
         assert!(data.is_empty());
         var_infos
@@ -1335,7 +1624,7 @@ pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String {
     pub fn probe_ty_var(&self, vid: TyVid) -> Result<Ty<'tcx>, ty::UniverseIndex> {
         use self::type_variable::TypeVariableValue;
 
-        match self.inner.borrow_mut().type_variables.probe(vid) {
+        match self.inner.borrow_mut().type_variables().probe(vid) {
             TypeVariableValue::Known { value } => Ok(value),
             TypeVariableValue::Unknown { universe } => Err(universe),
         }
@@ -1357,7 +1646,7 @@ pub fn shallow_resolve<T>(&self, value: T) -> T
     }
 
     pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
-        self.inner.borrow_mut().type_variables.root_var(var)
+        self.inner.borrow_mut().type_variables().root_var(var)
     }
 
     /// Where possible, replaces type/const variables in
@@ -1395,7 +1684,7 @@ pub fn probe_const_var(
         &self,
         vid: ty::ConstVid<'tcx>,
     ) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> {
-        match self.inner.borrow_mut().const_unification_table.probe_value(vid).val {
+        match self.inner.borrow_mut().const_unification_table().probe_value(vid).val {
             ConstVariableValue::Known { value } => Ok(value),
             ConstVariableValue::Unknown { universe } => Err(universe),
         }
@@ -1482,7 +1771,7 @@ pub fn replace_bound_vars_with_fresh_vars<T>(
         self.tcx.replace_bound_vars(value, fld_r, fld_t, fld_c)
     }
 
-    /// See the [`region_constraints::verify_generic_bound`] method.
+    /// See the [`region_constraints::RegionConstraintCollector::verify_generic_bound`] method.
     pub fn verify_generic_bound(
         &self,
         origin: SubregionOrigin<'tcx>,
@@ -1513,7 +1802,7 @@ pub fn closure_kind(&self, closure_substs: SubstsRef<'tcx>) -> Option<ty::Closur
     pub fn clear_caches(&self) {
         self.selection_cache.clear();
         self.evaluation_cache.clear();
-        self.inner.borrow_mut().projection_cache.clear();
+        self.inner.borrow_mut().projection_cache().clear();
     }
 
     fn universe(&self) -> ty::UniverseIndex {
@@ -1576,14 +1865,14 @@ fn shallow_resolve_ty(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
                 //
                 // Note: if these two lines are combined into one we get
                 // dynamic borrow errors on `self.inner`.
-                let known = self.inner.borrow_mut().type_variables.probe(v).known();
+                let known = self.inner.borrow_mut().type_variables().probe(v).known();
                 known.map(|t| self.shallow_resolve_ty(t)).unwrap_or(typ)
             }
 
             ty::Infer(ty::IntVar(v)) => self
                 .inner
                 .borrow_mut()
-                .int_unification_table
+                .int_unification_table()
                 .probe_value(v)
                 .map(|v| v.to_type(self.tcx))
                 .unwrap_or(typ),
@@ -1591,7 +1880,7 @@ fn shallow_resolve_ty(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
             ty::Infer(ty::FloatVar(v)) => self
                 .inner
                 .borrow_mut()
-                .float_unification_table
+                .float_unification_table()
                 .probe_value(v)
                 .map(|v| v.to_type(self.tcx))
                 .unwrap_or(typ),
@@ -1617,7 +1906,7 @@ pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>)
 
                 // If `inlined_probe` returns a `Known` value, it never equals
                 // `ty::Infer(ty::TyVar(v))`.
-                match self.inner.borrow_mut().type_variables.inlined_probe(v) {
+                match self.inner.borrow_mut().type_variables().inlined_probe(v) {
                     TypeVariableValue::Unknown { .. } => false,
                     TypeVariableValue::Known { .. } => true,
                 }
@@ -1627,7 +1916,7 @@ pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>)
                 // If `inlined_probe_value` returns a value it's always a
                 // `ty::Int(_)` or `ty::UInt(_)`, which never matches a
                 // `ty::Infer(_)`.
-                self.inner.borrow_mut().int_unification_table.inlined_probe_value(v).is_some()
+                self.inner.borrow_mut().int_unification_table().inlined_probe_value(v).is_some()
             }
 
             TyOrConstInferVar::TyFloat(v) => {
@@ -1635,7 +1924,7 @@ pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>)
                 // `ty::Float(_)`, which never matches a `ty::Infer(_)`.
                 //
                 // Not `inlined_probe_value(v)` because this call site is colder.
-                self.inner.borrow_mut().float_unification_table.probe_value(v).is_some()
+                self.inner.borrow_mut().float_unification_table().probe_value(v).is_some()
             }
 
             TyOrConstInferVar::Const(v) => {
@@ -1718,7 +2007,7 @@ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
             self.infcx
                 .inner
                 .borrow_mut()
-                .const_unification_table
+                .const_unification_table()
                 .probe_value(*vid)
                 .val
                 .known()