about summary refs log tree commit diff
path: root/compiler/rustc_infer
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2020-12-20 18:13:05 +0000
committerMatthew Jasper <mjjasper1@gmail.com>2020-12-20 21:47:51 +0000
commit2e92b13a606ba2f073c789dfd6c33f889f04c8cf (patch)
tree65d4dc0e2251bc3a5d08aa4d8360909074b5d3ca /compiler/rustc_infer
parent77fce67733d2a1403f17b382dfbd3802003172a6 (diff)
downloadrust-2e92b13a606ba2f073c789dfd6c33f889f04c8cf.tar.gz
rust-2e92b13a606ba2f073c789dfd6c33f889f04c8cf.zip
Prevent caching projections in the case of cycles
When normalizing a projection which results in a cycle, we would
cache the result of `project_type` without the nested obligations
(because they're not needed for inference). This would result in
the nested obligations only being handled once in fulfill, which
would avoid the cycle error.

Fixes #79714, a regresion from #79305 caused by the removal of
`get_paranoid_cache_value_obligation`.
Diffstat (limited to 'compiler/rustc_infer')
-rw-r--r--compiler/rustc_infer/src/traits/project.rs16
1 files changed, 15 insertions, 1 deletions
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index 65284bcee91..33bddf1dedc 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -90,6 +90,7 @@ impl ProjectionCacheKey<'tcx> {
 pub enum ProjectionCacheEntry<'tcx> {
     InProgress,
     Ambiguous,
+    Recur,
     Error,
     NormalizedTy(NormalizedTy<'tcx>),
 }
@@ -143,7 +144,12 @@ 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 mut map = self.map();
+        if let Some(ProjectionCacheEntry::Recur) = map.get(&key) {
+            debug!("Not overwriting Recur");
+            return;
+        }
+        let fresh_key = map.insert(key, ProjectionCacheEntry::NormalizedTy(value));
         assert!(!fresh_key, "never started projecting `{:?}`", key);
     }
 
@@ -197,6 +203,14 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
         assert!(!fresh, "never started projecting `{:?}`", key);
     }
 
+    /// Indicates that while trying to normalize `key`, `key` was required to
+    /// be normalized again. Selection or evaluation should eventually report
+    /// an error here.
+    pub fn recur(&mut self, key: ProjectionCacheKey<'tcx>) {
+        let fresh = self.map().insert(key, ProjectionCacheEntry::Recur);
+        assert!(!fresh, "never started projecting `{:?}`", key);
+    }
+
     /// Indicates that trying to normalize `key` resulted in
     /// error.
     pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) {