Skip to content

Commit 4b5995e

Browse files
committed
make type_must_be_valid_for_scope require each region to outlive S
This is compatible with the liveness rules for NLL; it is also stricter than the old requirement. It gives enough guidance to get inference passing.
1 parent b7feb9f commit 4b5995e

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

src/librustc_typeck/check/regionck.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1034,14 +1034,19 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
10341034
/// implies `T: scope` but is actually stronger than that in the
10351035
/// case of projections. This helps overcome some weakenesses in
10361036
/// our inference (see #55756).
1037+
///
1038+
/// (This is the lexical equivalent of NLL's "liveness rules",
1039+
/// which require that any region which appears at the point P
1040+
/// must contain the point P.)
10371041
pub fn type_must_be_valid_for_scope(
10381042
&self,
10391043
origin: infer::SubregionOrigin<'tcx>,
10401044
ty: Ty<'tcx>,
10411045
scope: region::Scope,
10421046
) {
1043-
let region = self.tcx.mk_region(ty::ReScope(scope));
1044-
self.type_must_outlive(origin, ty, region)
1047+
let scope_region = self.tcx.mk_region(ty::ReScope(scope));
1048+
let ty = self.resolve_type_vars_if_possible(&ty);
1049+
self.tcx.for_each_free_region(&ty, |ty_region| self.sub_regions(origin.clone(), scope_region, ty_region));
10451050
}
10461051

10471052
/// Adds constraints to inference such that `T: 'a` holds (or

src/test/ui/issues/issue-55756.rs

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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+
// The problem we were having was that we would observe two
17+
// potentially applicable rules when trying to find bounds for `<T as
18+
// Database<'0>>::Guard`:
19+
//
20+
// ```
21+
// <T as Database<'a>>::Guard: 'a // from the where clauses
22+
// for<'b> { <T as Database<'b>>::Guard: 'b } // from the trait definition
23+
// ```
24+
//
25+
// Because of this, we decided to take no action to influence
26+
// inference, which means that `'0` winds up unconstrained, leading to
27+
// the ultimate error.
28+
//
29+
// compile-pass
30+
31+
#![crate_type="lib"]
32+
33+
pub trait Database<'a> {
34+
type Guard: 'a;
35+
}
36+
37+
pub struct Stateful<'a, D: 'a>(&'a D);
38+
39+
impl<'b, D: for <'a> Database<'a>> Stateful<'b, D> {
40+
pub fn callee<'a>(&'a self) -> <D as Database<'a>>::Guard {
41+
unimplemented!()
42+
}
43+
pub fn caller<'a>(&'a self) -> <D as Database<'a>>::Guard {
44+
let state = self.callee();
45+
self.callee()
46+
}
47+
}

0 commit comments

Comments
 (0)