diff --git a/src/librustc_infer/infer/fudge.rs b/src/librustc_infer/infer/fudge.rs index ccc4a73d40f..53fd70a28e8 100644 --- a/src/librustc_infer/infer/fudge.rs +++ b/src/librustc_infer/infer/fudge.rs @@ -82,7 +82,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { debug!("fudge_inference_if_ok()"); - let (mut fudger, value) = self.probe_full(|snapshot| { + let (mut fudger, value) = self.probe_fudge(|snapshot| { match f() { Ok(value) => { let value = self.resolve_vars_if_possible(&value); diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 67d330ac892..e92008c68eb 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -167,7 +167,7 @@ pub struct InferCtxtInner<'tcx> { /// `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>, + region_constraint_storage: Option>, /// A set of constraints that regionck must validate. Each /// constraint has the form `T:'a`, meaning "some type `T` must @@ -214,7 +214,7 @@ impl<'tcx> InferCtxtInner<'tcx> { const_unification_storage: ut::UnificationTableStorage::new(), int_unification_storage: ut::UnificationTableStorage::new(), float_unification_storage: ut::UnificationTableStorage::new(), - region_constraints: Some(RegionConstraintStorage::new()), + region_constraint_storage: Some(RegionConstraintStorage::new()), region_obligations: vec![], } } @@ -268,7 +268,7 @@ impl<'tcx> InferCtxtInner<'tcx> { } pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'tcx, '_> { - self.region_constraints + self.region_constraint_storage .as_mut() .expect("region constraints already solved") .with_log(&mut self.undo_log) @@ -705,8 +705,9 @@ impl<'tcx> InferOk<'tcx, ()> { } } +/// Extends `CombinedSnapshot` by tracking which variables were added in the snapshot #[must_use = "once you start a snapshot, you should always consume it"] -pub struct FullSnapshot<'a, 'tcx> { +pub struct FudgeSnapshot<'a, 'tcx> { snapshot: CombinedSnapshot<'a, 'tcx>, region_constraints_snapshot: RegionSnapshot, type_snapshot: type_variable::Snapshot<'tcx>, @@ -830,10 +831,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { result } - fn start_full_snapshot(&self) -> FullSnapshot<'a, 'tcx> { + fn start_fudge_snapshot(&self) -> FudgeSnapshot<'a, 'tcx> { let snapshot = self.start_snapshot(); let mut inner = self.inner.borrow_mut(); - FullSnapshot { + FudgeSnapshot { snapshot, type_snapshot: inner.type_variables().snapshot(), const_var_len: inner.const_unification_table().len(), @@ -925,12 +926,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { r } - pub fn probe_full(&self, f: F) -> R + /// Like `probe` but provides information about which variables were created in the snapshot, + /// allowing for inference fudging + pub fn probe_fudge(&self, f: F) -> R where - F: FnOnce(&FullSnapshot<'a, 'tcx>) -> R, + F: FnOnce(&FudgeSnapshot<'a, 'tcx>) -> R, { debug!("probe()"); - let snapshot = self.start_full_snapshot(); + let snapshot = self.start_fudge_snapshot(); let r = f(&snapshot); self.rollback_to("probe", snapshot.snapshot); r @@ -1294,7 +1297,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { inner.region_obligations ); inner - .region_constraints + .region_constraint_storage .take() .expect("regions already resolved") .with_log(&mut inner.undo_log) @@ -1362,7 +1365,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn take_region_var_origins(&self) -> VarInfos { let mut inner = self.inner.borrow_mut(); let (var_infos, data) = inner - .region_constraints + .region_constraint_storage .take() .expect("regions already resolved") .with_log(&mut inner.undo_log) diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs index 68f84d4d1c3..ed8ee3b655d 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -13,30 +13,35 @@ use std::ops::Range; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; +/// Represents a single undo-able action that affects a type inference variable. pub(crate) enum UndoLog<'tcx> { EqRelation(sv::UndoLog>>), SubRelation(sv::UndoLog>), Values(sv::UndoLog), } +/// Convert from a specific kind of undo to the more general UndoLog impl<'tcx> From>>> for UndoLog<'tcx> { fn from(l: sv::UndoLog>>) -> Self { UndoLog::EqRelation(l) } } +/// Convert from a specific kind of undo to the more general UndoLog impl<'tcx> From>> for UndoLog<'tcx> { fn from(l: sv::UndoLog>) -> Self { UndoLog::SubRelation(l) } } +/// Convert from a specific kind of undo to the more general UndoLog impl<'tcx> From> for UndoLog<'tcx> { fn from(l: sv::UndoLog) -> Self { UndoLog::Values(l) } } +/// Convert from a specific kind of undo to the more general UndoLog impl<'tcx> From for UndoLog<'tcx> { fn from(l: Instantiate) -> Self { UndoLog::Values(sv::UndoLog::Other(l)) diff --git a/src/librustc_infer/infer/undo_log.rs b/src/librustc_infer/infer/undo_log.rs index 2271da01526..56cb182dbf0 100644 --- a/src/librustc_infer/infer/undo_log.rs +++ b/src/librustc_infer/infer/undo_log.rs @@ -59,6 +59,7 @@ impl_from! { ProjectionCache(traits::UndoLog<'tcx>), } +/// The Rollback trait defines how to rollback a particular action. impl<'tcx> Rollback> for InferCtxtInner<'tcx> { fn reverse(&mut self, undo: UndoLog<'tcx>) { match undo { @@ -67,10 +68,10 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo), UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo), UndoLog::RegionConstraintCollector(undo) => { - self.region_constraints.as_mut().unwrap().reverse(undo) + self.region_constraint_storage.as_mut().unwrap().reverse(undo) } UndoLog::RegionUnificationTable(undo) => { - self.region_constraints.as_mut().unwrap().unification_table.reverse(undo) + self.region_constraint_storage.as_mut().unwrap().unification_table.reverse(undo) } UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo), UndoLog::PushRegionObligation => { @@ -80,6 +81,8 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { } } +/// The combined undo log for all the various unification tables. For each change to the storage +/// for any kind of inference variable, we record an UndoLog entry in the vector here. pub(crate) struct InferCtxtUndoLogs<'tcx> { logs: Vec>, num_open_snapshots: usize, @@ -91,6 +94,8 @@ impl Default for InferCtxtUndoLogs<'_> { } } +/// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any +/// action that is convertable into a UndoLog (per the From impls above). impl<'tcx, T> UndoLogs for InferCtxtUndoLogs<'tcx> where UndoLog<'tcx>: From, @@ -98,15 +103,18 @@ where 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(&mut self, undos: J) where Self: Sized, @@ -196,6 +204,7 @@ impl<'tcx> InferCtxtUndoLogs<'tcx> { impl<'tcx> std::ops::Index for InferCtxtUndoLogs<'tcx> { type Output = UndoLog<'tcx>; + fn index(&self, key: usize) -> &Self::Output { &self.logs[key] }