Skip to content

Commit

Permalink
register the obligations from wf::implied_bounds
Browse files Browse the repository at this point in the history
Fixes #42552.
Fixes #42545.
  • Loading branch information
nikomatsakis committed Jun 17, 2017
1 parent a65d8d3 commit 9fec409
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
26 changes: 26 additions & 0 deletions src/librustc_typeck/check/regionck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
40 changes: 40 additions & 0 deletions src/test/run-pass/issue-42552.rs
Original file line number Diff line number Diff line change
@@ -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;
});
}

0 comments on commit 9fec409

Please sign in to comment.