Skip to content

Commit c11f8b3

Browse files
authored
Rollup merge of rust-lang#56043 - nikomatsakis:issue-55756-via-outlives, r=eddyb
remove "approx env bounds" if we already know from trait Alternative to rust-lang#55988 that fixes rust-lang#55756 -- smaller fix that I cannot see having (correctness) repercussions beyond the test at hand, and hence better for backporting. (Famous last words, I know.) r? @eddyb
2 parents 78ba8d5 + a5b4cb2 commit c11f8b3

File tree

2 files changed

+60
-7
lines changed

2 files changed

+60
-7
lines changed

src/librustc/infer/outlives/obligations.rs

+23-7
Original file line numberDiff line numberDiff line change
@@ -389,22 +389,38 @@ where
389389
// rule might not apply (but another rule might). For now, we err
390390
// on the side of adding too few edges into the graph.
391391

392+
// Compute the bounds we can derive from the trait definition.
393+
// These are guaranteed to apply, no matter the inference
394+
// results.
395+
let trait_bounds: Vec<_> = self.verify_bound
396+
.projection_declared_bounds_from_trait(projection_ty)
397+
.collect();
398+
392399
// Compute the bounds we can derive from the environment. This
393400
// is an "approximate" match -- in some cases, these bounds
394401
// may not apply.
395-
let approx_env_bounds = self.verify_bound
402+
let mut approx_env_bounds = self.verify_bound
396403
.projection_approx_declared_bounds_from_env(projection_ty);
397404
debug!(
398405
"projection_must_outlive: approx_env_bounds={:?}",
399406
approx_env_bounds
400407
);
401408

402-
// Compute the bounds we can derive from the trait definition.
403-
// These are guaranteed to apply, no matter the inference
404-
// results.
405-
let trait_bounds: Vec<_> = self.verify_bound
406-
.projection_declared_bounds_from_trait(projection_ty)
407-
.collect();
409+
// Remove outlives bounds that we get from the environment but
410+
// which are also deducable from the trait. This arises (cc
411+
// #55756) in cases where you have e.g. `<T as Foo<'a>>::Item:
412+
// 'a` in the environment but `trait Foo<'b> { type Item: 'b
413+
// }` in the trait definition.
414+
approx_env_bounds.retain(|bound| {
415+
match bound.0.sty {
416+
ty::Projection(projection_ty) => {
417+
self.verify_bound.projection_declared_bounds_from_trait(projection_ty)
418+
.all(|r| r != bound.1)
419+
}
420+
421+
_ => panic!("expected only projection types from env, not {:?}", bound.0),
422+
}
423+
});
408424

409425
// If declared bounds list is empty, the only applicable rule is
410426
// OutlivesProjectionComponent. If there are inference variables,
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Regression test for #55756.
2+
//
3+
// In this test, the result of `self.callee` is a projection `<D as
4+
// Database<'?0>>::Guard`. As it may contain a destructor, the dropck
5+
// rules require that this type outlivess the scope of `state`. Unfortunately,
6+
// our region inference is not smart enough to figure out how to
7+
// translate a requirement like
8+
//
9+
// <D as Database<'0>>::guard: 'r
10+
//
11+
// into a requirement that `'0: 'r` -- in particular, it fails to do
12+
// so because it *also* knows that `<D as Database<'a>>::Guard: 'a`
13+
// from the trait definition. Faced with so many choices, the current
14+
// solver opts to do nothing.
15+
//
16+
// Fixed by tweaking the solver to recognize that the constraint from
17+
// the environment duplicates one from the trait.
18+
//
19+
// compile-pass
20+
21+
#![crate_type="lib"]
22+
23+
pub trait Database<'a> {
24+
type Guard: 'a;
25+
}
26+
27+
pub struct Stateful<'a, D: 'a>(&'a D);
28+
29+
impl<'b, D: for <'a> Database<'a>> Stateful<'b, D> {
30+
pub fn callee<'a>(&'a self) -> <D as Database<'a>>::Guard {
31+
unimplemented!()
32+
}
33+
pub fn caller<'a>(&'a self) -> <D as Database<'a>>::Guard {
34+
let state = self.callee();
35+
unimplemented!()
36+
}
37+
}

0 commit comments

Comments
 (0)