pub use self::SubregionOrigin::*;
pub use self::ValuePairs::*;
+pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
+
use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
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::undo_log::Rollback;
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;
pub mod resolve;
mod sub;
pub mod type_variable;
+mod undo_log;
use crate::infer::canonical::OriginalQueryValues;
pub use rustc_middle::infer::unify_key;
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result"
+pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
+ ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'tcx>>,
+>;
+
/// How we should handle region solving.
///
/// This is used so that the region values inferred by HIR region solving are
/// 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::TypeVariableStorage<'tcx>,
- undo_log: Logs<'tcx>,
+ type_variable_storage: type_variable::TypeVariableStorage<'tcx>,
/// Map from const parameter variable to the kind of const it represents.
- const_unification_table: ut::UnificationStorage<ty::ConstVid<'tcx>>,
+ const_unification_storage: ut::UnificationTableStorage<ty::ConstVid<'tcx>>,
/// Map from integral variable to the kind of integer it represents.
- int_unification_table: ut::UnificationStorage<ty::IntVid>,
+ int_unification_storage: ut::UnificationTableStorage<ty::IntVid>,
/// Map from floating variable to the kind of float it represents.
- float_unification_table: ut::UnificationStorage<ty::FloatVid>,
+ float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
/// Tracks the set of region variables and the constraints between them.
/// This is initially `Some(_)` but when
/// obligations within. This is expected to be done 'late enough'
/// that all type inference variables have been bound and so forth.
region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>,
+
+ undo_log: InferCtxtUndoLogs<'tcx>,
}
impl<'tcx> InferCtxtInner<'tcx> {
fn new() -> InferCtxtInner<'tcx> {
InferCtxtInner {
projection_cache: Default::default(),
- 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(),
+ type_variable_storage: type_variable::TypeVariableStorage::new(),
+ undo_log: InferCtxtUndoLogs::default(),
+ const_unification_storage: ut::UnificationTableStorage::new(),
+ int_unification_storage: ut::UnificationTableStorage::new(),
+ float_unification_storage: ut::UnificationTableStorage::new(),
region_constraints: Some(RegionConstraintStorage::new()),
region_obligations: vec![],
}
&self.region_obligations
}
- pub(crate) fn projection_cache(&mut self) -> traits::ProjectionCache<'tcx, '_> {
+ pub 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 type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> {
+ self.type_variable_storage.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::InPlace<
+ ty::IntVid,
+ &mut ut::UnificationStorage<ty::IntVid>,
+ &mut InferCtxtUndoLogs<'tcx>,
+ >,
> {
- ut::UnificationTable::with_log(&mut self.int_unification_table, &mut self.undo_log)
+ self.int_unification_storage.with_log(&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::InPlace<
+ ty::FloatVid,
+ &mut ut::UnificationStorage<ty::FloatVid>,
+ &mut InferCtxtUndoLogs<'tcx>,
+ >,
> {
- ut::UnificationTable::with_log(&mut self.float_unification_table, &mut self.undo_log)
+ self.float_unification_storage.with_log(&mut self.undo_log)
}
fn const_unification_table(
ut::InPlace<
ty::ConstVid<'tcx>,
&mut ut::UnificationStorage<ty::ConstVid<'tcx>>,
- &mut Logs<'tcx>,
+ &mut InferCtxtUndoLogs<'tcx>,
>,
> {
- ut::UnificationTable::with_log(&mut self.const_unification_table, &mut self.undo_log)
+ self.const_unification_storage.with_log(&mut self.undo_log)
}
pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'tcx, '_> {
}
}
-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>),
- PushRegionObligation,
-}
-
-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>,
- region_obligations: &'a mut Vec<(hir::HirId, RegionObligation<'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),
- UndoLog::PushRegionObligation => {
- self.region_obligations.pop();
- }
- }
- }
-}
-
-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);
- }
-}
-
pub struct InferCtxt<'a, 'tcx> {
pub tcx: TyCtxt<'tcx>,
snapshot: CombinedSnapshot<'a, 'tcx>,
region_constraints_snapshot: RegionSnapshot,
type_snapshot: type_variable::Snapshot<'tcx>,
- const_snapshot: usize,
- int_snapshot: usize,
- float_snapshot: usize,
+ const_var_len: usize,
+ int_var_len: usize,
+ float_var_len: usize,
}
#[must_use = "once you start a snapshot, you should always consume it"]
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(),
+ const_var_len: inner.const_unification_table().len(),
+ int_var_len: inner.int_unification_table().len(),
+ float_var_len: inner.float_unification_table().len(),
region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
}
}
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 {
- undo_snapshot,
+ undo_snapshot: inner.undo_log.start_snapshot(),
universe: self.universe(),
was_in_snapshot: in_snapshot,
// Borrow tables "in progress" (i.e., during typeck)
self.in_snapshot.set(was_in_snapshot);
self.universe.set(universe);
- 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,
- region_obligations,
- },
- undo_snapshot,
- );
+ self.inner.borrow_mut().rollback_to(undo_snapshot);
}
fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
self.in_snapshot.set(was_in_snapshot);
- let mut inner = self.inner.borrow_mut();
- inner.undo_log.commit(undo_snapshot);
+ self.inner.borrow_mut().commit(undo_snapshot);
}
/// Executes `f` and commit the bindings.
outlives_env: &OutlivesEnvironment<'tcx>,
mode: RegionckMode,
) {
- assert!(
- self.is_tainted_by_errors() || self.inner.borrow().region_obligations.is_empty(),
- "region_obligations not empty: {:#?}",
- self.inner.borrow().region_obligations
- );
- let (var_infos, data) = self
- .inner
- .borrow_mut()
- .region_constraints
- .take()
- .expect("regions already resolved")
- .with_log(&mut inner.undo_log)
- .into_infos_and_data();
+ let (var_infos, data) = {
+ let mut inner = self.inner.borrow_mut();
+ let inner = &mut *inner;
+ assert!(
+ self.is_tainted_by_errors() || inner.region_obligations.is_empty(),
+ "region_obligations not empty: {:#?}",
+ inner.region_obligations
+ );
+ inner
+ .region_constraints
+ .take()
+ .expect("regions already resolved")
+ .with_log(&mut inner.undo_log)
+ .into_infos_and_data()
+ };
let region_rels = &RegionRelations::new(
self.tcx,
/// having to resort to storing full `GenericArg`s in `stalled_on`.
#[inline(always)]
pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool {
+ let mut inner = self.inner.borrow_mut();
match infer_var {
TyOrConstInferVar::Ty(v) => {
use self::type_variable::TypeVariableValue;
// 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 inner.type_variables().inlined_probe(v) {
TypeVariableValue::Unknown { .. } => false,
TypeVariableValue::Known { .. } => true,
}
// 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()
+ inner.int_unification_table().inlined_probe_value(v).is_some()
}
TyOrConstInferVar::TyFloat(v) => {
// `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()
+ inner.float_unification_table().probe_value(v).is_some()
}
TyOrConstInferVar::Const(v) => {
// `ty::ConstKind::Infer(ty::InferConst::Var(v))`.
//
// Not `inlined_probe_value(v)` because this call site is colder.
- match self.inner.borrow_mut().const_unification_table.probe_value(v).val {
+ match inner.const_unification_table().probe_value(v).val {
ConstVariableValue::Unknown { .. } => false,
ConstVariableValue::Known { .. } => true,
}