+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>>),
+}
+
+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)
+ }
+}
+
+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>,
+}
+
+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),
+ }
+ }
+}
+
+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 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(&mut self, values: &mut impl Rollback<UndoLog<'tcx>>, snapshot: Self::Snapshot) {
+ debug!("rollback_to({})", snapshot.undo_len);
+ self.assert_open_snapshot(&snapshot);
+
+ 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> {
+ 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);
+ }
+}
+