diff options
author | Niko Matsakis <niko@alum.mit.edu> | 2018-11-18 10:07:25 -0500 |
---|---|---|
committer | Niko Matsakis <niko@alum.mit.edu> | 2018-11-18 15:00:34 -0500 |
commit | a5b4cb29919a19a9f92bf57a304461fe4239d46d (patch) | |
tree | 353e64a47ea25baaba444aa33288a33fa7a9db7b /src | |
parent | 485397e49a02a3b7ff77c17e4a3f16c653925cb3 (diff) | |
download | rust-a5b4cb29919a19a9f92bf57a304461fe4239d46d.tar.gz |
remove "approx env bounds" if we already know from trait
Diffstat (limited to 'src')
-rw-r--r-- | src/librustc/infer/outlives/obligations.rs | 30 | ||||
-rw-r--r-- | src/test/ui/nll/ty-outlives/issue-55756.rs | 37 |
2 files changed, 60 insertions, 7 deletions
diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index f2825887f36..ab75a914d9c 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -389,22 +389,38 @@ where // rule might not apply (but another rule might). For now, we err // on the side of adding too few edges into the graph. + // Compute the bounds we can derive from the trait definition. + // These are guaranteed to apply, no matter the inference + // results. + let trait_bounds: Vec<_> = self.verify_bound + .projection_declared_bounds_from_trait(projection_ty) + .collect(); + // Compute the bounds we can derive from the environment. This // is an "approximate" match -- in some cases, these bounds // may not apply. - let approx_env_bounds = self.verify_bound + let mut approx_env_bounds = self.verify_bound .projection_approx_declared_bounds_from_env(projection_ty); debug!( "projection_must_outlive: approx_env_bounds={:?}", approx_env_bounds ); - // Compute the bounds we can derive from the trait definition. - // These are guaranteed to apply, no matter the inference - // results. - let trait_bounds: Vec<_> = self.verify_bound - .projection_declared_bounds_from_trait(projection_ty) - .collect(); + // Remove outlives bounds that we get from the environment but + // which are also deducable from the trait. This arises (cc + // #55756) in cases where you have e.g. `<T as Foo<'a>>::Item: + // 'a` in the environment but `trait Foo<'b> { type Item: 'b + // }` in the trait definition. + approx_env_bounds.retain(|bound| { + match bound.0.sty { + ty::Projection(projection_ty) => { + self.verify_bound.projection_declared_bounds_from_trait(projection_ty) + .all(|r| r != bound.1) + } + + _ => panic!("expected only projection types from env, not {:?}", bound.0), + } + }); // If declared bounds list is empty, the only applicable rule is // OutlivesProjectionComponent. If there are inference variables, diff --git a/src/test/ui/nll/ty-outlives/issue-55756.rs b/src/test/ui/nll/ty-outlives/issue-55756.rs new file mode 100644 index 00000000000..cda3915849e --- /dev/null +++ b/src/test/ui/nll/ty-outlives/issue-55756.rs @@ -0,0 +1,37 @@ +// Regression test for #55756. +// +// In this test, the result of `self.callee` is a projection `<D as +// Database<'?0>>::Guard`. As it may contain a destructor, the dropck +// rules require that this type outlivess the scope of `state`. Unfortunately, +// our region inference is not smart enough to figure out how to +// translate a requirement like +// +// <D as Database<'0>>::guard: 'r +// +// into a requirement that `'0: 'r` -- in particular, it fails to do +// so because it *also* knows that `<D as Database<'a>>::Guard: 'a` +// from the trait definition. Faced with so many choices, the current +// solver opts to do nothing. +// +// Fixed by tweaking the solver to recognize that the constraint from +// the environment duplicates one from the trait. +// +// compile-pass + +#![crate_type="lib"] + +pub trait Database<'a> { + type Guard: 'a; +} + +pub struct Stateful<'a, D: 'a>(&'a D); + +impl<'b, D: for <'a> Database<'a>> Stateful<'b, D> { + pub fn callee<'a>(&'a self) -> <D as Database<'a>>::Guard { + unimplemented!() + } + pub fn caller<'a>(&'a self) -> <D as Database<'a>>::Guard { + let state = self.callee(); + unimplemented!() + } +} |