Move projection_cache into the combined undo log

This commit is contained in:
Markus Westerlind 2020-02-25 13:08:38 +01:00
parent c50fc6e113
commit 0c5d833812
6 changed files with 80 additions and 54 deletions

View File

@ -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",
]

View File

@ -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<K, V> = SnapshotMap<K, V, FxHashMap<K, V>, ()>;
pub type SnapshotMapRef<'a, K, V, L> = SnapshotMap<K, V, &'a mut FxHashMap<K, V>, &'a mut L>;
pub struct SnapshotMap<K, V, M = FxHashMap<K, V>, L = VecLog<UndoLog<K, V>>> {
map: M,
@ -43,16 +45,16 @@ impl<K, V, M, L> SnapshotMap<K, V, M, L> {
impl<K, V, M, L> SnapshotMap<K, V, M, L>
where
K: Hash + Clone + Eq,
M: AsMut<FxHashMap<K, V>> + AsRef<FxHashMap<K, V>>,
M: BorrowMut<FxHashMap<K, V>> + Borrow<FxHashMap<K, V>>,
L: UndoLogs<UndoLog<K, V>>,
{
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<K, V, M, L>
where
K: Hash + Clone + Eq,
M: AsRef<FxHashMap<K, V>>,
M: Borrow<FxHashMap<K, V>>,
{
type Output = V;
fn index(&self, key: &'k K) -> &V {
&self.map.as_ref()[key]
&self.map.borrow()[key]
}
}
impl<K, V, M, L> Rollback<UndoLog<K, V>> for SnapshotMap<K, V, M, L>
where
K: Eq + Hash,
M: Rollback<UndoLog<K, V>>,
{
fn reverse(&mut self, undo: UndoLog<K, V>) {
self.map.reverse(undo)
}
}

View File

@ -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<Ty>` 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<ut::Delegate<ty::FloatVid>>),
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>),
ProjectionCache(traits::UndoLog<'tcx>),
}
impl<'tcx> From<region_constraints::UndoLog<'tcx>> for UndoLog<'tcx> {
@ -327,6 +332,12 @@ impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::RegionVid>>> for UndoLog<'tcx> {
}
}
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>>>;
@ -336,6 +347,7 @@ struct RollbackView<'tcx, 'a> {
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>,
}
impl<'tcx> Rollback<UndoLog<'tcx>> for RollbackView<'tcx, '_> {
@ -349,6 +361,7 @@ impl<'tcx> Rollback<UndoLog<'tcx>> 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 {

View File

@ -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,

View File

@ -8,6 +8,9 @@ use rustc_middle::ty::{self, Ty};
pub use rustc_middle::traits::Reveal;
pub(crate) type UndoLog<'tcx> =
snapshot_map::UndoLog<ProjectionCacheKey<'tcx>, 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<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>,
undo_log: &'a mut Logs<'tcx>,
}
#[derive(Default)]
pub struct ProjectionCache<'tcx> {
map: SnapshotMap<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>,
pub struct ProjectionCacheStorage<'tcx> {
map: SnapshotMapStorage<ProjectionCacheKey<'tcx>, 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<UndoLog<'tcx>> for ProjectionCacheStorage<'tcx> {
fn reverse(&mut self, undo: UndoLog<'tcx>) {
self.map.reverse(undo);
}
}

View File

@ -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
}