]> git.lizzy.rs Git - rust.git/commitdiff
create but do not use a projection cache
authorNiko Matsakis <niko@alum.mit.edu>
Sat, 21 May 2016 12:18:52 +0000 (08:18 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 31 May 2016 23:44:43 +0000 (19:44 -0400)
src/librustc/infer/mod.rs
src/librustc/traits/mod.rs
src/librustc/traits/project.rs

index ab9c056644571206929dca012bb067c2df809f56..8e3d63508bfc5b0577b2c80ea6aaecbeb96e6ce0 100644 (file)
@@ -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 @@ pub fn borrowck_fake_infer_ctxt(self, param_env: ty::ParameterEnvironment<'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 @@ pub fn enter<F, R>(&'tcx mut self, f: F) -> R
         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 @@ pub fn unit(self) -> InferOk<'tcx, ()> {
 
 #[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 @@ fn start_snapshot(&self) -> CombinedSnapshot {
         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 @@ fn start_snapshot(&self) -> CombinedSnapshot {
 
     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 @@ fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot) {
         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 @@ fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot) {
 
     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 @@ fn commit_from(&self, snapshot: CombinedSnapshot) {
 
         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 @@ pub fn commit_regions_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
         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 @@ pub fn commit_regions_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
 
         // 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);
index c177ec4dbede7bcfc81ec845d5cff766d41b01b6..5b363d90578b1e7c2d996c904bc5bd5b468f1af7 100644 (file)
@@ -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::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};
index 011662fe8c2de5bbbc47e8f5fe27e67b43eb2e4b..7eb44d0e79e8ee34668692d04eb0f9d2c658048c 100644 (file)
@@ -340,7 +340,8 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                                               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);
+    }
+}