diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2017-06-14 14:25:41 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2017-06-17 05:40:39 -0400 |
| commit | 9fec4093df1b31a3d63100922136e7bfb53c0d26 (patch) | |
| tree | 01d90b5b421e2e033c9be17dbae129a3b2322dd1 | |
| parent | a65d8d3d71d49ba87fd4e8bfb86b70ec7d2ad83f (diff) | |
| download | rust-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.rs | 3 | ||||
| -rw-r--r-- | src/librustc_typeck/check/regionck.rs | 26 | ||||
| -rw-r--r-- | src/test/run-pass/issue-42552.rs | 40 |
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; + }); +} |
