about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2020-02-11 19:46:31 +0100
committerCamille GILLOT <gillot.camille@gmail.com>2020-03-14 14:15:14 +0100
commit21d4e063bca7d9f5a5d0f705e0f11092cbf2cf98 (patch)
tree1952fcac5d74ea23eebbc8e2a7e89ea6106da38d
parent796ca64e9ad95a8cba0f2ab8d252fb4c5b5fb9b4 (diff)
downloadrust-21d4e063bca7d9f5a5d0f705e0f11092cbf2cf98.tar.gz
rust-21d4e063bca7d9f5a5d0f705e0f11092cbf2cf98.zip
Mode ProjectionCache to its own module.
-rw-r--r--src/librustc_infer/traits/mod.rs8
-rw-r--r--src/librustc_infer/traits/project.rs180
-rw-r--r--src/librustc_infer/traits/projection_cache.rs185
-rw-r--r--src/librustc_infer/traits/query/normalize.rs2
-rw-r--r--src/librustc_infer/traits/select.rs5
-rw-r--r--src/librustc_infer/traits/structural_impls.rs2
6 files changed, 198 insertions, 184 deletions
diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs
index aa0cfedff9e..9f7d019e8fd 100644
--- a/src/librustc_infer/traits/mod.rs
+++ b/src/librustc_infer/traits/mod.rs
@@ -13,6 +13,7 @@ pub mod misc;
 mod object_safety;
 mod on_unimplemented;
 mod project;
+mod projection_cache;
 pub mod query;
 mod select;
 mod specialize;
@@ -49,11 +50,14 @@ pub use self::object_safety::is_vtable_safe_method;
 pub use self::object_safety::MethodViolationCode;
 pub use self::object_safety::ObjectSafetyViolation;
 pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
-pub use self::project::MismatchedProjectionTypes;
 pub use self::project::{
     normalize, normalize_projection_type, normalize_to, poly_project_and_unify_type,
 };
-pub use self::project::{Normalized, ProjectionCache, ProjectionCacheSnapshot, Reveal};
+pub use self::projection_cache::MismatchedProjectionTypes;
+pub use self::projection_cache::{
+    Normalized, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, ProjectionCacheSnapshot,
+    Reveal,
+};
 pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
 pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
 pub use self::specialize::find_associated_item;
diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs
index 78483cf6577..551b8618af1 100644
--- a/src/librustc_infer/traits/project.rs
+++ b/src/librustc_infer/traits/project.rs
@@ -1,15 +1,18 @@
 //! Code for projecting associated types out of trait references.
 
 use super::elaborate_predicates;
+use super::projection_cache::NormalizedTy;
 use super::specialization_graph;
 use super::translate_substs;
 use super::util;
+use super::MismatchedProjectionTypes;
 use super::Obligation;
 use super::ObligationCause;
 use super::PredicateObligation;
 use super::Selection;
 use super::SelectionContext;
 use super::SelectionError;
+use super::{Normalized, ProjectionCacheEntry, ProjectionCacheKey};
 use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData};
 
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -18,7 +21,6 @@ use rustc::ty::fold::{TypeFoldable, TypeFolder};
 use rustc::ty::subst::{InternalSubsts, Subst};
 use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_ast::ast::Ident;
-use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
 use rustc_hir::def_id::DefId;
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
@@ -41,11 +43,6 @@ pub enum ProjectionTyError<'tcx> {
     TraitSelectionError(SelectionError<'tcx>),
 }
 
-#[derive(Clone)]
-pub struct MismatchedProjectionTypes<'tcx> {
-    pub err: ty::error::TypeError<'tcx>,
-}
-
 #[derive(PartialEq, Eq, Debug)]
 enum ProjectionTyCandidate<'tcx> {
     // from a where-clause in the env or object type
@@ -393,20 +390,6 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
     }
 }
 
-#[derive(Clone, TypeFoldable)]
-pub struct Normalized<'tcx, T> {
-    pub value: T,
-    pub obligations: Vec<PredicateObligation<'tcx>>,
-}
-
-pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>;
-
-impl<'tcx, T> Normalized<'tcx, T> {
-    pub fn with<U>(self, value: U) -> Normalized<'tcx, U> {
-        Normalized { value, obligations: self.obligations }
-    }
-}
-
 /// The guts of `normalize`: normalize a specific projection like `<T
 /// as Trait>::Item`. The result is always a type (and possibly
 /// additional obligations). If ambiguity arises, which implies that
@@ -1500,47 +1483,6 @@ fn assoc_ty_def(
     }
 }
 
-// # Cache
-
-/// The projection cache. Unlike the standard caches, this can include
-/// infcx-dependent type variables, therefore we have to roll the
-/// cache back each time we roll a snapshot back, to avoid assumptions
-/// on yet-unresolved inference variables. Types with placeholder
-/// regions also have to be removed when the respective snapshot ends.
-///
-/// Because of that, projection cache entries can be "stranded" and left
-/// inaccessible when type variables inside the key are resolved. We make no
-/// attempt to recover or remove "stranded" entries, but rather let them be
-/// (for the lifetime of the infcx).
-///
-/// Entries in the projection cache might contain inference variables
-/// that will be resolved by obligations on the projection cache entry (e.g.,
-/// when a type parameter in the associated type is constrained through
-/// an "RFC 447" projection on the impl).
-///
-/// When working with a fulfillment context, the derived obligations of each
-/// projection cache entry will be registered on the fulfillcx, so any users
-/// that can wait for a fulfillcx fixed point need not care about this. However,
-/// users that don't wait for a fixed point (e.g., trait evaluation) have to
-/// resolve the obligations themselves to make sure the projected result is
-/// ok and avoid issues like #43132.
-///
-/// If that is done, after evaluation the obligations, it is a good idea to
-/// call `ProjectionCache::complete` to make sure the obligations won't be
-/// re-evaluated and avoid an exponential worst-case.
-//
-// 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.
-#[derive(Default)]
-pub struct ProjectionCache<'tcx> {
-    map: SnapshotMap<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>,
-}
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub struct ProjectionCacheKey<'tcx> {
-    ty: ty::ProjectionTy<'tcx>,
-}
-
 impl<'cx, 'tcx> ProjectionCacheKey<'tcx> {
     pub fn from_poly_projection_predicate(
         selcx: &mut SelectionContext<'cx, 'tcx>,
@@ -1558,119 +1500,3 @@ impl<'cx, 'tcx> ProjectionCacheKey<'tcx> {
         })
     }
 }
-
-#[derive(Clone, Debug)]
-enum ProjectionCacheEntry<'tcx> {
-    InProgress,
-    Ambiguous,
-    Error,
-    NormalizedTy(NormalizedTy<'tcx>),
-}
-
-// N.B., intentionally not Clone
-pub struct ProjectionCacheSnapshot {
-    snapshot: Snapshot,
-}
-
-impl<'tcx> ProjectionCache<'tcx> {
-    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 rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) {
-        self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_placeholders());
-    }
-
-    pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) {
-        self.map.commit(snapshot.snapshot);
-    }
-
-    /// Try to start normalize `key`; returns an error if
-    /// normalization already occurred (this error corresponds to a
-    /// cache hit, so it's actually a good thing).
-    fn try_start(
-        &mut self,
-        key: ProjectionCacheKey<'tcx>,
-    ) -> Result<(), ProjectionCacheEntry<'tcx>> {
-        if let Some(entry) = self.map.get(&key) {
-            return Err(entry.clone());
-        }
-
-        self.map.insert(key, ProjectionCacheEntry::InProgress);
-        Ok(())
-    }
-
-    /// Indicates that `key` was normalized to `value`.
-    fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) {
-        debug!(
-            "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
-            key, value
-        );
-        let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value));
-        assert!(!fresh_key, "never started projecting `{:?}`", key);
-    }
-
-    /// Mark the relevant projection cache key as having its derived obligations
-    /// complete, so they won't have to be re-computed (this is OK to do in a
-    /// 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) {
-            Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => {
-                debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
-                ty.value
-            }
-            ref value => {
-                // Type inference could "strand behind" old cache entries. Leave
-                // them alone for now.
-                debug!("ProjectionCacheEntry::complete({:?}) - ignoring {:?}", key, value);
-                return;
-            }
-        };
-
-        self.map.insert(
-            key,
-            ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }),
-        );
-    }
-
-    /// A specialized version of `complete` for when the key's value is known
-    /// to be a NormalizedTy.
-    pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'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(
-                key,
-                ProjectionCacheEntry::NormalizedTy(Normalized {
-                    value: ty.value,
-                    obligations: vec![],
-                }),
-            );
-        }
-    }
-
-    /// 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: ProjectionCacheKey<'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: ProjectionCacheKey<'tcx>) {
-        let fresh = self.map.insert(key, ProjectionCacheEntry::Error);
-        assert!(!fresh, "never started projecting `{:?}`", key);
-    }
-}
diff --git a/src/librustc_infer/traits/projection_cache.rs b/src/librustc_infer/traits/projection_cache.rs
new file mode 100644
index 00000000000..fb7b5fdb8ea
--- /dev/null
+++ b/src/librustc_infer/traits/projection_cache.rs
@@ -0,0 +1,185 @@
+//! Code for projecting associated types out of trait references.
+
+use super::PredicateObligation;
+
+use rustc::ty::fold::TypeFoldable;
+use rustc::ty::{self, Ty};
+use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
+
+pub use rustc::traits::Reveal;
+
+#[derive(Clone)]
+pub struct MismatchedProjectionTypes<'tcx> {
+    pub err: ty::error::TypeError<'tcx>,
+}
+
+#[derive(Clone, TypeFoldable)]
+pub struct Normalized<'tcx, T> {
+    pub value: T,
+    pub obligations: Vec<PredicateObligation<'tcx>>,
+}
+
+pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>;
+
+impl<'tcx, T> Normalized<'tcx, T> {
+    pub fn with<U>(self, value: U) -> Normalized<'tcx, U> {
+        Normalized { value: value, obligations: self.obligations }
+    }
+}
+
+// # Cache
+
+/// The projection cache. Unlike the standard caches, this can include
+/// infcx-dependent type variables, therefore we have to roll the
+/// cache back each time we roll a snapshot back, to avoid assumptions
+/// on yet-unresolved inference variables. Types with placeholder
+/// regions also have to be removed when the respective snapshot ends.
+///
+/// Because of that, projection cache entries can be "stranded" and left
+/// inaccessible when type variables inside the key are resolved. We make no
+/// attempt to recover or remove "stranded" entries, but rather let them be
+/// (for the lifetime of the infcx).
+///
+/// Entries in the projection cache might contain inference variables
+/// that will be resolved by obligations on the projection cache entry (e.g.,
+/// when a type parameter in the associated type is constrained through
+/// an "RFC 447" projection on the impl).
+///
+/// When working with a fulfillment context, the derived obligations of each
+/// projection cache entry will be registered on the fulfillcx, so any users
+/// that can wait for a fulfillcx fixed point need not care about this. However,
+/// users that don't wait for a fixed point (e.g., trait evaluation) have to
+/// resolve the obligations themselves to make sure the projected result is
+/// ok and avoid issues like #43132.
+///
+/// If that is done, after evaluation the obligations, it is a good idea to
+/// call `ProjectionCache::complete` to make sure the obligations won't be
+/// re-evaluated and avoid an exponential worst-case.
+//
+// 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.
+#[derive(Default)]
+pub struct ProjectionCache<'tcx> {
+    map: SnapshotMap<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>,
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct ProjectionCacheKey<'tcx> {
+    pub ty: ty::ProjectionTy<'tcx>,
+}
+
+#[derive(Clone, Debug)]
+pub enum ProjectionCacheEntry<'tcx> {
+    InProgress,
+    Ambiguous,
+    Error,
+    NormalizedTy(NormalizedTy<'tcx>),
+}
+
+// N.B., intentionally not Clone
+pub struct ProjectionCacheSnapshot {
+    snapshot: Snapshot,
+}
+
+impl<'tcx> ProjectionCache<'tcx> {
+    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 rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) {
+        self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_placeholders());
+    }
+
+    pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) {
+        self.map.commit(snapshot.snapshot);
+    }
+
+    /// Try to start normalize `key`; returns an error if
+    /// normalization already occurred (this error corresponds to a
+    /// cache hit, so it's actually a good thing).
+    pub fn try_start(
+        &mut self,
+        key: ProjectionCacheKey<'tcx>,
+    ) -> Result<(), ProjectionCacheEntry<'tcx>> {
+        if let Some(entry) = self.map.get(&key) {
+            return Err(entry.clone());
+        }
+
+        self.map.insert(key, ProjectionCacheEntry::InProgress);
+        Ok(())
+    }
+
+    /// Indicates that `key` was normalized to `value`.
+    pub fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) {
+        debug!(
+            "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
+            key, value
+        );
+        let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value));
+        assert!(!fresh_key, "never started projecting `{:?}`", key);
+    }
+
+    /// Mark the relevant projection cache key as having its derived obligations
+    /// complete, so they won't have to be re-computed (this is OK to do in a
+    /// 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) {
+            Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => {
+                debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
+                ty.value
+            }
+            ref value => {
+                // Type inference could "strand behind" old cache entries. Leave
+                // them alone for now.
+                debug!("ProjectionCacheEntry::complete({:?}) - ignoring {:?}", key, value);
+                return;
+            }
+        };
+
+        self.map.insert(
+            key,
+            ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }),
+        );
+    }
+
+    /// A specialized version of `complete` for when the key's value is known
+    /// to be a NormalizedTy.
+    pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'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(
+                key,
+                ProjectionCacheEntry::NormalizedTy(Normalized {
+                    value: ty.value,
+                    obligations: vec![],
+                }),
+            );
+        }
+    }
+
+    /// 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).
+    pub fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) {
+        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);
+        assert!(!fresh, "never started projecting `{:?}`", key);
+    }
+}
diff --git a/src/librustc_infer/traits/query/normalize.rs b/src/librustc_infer/traits/query/normalize.rs
index 4577e3d2e1c..365bf9e295b 100644
--- a/src/librustc_infer/traits/query/normalize.rs
+++ b/src/librustc_infer/traits/query/normalize.rs
@@ -5,7 +5,7 @@
 use crate::infer::at::At;
 use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::{InferCtxt, InferOk};
-use crate::traits::project::Normalized;
+use crate::traits::Normalized;
 use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
 use rustc::ty::fold::{TypeFoldable, TypeFolder};
 use rustc::ty::subst::Subst;
diff --git a/src/librustc_infer/traits/select.rs b/src/librustc_infer/traits/select.rs
index 5c805731f25..12f39b12c72 100644
--- a/src/librustc_infer/traits/select.rs
+++ b/src/librustc_infer/traits/select.rs
@@ -9,9 +9,7 @@ use self::SelectionCandidate::*;
 
 use super::coherence::{self, Conflict};
 use super::project;
-use super::project::{
-    normalize_with_depth, normalize_with_depth_to, Normalized, ProjectionCacheKey,
-};
+use super::project::{normalize_with_depth, normalize_with_depth_to};
 use super::util;
 use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
 use super::wf;
@@ -21,6 +19,7 @@ use super::SelectionResult;
 use super::TraitNotObjectSafe;
 use super::TraitQueryMode;
 use super::{BuiltinDerivedObligation, ImplDerivedObligation, ObligationCauseCode};
+use super::{Normalized, ProjectionCacheKey};
 use super::{ObjectCastObligation, Obligation};
 use super::{ObligationCause, PredicateObligation, TraitObligation};
 use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented};
diff --git a/src/librustc_infer/traits/structural_impls.rs b/src/librustc_infer/traits/structural_impls.rs
index 6630f664f96..a164995255a 100644
--- a/src/librustc_infer/traits/structural_impls.rs
+++ b/src/librustc_infer/traits/structural_impls.rs
@@ -1,5 +1,5 @@
 use crate::traits;
-use crate::traits::project::Normalized;
+use crate::traits::Normalized;
 use rustc::ty;
 use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};