diff --git a/Cargo.lock b/Cargo.lock index 45c298ea8bf..c5e25b0a2c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -485,7 +485,7 @@ version = "0.0.212" dependencies = [ "cargo_metadata 0.9.1", "if_chain", - "itertools 0.9.0", + "itertools 0.8.0", "lazy_static 1.4.0", "pulldown-cmark 0.7.1", "quine-mc_cluskey", @@ -1629,15 +1629,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "0.4.4" @@ -2188,7 +2179,6 @@ dependencies = [ "rustc-workspace-hack", "rustc_version", "serde", - "serde_json", "shell-escape", "vergen", ] diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index 81b4c35aa1a..fe3c5a8afc9 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -1,5 +1,6 @@ use crate::fx::FxHashMap; use crate::undo_log::{Rollback, Snapshots, UndoLogs, VecLog}; +use std::borrow::{Borrow, BorrowMut}; use std::hash::Hash; use std::marker::PhantomData; use std::ops; @@ -10,6 +11,7 @@ pub use crate::undo_log::Snapshot; mod tests; pub type SnapshotMapStorage = SnapshotMap, ()>; +pub type SnapshotMapRef<'a, K, V, L> = SnapshotMap, &'a mut L>; pub struct SnapshotMap, L = VecLog>> { map: M, @@ -43,16 +45,16 @@ impl SnapshotMap { impl SnapshotMap where K: Hash + Clone + Eq, - M: AsMut> + AsRef>, + M: BorrowMut> + Borrow>, L: UndoLogs>, { pub fn clear(&mut self) { - self.map.as_mut().clear(); + self.map.borrow_mut().clear(); self.undo_log.clear(); } pub fn insert(&mut self, key: K, value: V) -> bool { - match self.map.as_mut().insert(key.clone(), value) { + match self.map.borrow_mut().insert(key.clone(), value) { None => { self.undo_log.push(UndoLog::Inserted(key)); true @@ -65,7 +67,7 @@ where } pub fn remove(&mut self, key: K) -> bool { - match self.map.as_mut().remove(&key) { + match self.map.borrow_mut().remove(&key) { Some(old_value) => { self.undo_log.push(UndoLog::Overwrite(key, old_value)); true @@ -75,7 +77,7 @@ where } pub fn get(&self, key: &K) -> Option<&V> { - self.map.as_ref().get(key) + self.map.borrow().get(key) } } @@ -99,11 +101,21 @@ where impl<'k, K, V, M, L> ops::Index<&'k K> for SnapshotMap where K: Hash + Clone + Eq, - M: AsRef>, + M: Borrow>, { type Output = V; fn index(&self, key: &'k K) -> &V { - &self.map.as_ref()[key] + &self.map.borrow()[key] + } +} + +impl Rollback> for SnapshotMap +where + K: Eq + Hash, + M: Rollback>, +{ + fn reverse(&mut self, undo: UndoLog) { + self.map.reverse(undo) } } diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index eabb513d2d3..685dc1ab8a4 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -141,7 +141,7 @@ pub struct InferCtxtInner<'tcx> { /// Cache for projections. This cache is snapshotted along with the infcx. /// /// Public so that `traits::project` can use it. - pub projection_cache: traits::ProjectionCache<'tcx>, + pub projection_cache: traits::ProjectionCacheStorage<'tcx>, /// We instantiate `UnificationTable` with `bounds` because the types /// that might instantiate a general type variable have an order, @@ -213,6 +213,10 @@ impl<'tcx> InferCtxtInner<'tcx> { } } + pub(crate) 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) } @@ -265,6 +269,7 @@ pub(crate) enum UndoLog<'tcx> { FloatUnificationTable(sv::UndoLog>), RegionConstraintCollector(region_constraints::UndoLog<'tcx>), RegionUnificationTable(sv::UndoLog>), + ProjectionCache(traits::UndoLog<'tcx>), } impl<'tcx> From> for UndoLog<'tcx> { @@ -327,6 +332,12 @@ impl<'tcx> From>> for UndoLog<'tcx> { } } +impl<'tcx> From> for UndoLog<'tcx> { + fn from(l: traits::UndoLog<'tcx>) -> Self { + Self::ProjectionCache(l) + } +} + pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable, &'a mut Logs<'tcx>>>; @@ -336,6 +347,7 @@ struct RollbackView<'tcx, 'a> { int_unification_table: &'a mut ut::UnificationStorage, float_unification_table: &'a mut ut::UnificationStorage, region_constraints: &'a mut RegionConstraintStorage<'tcx>, + projection_cache: &'a mut traits::ProjectionCacheStorage<'tcx>, } impl<'tcx> Rollback> for RollbackView<'tcx, '_> { @@ -349,6 +361,7 @@ impl<'tcx> Rollback> for RollbackView<'tcx, '_> { UndoLog::RegionUnificationTable(undo) => { self.region_constraints.unification_table.reverse(undo) } + UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo), } } } @@ -885,7 +898,6 @@ impl<'tcx> InferOk<'tcx, ()> { #[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot<'a, 'tcx> { - projection_cache_snapshot: traits::ProjectionCacheSnapshot, undo_snapshot: Snapshot<'tcx>, type_snapshot: type_variable::Snapshot<'tcx>, const_snapshot: usize, @@ -1016,7 +1028,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { inner.undo_log.num_open_snapshots += 1; let undo_snapshot = Snapshot { undo_len: inner.undo_log.logs.len(), _marker: PhantomData }; CombinedSnapshot { - projection_cache_snapshot: inner.projection_cache.snapshot(), undo_snapshot, type_snapshot: inner.type_variables().snapshot(), const_snapshot: inner.const_unification_table().len(), @@ -1036,7 +1047,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("rollback_to(cause={})", cause); let CombinedSnapshot { - projection_cache_snapshot, undo_snapshot, type_snapshot: _, const_snapshot: _, @@ -1062,6 +1072,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { int_unification_table, float_unification_table, region_constraints, + projection_cache, .. } = inner; inner.undo_log.rollback_to( @@ -1071,17 +1082,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { int_unification_table, float_unification_table, region_constraints: region_constraints.as_mut().unwrap(), + projection_cache, }, undo_snapshot, ); - inner.projection_cache.rollback_to(projection_cache_snapshot); inner.region_obligations.truncate(region_obligations_snapshot); } fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("commit_from()"); let CombinedSnapshot { - projection_cache_snapshot, undo_snapshot, type_snapshot: _, const_snapshot: _, @@ -1100,7 +1110,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut inner = self.inner.borrow_mut(); inner.undo_log.commit(undo_snapshot); - inner.projection_cache.commit(projection_cache_snapshot); } /// Executes `f` and commit the bindings. @@ -1773,7 +1782,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn clear_caches(&self) { self.selection_cache.clear(); self.evaluation_cache.clear(); - self.inner.borrow_mut().projection_cache.clear(); + self.inner.borrow_mut().projection_cache().clear(); } fn universe(&self) -> ty::UniverseIndex { diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index 2210c663d14..640ea7774cd 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -20,6 +20,7 @@ pub use self::Vtable::*; pub use self::engine::{TraitEngine, TraitEngineExt}; pub use self::project::MismatchedProjectionTypes; +pub(crate) use self::project::UndoLog; pub use self::project::{ Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, ProjectionCacheSnapshot, Reveal, diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs index 17105f99ac0..0c51dafef6f 100644 --- a/src/librustc_infer/traits/project.rs +++ b/src/librustc_infer/traits/project.rs @@ -8,6 +8,9 @@ use rustc_middle::ty::{self, Ty}; pub use rustc_middle::traits::Reveal; +pub(crate) type UndoLog<'tcx> = + snapshot_map::UndoLog, ProjectionCacheEntry<'tcx>>; + #[derive(Clone)] pub struct MismatchedProjectionTypes<'tcx> { pub err: ty::error::TypeError<'tcx>, @@ -58,9 +61,14 @@ impl<'tcx, T> Normalized<'tcx, T> { // // FIXME: we probably also want some sort of cross-infcx cache here to // reduce the amount of duplication. Let's see what we get with the Chalk reforms. +pub struct ProjectionCache<'tcx, 'a> { + map: &'a mut SnapshotMapStorage, ProjectionCacheEntry<'tcx>>, + undo_log: &'a mut Logs<'tcx>, +} + #[derive(Default)] -pub struct ProjectionCache<'tcx> { - map: SnapshotMap, ProjectionCacheEntry<'tcx>>, +pub struct ProjectionCacheStorage<'tcx> { + map: SnapshotMapStorage, ProjectionCacheEntry<'tcx>>, } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -82,26 +90,24 @@ pub enum ProjectionCacheEntry<'tcx> { NormalizedTy(NormalizedTy<'tcx>), } -// N.B., intentionally not Clone -pub struct ProjectionCacheSnapshot { - snapshot: Snapshot, +impl<'tcx> ProjectionCacheStorage<'tcx> { + pub(crate) fn with_log<'a>( + &'a mut self, + undo_log: &'a mut Logs<'tcx>, + ) -> ProjectionCache<'tcx, 'a> { + ProjectionCache { map: &mut self.map, undo_log } + } } -impl<'tcx> ProjectionCache<'tcx> { +impl<'tcx> ProjectionCache<'tcx, '_> { + fn map( + &mut self, + ) -> SnapshotMapRef<'_, ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>, Logs<'tcx>> { + self.map.with_log(self.undo_log) + } + pub fn clear(&mut self) { - self.map.clear(); - } - - pub fn snapshot(&mut self) -> ProjectionCacheSnapshot { - ProjectionCacheSnapshot { snapshot: self.map.snapshot() } - } - - pub fn rollback_to(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.rollback_to(snapshot.snapshot); - } - - pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.commit(snapshot.snapshot); + self.map().clear(); } /// Try to start normalize `key`; returns an error if @@ -111,11 +117,12 @@ impl<'tcx> ProjectionCache<'tcx> { &mut self, key: ProjectionCacheKey<'tcx>, ) -> Result<(), ProjectionCacheEntry<'tcx>> { - if let Some(entry) = self.map.get(&key) { + let mut map = self.map(); + if let Some(entry) = map.get(&key) { return Err(entry.clone()); } - self.map.insert(key, ProjectionCacheEntry::InProgress); + map.insert(key, ProjectionCacheEntry::InProgress); Ok(()) } @@ -125,7 +132,7 @@ impl<'tcx> ProjectionCache<'tcx> { "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", key, value ); - let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value)); + let fresh_key = self.map().insert(key, ProjectionCacheEntry::NormalizedTy(value)); assert!(!fresh_key, "never started projecting `{:?}`", key); } @@ -134,7 +141,8 @@ impl<'tcx> ProjectionCache<'tcx> { /// snapshot - if the snapshot is rolled back, the obligations will be /// marked as incomplete again). pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) { - let ty = match self.map.get(&key) { + let mut map = self.map(); + let ty = match map.get(&key) { Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => { debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); ty.value @@ -147,7 +155,7 @@ impl<'tcx> ProjectionCache<'tcx> { } }; - self.map.insert( + map.insert( key, ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }), ); @@ -159,7 +167,7 @@ impl<'tcx> ProjectionCache<'tcx> { // We want to insert `ty` with no obligations. If the existing value // already has no obligations (as is common) we don't insert anything. if !ty.obligations.is_empty() { - self.map.insert( + self.map().insert( key, ProjectionCacheEntry::NormalizedTy(Normalized { value: ty.value, @@ -174,14 +182,20 @@ impl<'tcx> ProjectionCache<'tcx> { /// type information (in which case, the "fully resolved" key will /// be different). pub fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) { - let fresh = self.map.insert(key, ProjectionCacheEntry::Ambiguous); + let fresh = self.map().insert(key, ProjectionCacheEntry::Ambiguous); assert!(!fresh, "never started projecting `{:?}`", key); } /// Indicates that trying to normalize `key` resulted in /// error. pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) { - let fresh = self.map.insert(key, ProjectionCacheEntry::Error); + let fresh = self.map().insert(key, ProjectionCacheEntry::Error); assert!(!fresh, "never started projecting `{:?}`", key); } } + +impl<'tcx> Rollback> for ProjectionCacheStorage<'tcx> { + fn reverse(&mut self, undo: UndoLog<'tcx>) { + self.map.reverse(undo); + } +} diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index dfbb0742448..38590abf1f7 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -471,7 +471,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(key) = ProjectionCacheKey::from_poly_projection_predicate(self, data) { - self.infcx.inner.borrow_mut().projection_cache.complete(key); + self.infcx.inner.borrow_mut().projection_cache().complete(key); } result }