blob: fa813500c544ea7c17f3bbb93b13e40dba9335bd [file] [log] [blame]
use rustc_data_structures::undo_log::UndoLogs;
use rustc_middle::ty;
use tracing::{debug, instrument};
use super::InferCtxt;
use super::region_constraints::RegionSnapshot;
pub(crate) mod fudge;
pub(crate) mod undo_log;
use undo_log::{Snapshot, UndoLog};
#[must_use = "once you start a snapshot, you should always consume it"]
pub struct CombinedSnapshot<'tcx> {
pub(super) undo_snapshot: Snapshot<'tcx>,
region_constraints_snapshot: RegionSnapshot,
universe: ty::UniverseIndex,
}
struct VariableLengths {
region_constraints_len: usize,
type_var_len: usize,
int_var_len: usize,
float_var_len: usize,
const_var_len: usize,
effect_var_len: usize,
}
impl<'tcx> InferCtxt<'tcx> {
fn variable_lengths(&self) -> VariableLengths {
let mut inner = self.inner.borrow_mut();
VariableLengths {
region_constraints_len: inner.unwrap_region_constraints().num_region_vars(),
type_var_len: inner.type_variables().num_vars(),
int_var_len: inner.int_unification_table().len(),
float_var_len: inner.float_unification_table().len(),
const_var_len: inner.const_unification_table().len(),
effect_var_len: inner.effect_unification_table().len(),
}
}
pub fn in_snapshot(&self) -> bool {
UndoLogs::<UndoLog<'tcx>>::in_snapshot(&self.inner.borrow_mut().undo_log)
}
pub fn num_open_snapshots(&self) -> usize {
UndoLogs::<UndoLog<'tcx>>::num_open_snapshots(&self.inner.borrow_mut().undo_log)
}
fn start_snapshot(&self) -> CombinedSnapshot<'tcx> {
debug!("start_snapshot()");
let mut inner = self.inner.borrow_mut();
CombinedSnapshot {
undo_snapshot: inner.undo_log.start_snapshot(),
region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
universe: self.universe(),
}
}
#[instrument(skip(self, snapshot), level = "debug")]
fn rollback_to(&self, snapshot: CombinedSnapshot<'tcx>) {
let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, universe } = snapshot;
self.universe.set(universe);
let mut inner = self.inner.borrow_mut();
inner.rollback_to(undo_snapshot);
inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot);
}
#[instrument(skip(self, snapshot), level = "debug")]
fn commit_from(&self, snapshot: CombinedSnapshot<'tcx>) {
let CombinedSnapshot { undo_snapshot, region_constraints_snapshot: _, universe: _ } =
snapshot;
self.inner.borrow_mut().commit(undo_snapshot);
}
/// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`.
#[instrument(skip(self, f), level = "debug")]
pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
where
F: FnOnce(&CombinedSnapshot<'tcx>) -> Result<T, E>,
{
let snapshot = self.start_snapshot();
let r = f(&snapshot);
debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok());
match r {
Ok(_) => {
self.commit_from(snapshot);
}
Err(_) => {
self.rollback_to(snapshot);
}
}
r
}
/// Execute `f` then unroll any bindings it creates.
#[instrument(skip(self, f), level = "debug")]
pub fn probe<R, F>(&self, f: F) -> R
where
F: FnOnce(&CombinedSnapshot<'tcx>) -> R,
{
let snapshot = self.start_snapshot();
let r = f(&snapshot);
self.rollback_to(snapshot);
r
}
/// Scan the constraints produced since `snapshot` and check whether
/// we added any region constraints.
pub fn region_constraints_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'tcx>) -> bool {
self.inner
.borrow_mut()
.unwrap_region_constraints()
.region_constraints_added_in_snapshot(&snapshot.undo_snapshot)
}
pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'tcx>) -> bool {
self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
}
}