about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-07-29 21:40:37 +0300
committerAlex Crichton <alex@alexcrichton.com>2017-07-30 11:07:28 -0700
commit2574f31b9b71cd2b37002dbfc9a818c3cc805498 (patch)
tree5cf8af12f124c85aa05b5d454a357c1e412fcc76
parent477e9f01714b6dffa1fb75e95b890d7abc2fcc52 (diff)
downloadrust-2574f31b9b71cd2b37002dbfc9a818c3cc805498.tar.gz
rust-2574f31b9b71cd2b37002dbfc9a818c3cc805498.zip
save the subobligations as well
-rw-r--r--src/librustc/traits/project.rs18
-rw-r--r--src/test/run-pass/issue-43132.rs74
2 files changed, 86 insertions, 6 deletions
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index cae1eba5797..7cce9c398bb 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -462,13 +462,19 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             selcx.infcx().report_overflow_error(&obligation, false);
         }
         Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
-            // If we find the value in the cache, then the obligations
-            // have already been returned from the previous entry (and
-            // should therefore have been honored).
+            // If we find the value in the cache, then return it along
+            // with the obligations that went along with it. Note
+            // that, when using a fulfillment context, these
+            // obligations could in principle be ignored: they have
+            // already been registered when the cache entry was
+            // created (and hence the new ones will quickly be
+            // discarded as duplicated). But when doing trait
+            // evaluation this is not the case, and dropping the trait
+            // evaluations can causes ICEs (e.g. #43132).
             debug!("opt_normalize_projection_type: \
                     found normalized ty `{:?}`",
                    ty);
-            return Some(NormalizedTy { value: ty, obligations: vec![] });
+            return Some(ty);
         }
         Err(ProjectionCacheEntry::Error) => {
             debug!("opt_normalize_projection_type: \
@@ -1326,7 +1332,7 @@ enum ProjectionCacheEntry<'tcx> {
     InProgress,
     Ambiguous,
     Error,
-    NormalizedTy(Ty<'tcx>),
+    NormalizedTy(NormalizedTy<'tcx>),
 }
 
 // NB: intentionally not Clone
@@ -1374,7 +1380,7 @@ impl<'tcx> ProjectionCache<'tcx> {
     fn complete(&mut self, key: ty::ProjectionTy<'tcx>, value: &NormalizedTy<'tcx>) {
         debug!("ProjectionCacheEntry::complete: adding cache entry: key={:?}, value={:?}",
                key, value);
-        let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.value));
+        let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.clone()));
         assert!(!fresh_key, "never started projecting `{:?}`", key);
     }
 
diff --git a/src/test/run-pass/issue-43132.rs b/src/test/run-pass/issue-43132.rs
new file mode 100644
index 00000000000..64b3b092b89
--- /dev/null
+++ b/src/test/run-pass/issue-43132.rs
@@ -0,0 +1,74 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(unused)]
+
+fn main() {
+}
+
+fn foo() {
+    let b = mk::<
+        Forward<(Box<Future<Error = u32>>,)>,
+    >();
+    b.map_err(|_| ()).join();
+}
+
+fn mk<T>() -> T {
+    loop {}
+}
+
+impl<I: Future<Error = E>, E> Future for (I,) {
+    type Error = E;
+}
+
+struct Forward<T: Future> {
+    _a: T,
+}
+
+impl<T: Future> Future for Forward<T>
+where
+    T::Error: From<u32>,
+{
+    type Error = T::Error;
+}
+
+trait Future {
+    type Error;
+
+    fn map_err<F, E>(self, _: F) -> (Self, F)
+    where
+        F: FnOnce(Self::Error) -> E,
+        Self: Sized,
+    {
+        loop {}
+    }
+
+    fn join(self) -> (MaybeDone<Self>, ())
+    where
+        Self: Sized,
+    {
+        loop {}
+    }
+}
+
+impl<S: ?Sized + Future> Future for Box<S> {
+    type Error = S::Error;
+}
+
+enum MaybeDone<A: Future> {
+    _Done(A::Error),
+}
+
+impl<U, A: Future, F> Future for (A, F)
+where
+    F: FnOnce(A::Error) -> U,
+{
+    type Error = U;
+}