mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-05 03:23:25 +00:00
create but do not use a projection cache
This commit is contained in:
parent
d042ce2ed3
commit
21eb36608e
@ -106,6 +106,12 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
|
||||
pub tables: InferTables<'a, 'gcx, 'tcx>,
|
||||
|
||||
// Cache for projections. This cache is snapshotted along with the
|
||||
// infcx.
|
||||
//
|
||||
// Public so that `traits::project` can use it.
|
||||
pub projection_cache: RefCell<traits::ProjectionCache<'tcx>>,
|
||||
|
||||
// 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.
|
||||
@ -479,6 +485,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
|
||||
parameter_environment: param_env,
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
evaluation_cache: traits::EvaluationCache::new(),
|
||||
projection_cache: RefCell::new(traits::ProjectionCache::new()),
|
||||
reported_trait_errors: RefCell::new(FnvHashSet()),
|
||||
normalize: false,
|
||||
projection_mode: ProjectionMode::AnyFinal,
|
||||
@ -512,6 +519,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
|
||||
global_tcx.enter_local(arenas, |tcx| f(InferCtxt {
|
||||
tcx: tcx,
|
||||
tables: tables,
|
||||
projection_cache: RefCell::new(traits::ProjectionCache::new()),
|
||||
type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
|
||||
int_unification_table: RefCell::new(UnificationTable::new()),
|
||||
float_unification_table: RefCell::new(UnificationTable::new()),
|
||||
@ -547,6 +555,7 @@ impl<'tcx, T> InferOk<'tcx, T> {
|
||||
|
||||
#[must_use = "once you start a snapshot, you should always consume it"]
|
||||
pub struct CombinedSnapshot {
|
||||
projection_cache_snapshot: traits::ProjectionCacheSnapshot,
|
||||
type_snapshot: type_variable::Snapshot,
|
||||
int_snapshot: unify::Snapshot<ty::IntVid>,
|
||||
float_snapshot: unify::Snapshot<ty::FloatVid>,
|
||||
@ -827,6 +836,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
self.obligations_in_snapshot.set(false);
|
||||
|
||||
CombinedSnapshot {
|
||||
projection_cache_snapshot: self.projection_cache.borrow_mut().snapshot(),
|
||||
type_snapshot: self.type_variables.borrow_mut().snapshot(),
|
||||
int_snapshot: self.int_unification_table.borrow_mut().snapshot(),
|
||||
float_snapshot: self.float_unification_table.borrow_mut().snapshot(),
|
||||
@ -837,7 +847,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot) {
|
||||
debug!("rollback_to(cause={})", cause);
|
||||
let CombinedSnapshot { type_snapshot,
|
||||
let CombinedSnapshot { projection_cache_snapshot,
|
||||
type_snapshot,
|
||||
int_snapshot,
|
||||
float_snapshot,
|
||||
region_vars_snapshot,
|
||||
@ -846,6 +857,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
assert!(!self.obligations_in_snapshot.get());
|
||||
self.obligations_in_snapshot.set(obligations_in_snapshot);
|
||||
|
||||
self.projection_cache
|
||||
.borrow_mut()
|
||||
.rollback_to(projection_cache_snapshot);
|
||||
self.type_variables
|
||||
.borrow_mut()
|
||||
.rollback_to(type_snapshot);
|
||||
@ -861,7 +875,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn commit_from(&self, snapshot: CombinedSnapshot) {
|
||||
debug!("commit_from()");
|
||||
let CombinedSnapshot { type_snapshot,
|
||||
let CombinedSnapshot { projection_cache_snapshot,
|
||||
type_snapshot,
|
||||
int_snapshot,
|
||||
float_snapshot,
|
||||
region_vars_snapshot,
|
||||
@ -869,6 +884,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
self.obligations_in_snapshot.set(obligations_in_snapshot);
|
||||
|
||||
self.projection_cache
|
||||
.borrow_mut()
|
||||
.commit(projection_cache_snapshot);
|
||||
self.type_variables
|
||||
.borrow_mut()
|
||||
.commit(type_snapshot);
|
||||
@ -926,7 +944,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
F: FnOnce() -> Result<T, E>
|
||||
{
|
||||
debug!("commit_regions_if_ok()");
|
||||
let CombinedSnapshot { type_snapshot,
|
||||
let CombinedSnapshot { projection_cache_snapshot,
|
||||
type_snapshot,
|
||||
int_snapshot,
|
||||
float_snapshot,
|
||||
region_vars_snapshot,
|
||||
@ -941,6 +960,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Roll back any non-region bindings - they should be resolved
|
||||
// inside `f`, with, e.g. `resolve_type_vars_if_possible`.
|
||||
self.projection_cache
|
||||
.borrow_mut()
|
||||
.rollback_to(projection_cache_snapshot);
|
||||
self.type_variables
|
||||
.borrow_mut()
|
||||
.rollback_to(type_snapshot);
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Trait Resolution. See the Book for more.
|
||||
//! Trait Resolution. See README.md for an overview of how this works.
|
||||
|
||||
pub use self::SelectionError::*;
|
||||
pub use self::FulfillmentErrorCode::*;
|
||||
@ -30,8 +30,9 @@ pub use self::coherence::orphan_check;
|
||||
pub use self::coherence::overlapping_impls;
|
||||
pub use self::coherence::OrphanCheckErr;
|
||||
pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation};
|
||||
pub use self::project::{MismatchedProjectionTypes, ProjectionMode};
|
||||
pub use self::project::MismatchedProjectionTypes;
|
||||
pub use self::project::{normalize, normalize_projection_type, Normalized};
|
||||
pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, ProjectionMode};
|
||||
pub use self::object_safety::ObjectSafetyViolation;
|
||||
pub use self::object_safety::MethodViolationCode;
|
||||
pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
|
||||
|
@ -340,7 +340,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
|
||||
data.clone(),
|
||||
self.cause.clone(),
|
||||
self.depth);
|
||||
debug!("AssociatedTypeNormalizer: depth={} normalized {:?} to {:?} with {} add'l obligations",
|
||||
debug!("AssociatedTypeNormalizer: depth={} normalized {:?} to {:?} \
|
||||
with {} add'l obligations",
|
||||
self.depth, ty, normalized_ty, obligations.len());
|
||||
self.obligations.extend(obligations);
|
||||
normalized_ty
|
||||
@ -1237,3 +1238,91 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
|
||||
.next()
|
||||
}
|
||||
}
|
||||
|
||||
// # Cache
|
||||
|
||||
pub struct ProjectionCache<'tcx> {
|
||||
map: SnapshotMap<ty::ProjectionTy<'tcx>, ProjectionCacheEntry<'tcx>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum ProjectionCacheEntry<'tcx> {
|
||||
InProgress,
|
||||
Ambiguous,
|
||||
Error,
|
||||
NormalizedTy(Ty<'tcx>),
|
||||
}
|
||||
|
||||
// NB: intentionally not Clone
|
||||
pub struct ProjectionCacheSnapshot {
|
||||
snapshot: Snapshot
|
||||
}
|
||||
|
||||
impl<'tcx> ProjectionCache<'tcx> {
|
||||
pub fn new() -> Self {
|
||||
ProjectionCache {
|
||||
map: SnapshotMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/// Try to start normalize `key`; returns an error if
|
||||
/// normalization already occured (this error corresponds to a
|
||||
/// cache hit, so it's actually a good thing).
|
||||
fn try_start(&mut self, key: ty::ProjectionTy<'tcx>)
|
||||
-> Result<(), ProjectionCacheEntry<'tcx>> {
|
||||
match self.map.get(&key) {
|
||||
Some(entry) => return Err(entry.clone()),
|
||||
None => { }
|
||||
}
|
||||
|
||||
self.map.insert(key, ProjectionCacheEntry::InProgress);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Indicates that `key` was normalized to `value`. If `cacheable` is false,
|
||||
/// then this result is sadly not cacheable.
|
||||
fn complete(&mut self,
|
||||
key: ty::ProjectionTy<'tcx>,
|
||||
value: &NormalizedTy<'tcx>,
|
||||
cacheable: bool) {
|
||||
let fresh_key = if cacheable {
|
||||
debug!("ProjectionCacheEntry::complete: adding cache entry: key={:?}, value={:?}",
|
||||
key, value);
|
||||
self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.value))
|
||||
} else {
|
||||
debug!("ProjectionCacheEntry::complete: cannot cache: key={:?}, value={:?}",
|
||||
key, value);
|
||||
!self.map.remove(key)
|
||||
};
|
||||
|
||||
assert!(!fresh_key, "never started projecting `{:?}`", key);
|
||||
}
|
||||
|
||||
/// Indicates that trying to normalize `key` resulted in
|
||||
/// ambiguity. No point in trying it again then until we gain more
|
||||
/// type information (in which case, the "fully resolved" key will
|
||||
/// be different).
|
||||
fn ambiguous(&mut self, key: ty::ProjectionTy<'tcx>) {
|
||||
let fresh = self.map.insert(key, ProjectionCacheEntry::Ambiguous);
|
||||
assert!(!fresh, "never started projecting `{:?}`", key);
|
||||
}
|
||||
|
||||
/// Indicates that trying to normalize `key` resulted in
|
||||
/// error.
|
||||
fn error(&mut self, key: ty::ProjectionTy<'tcx>) {
|
||||
let fresh = self.map.insert(key, ProjectionCacheEntry::Error);
|
||||
assert!(!fresh, "never started projecting `{:?}`", key);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user