about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-06-14 14:25:41 -0400
committerNiko Matsakis <niko@alum.mit.edu>2017-06-17 05:40:39 -0400
commit9fec4093df1b31a3d63100922136e7bfb53c0d26 (patch)
tree01d90b5b421e2e033c9be17dbae129a3b2322dd1
parenta65d8d3d71d49ba87fd4e8bfb86b70ec7d2ad83f (diff)
downloadrust-9fec4093df1b31a3d63100922136e7bfb53c0d26.tar.gz
rust-9fec4093df1b31a3d63100922136e7bfb53c0d26.zip
register the obligations from `wf::implied_bounds`
Fixes #42552.
Fixes #42545.
-rw-r--r--src/librustc_typeck/check/mod.rs3
-rw-r--r--src/librustc_typeck/check/regionck.rs26
-rw-r--r--src/test/run-pass/issue-42552.rs40
3 files changed, 68 insertions, 1 deletions
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index b1d3292e04c..44d85791f35 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -614,7 +614,8 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
             .register_predicate_obligation(self, obligation);
     }
 
-    fn register_predicates(&self, obligations: Vec<traits::PredicateObligation<'tcx>>) {
+    fn register_predicates<I>(&self, obligations: I)
+    where I: IntoIterator<Item = traits::PredicateObligation<'tcx>> {
         for obligation in obligations {
             self.register_predicate(obligation);
         }
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index bbcd0eadef7..5e79237da69 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -471,6 +471,32 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                 wf::obligations(self, self.fcx.param_env, body_id, ty, span)
                 .unwrap_or(vec![]);
 
+            // NB: All of these predicates *ought* to be easily proven
+            // true. In fact, their correctness is (mostly) implied by
+            // other parts of the program. However, in #42552, we had
+            // an annoying scenario where:
+            //
+            // - Some `T::Foo` gets normalized, resulting in a
+            //   variable `_1` and a `T: Trait<Foo=_1>` constraint
+            //   (not sure why it couldn't immediately get
+            //   solved). This result of `_1` got cached.
+            // - These obligations were dropped on the floor here,
+            //   rather than being registered.
+            // - Then later we would get a request to normalize
+            //   `T::Foo` which would result in `_1` being used from
+            //   the cache, but hence without the `T: Trait<Foo=_1>`
+            //   constraint. As a result, `_1` never gets resolved,
+            //   and we get an ICE (in dropck).
+            //
+            // Therefore, we register any predicates involving
+            // inference variables. We restrict ourselves to those
+            // involving inference variables both for efficiency and
+            // to avoids duplicate errors that otherwise show up.
+            self.fcx.register_predicates(
+                obligations.iter()
+                           .filter(|o| o.predicate.has_infer_types())
+                           .cloned());
+
             // From the full set of obligations, just filter down to the
             // region relationships.
             implied_bounds.extend(
diff --git a/src/test/run-pass/issue-42552.rs b/src/test/run-pass/issue-42552.rs
new file mode 100644
index 00000000000..fd1265b7174
--- /dev/null
+++ b/src/test/run-pass/issue-42552.rs
@@ -0,0 +1,40 @@
+// Copyright 2016 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.
+
+// Regression test for an obscure issue with the projection cache.
+
+fn into_iter<I: Iterator>(a: &I) -> Groups<I> {
+    Groups { _a: a }
+}
+
+pub struct Groups<'a, I: 'a> {
+    _a: &'a I,
+}
+
+impl<'a, I: Iterator> Iterator for Groups<'a, I> {
+    type Item = Group<'a, I>;
+    fn next(&mut self) -> Option<Self::Item> {
+        None
+    }
+}
+
+pub struct Group<'a, I: Iterator + 'a>
+    where I::Item: 'a       // <-- needed to trigger ICE!
+{
+    _phantom: &'a (),
+    _ice_trigger: I::Item,  // <-- needed to trigger ICE!
+}
+
+
+fn main() {
+    let _ = into_iter(&[0].iter().map(|_| 0)).map(|grp| {
+        let _g = grp;
+    });
+}