hir_ty/next_solver/infer/snapshot/
mod.rs

1//! Snapshotting in the infer ctxt of the next-trait-solver.
2
3use ena::undo_log::UndoLogs;
4use rustc_type_ir::UniverseIndex;
5use tracing::{debug, instrument};
6
7use super::InferCtxt;
8use super::region_constraints::RegionSnapshot;
9
10pub(crate) mod undo_log;
11
12use undo_log::{Snapshot, UndoLog};
13
14#[must_use = "once you start a snapshot, you should always consume it"]
15pub struct CombinedSnapshot {
16    pub(super) undo_snapshot: Snapshot,
17    region_constraints_snapshot: RegionSnapshot,
18    universe: UniverseIndex,
19}
20
21struct VariableLengths {
22    region_constraints_len: usize,
23    type_var_len: usize,
24    int_var_len: usize,
25    float_var_len: usize,
26    const_var_len: usize,
27}
28
29impl<'db> InferCtxt<'db> {
30    fn variable_lengths(&self) -> VariableLengths {
31        let mut inner = self.inner.borrow_mut();
32        VariableLengths {
33            region_constraints_len: inner.unwrap_region_constraints().num_region_vars(),
34            type_var_len: inner.type_variables().num_vars(),
35            int_var_len: inner.int_unification_table().len(),
36            float_var_len: inner.float_unification_table().len(),
37            const_var_len: inner.const_unification_table().len(),
38        }
39    }
40
41    pub fn in_snapshot(&self) -> bool {
42        UndoLogs::<UndoLog<'db>>::in_snapshot(&self.inner.borrow_mut().undo_log)
43    }
44
45    pub fn num_open_snapshots(&self) -> usize {
46        UndoLogs::<UndoLog<'db>>::num_open_snapshots(&self.inner.borrow_mut().undo_log)
47    }
48
49    fn start_snapshot(&self) -> CombinedSnapshot {
50        debug!("start_snapshot()");
51
52        let mut inner = self.inner.borrow_mut();
53
54        CombinedSnapshot {
55            undo_snapshot: inner.undo_log.start_snapshot(),
56            region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
57            universe: self.universe(),
58        }
59    }
60
61    #[instrument(skip(self, snapshot), level = "debug")]
62    fn rollback_to(&self, snapshot: CombinedSnapshot) {
63        let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, universe } = snapshot;
64
65        self.universe.set(universe);
66
67        let mut inner = self.inner.borrow_mut();
68        inner.rollback_to(undo_snapshot);
69        inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot);
70    }
71
72    #[instrument(skip(self, snapshot), level = "debug")]
73    fn commit_from(&self, snapshot: CombinedSnapshot) {
74        let CombinedSnapshot { undo_snapshot, region_constraints_snapshot: _, universe: _ } =
75            snapshot;
76
77        self.inner.borrow_mut().commit(undo_snapshot);
78    }
79
80    /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`.
81    #[instrument(skip(self, f), level = "debug")]
82    pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
83    where
84        F: FnOnce(&CombinedSnapshot) -> Result<T, E>,
85    {
86        let snapshot = self.start_snapshot();
87        let r = f(&snapshot);
88        debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok());
89        match r {
90            Ok(_) => {
91                self.commit_from(snapshot);
92            }
93            Err(_) => {
94                self.rollback_to(snapshot);
95            }
96        }
97        r
98    }
99
100    /// Execute `f` then unroll any bindings it creates.
101    #[instrument(skip(self, f), level = "debug")]
102    pub fn probe<R, F>(&self, f: F) -> R
103    where
104        F: FnOnce(&CombinedSnapshot) -> R,
105    {
106        let snapshot = self.start_snapshot();
107        let r = f(&snapshot);
108        self.rollback_to(snapshot);
109        r
110    }
111}