Skip to content

Commit bed5ff5

Browse files
committed
Cover type outlives handling in the minimal coroutine mode
The shared binder tests only exercised region outlives constraints, and the two alias cases assert on the rewrite that the full mode performs, which the minimal mode deliberately skips. Add a case where an assumption names the component while the goal names the composite. Keeping the constraint whole leaves it for the root, and destructuring it would reduce it to the component and discharge it, so the two representations disagree. Also record that an assumption naming an alias exactly fails to discharge it, because assumptions are lowered without normalization and so compare unequal to the normalized goal.
1 parent e038e65 commit bed5ff5

3 files changed

Lines changed: 129 additions & 0 deletions

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//@ compile-flags: -Zassumptions-on-binders=min_coroutines
2+
//@ normalize-stderr: "\[[0-9a-f]{4}\]" -> "[HASH]"
3+
4+
#![feature(test_binder_constraints)]
5+
#![allow(internal_features)]
6+
7+
trait Trait {
8+
type Assoc;
9+
}
10+
11+
// Minimal mode keeps type outlives constraints intact instead of destructuring them into their
12+
// components, so these constraints are retained and left for the root inference context.
13+
//
14+
// The `actual` constraint in the expected output is the point of these tests, so do not normalize
15+
// it away: it is what distinguishes the retained `TypeOutlives` leaf from the OR of item bounds,
16+
// env assumptions and components that eager destructuring would produce.
17+
18+
// The assumption names the component `T` while the goal names the composite `(T,)`. Destructuring
19+
// eagerly would reduce the goal to its component and discharge it against the assumption, which is
20+
// exactly the strengthening of the eager leak check that this mode avoids. Keeping the constraint
21+
// whole means it is retained instead, so this `expect` clause fails.
22+
core::test_binder_constraints! {
23+
impl<T> {
24+
forall<'a> where T: 'a {
25+
//~^ ERROR forall expect clause failed
26+
where (T,): 'a
27+
} expect {}
28+
}
29+
}
30+
31+
// FIXME(-Zassumptions-on-binders): the assumption on the binder names the very same alias, so this
32+
// ought to be discharged and the `expect` clause ought to hold. It is not, because the assumption
33+
// is lowered without being normalized and so carries a non-rigid alias, while the goal is
34+
// normalized to a rigid one, and the two do not compare equal. See the FIXME about normalizing
35+
// assumptions in `region_assumptions_for_placeholders_in_universe`. Destructuring the constraint
36+
// eagerly would lose the `TypeOutlives` leaf that this matching needs, which is why minimal mode
37+
// keeps it.
38+
core::test_binder_constraints! {
39+
impl<T: Trait> {
40+
forall<'a> where T::Assoc: 'a {
41+
//~^ ERROR forall expect clause failed
42+
where T::Assoc: 'a
43+
} expect {}
44+
}
45+
}
46+
47+
fn main() {}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
error: forall expect clause failed
2+
--> $DIR/min-coroutines-alias-outlives.rs:24:9
3+
|
4+
LL | forall<'a> where T: 'a {
5+
| ^^^^^^
6+
|
7+
note: constraint from here
8+
--> $DIR/min-coroutines-alias-outlives.rs:24:9
9+
|
10+
LL | forall<'a> where T: 'a {
11+
| ^^^^^^
12+
= note: expected: And(
13+
[],
14+
)
15+
= note: actual: And(
16+
[
17+
TypeOutlives(
18+
(T/#0,),
19+
'!1_0.Named(DefId(0:8 ~ min_coroutines_alias_outlives[HASH]::{test_binder_constraints#0}::'a)),
20+
$DIR/min-coroutines-alias-outlives.rs:24:9: 24:15 (#0),
21+
),
22+
],
23+
)
24+
25+
error: forall expect clause failed
26+
--> $DIR/min-coroutines-alias-outlives.rs:40:9
27+
|
28+
LL | forall<'a> where T::Assoc: 'a {
29+
| ^^^^^^
30+
|
31+
note: constraint from here
32+
--> $DIR/min-coroutines-alias-outlives.rs:40:9
33+
|
34+
LL | forall<'a> where T::Assoc: 'a {
35+
| ^^^^^^
36+
= note: expected: And(
37+
[],
38+
)
39+
= note: actual: And(
40+
[
41+
TypeOutlives(
42+
Alias(
43+
Yes,
44+
Alias {
45+
kind: Projection {
46+
def_id: DefId(0:4 ~ min_coroutines_alias_outlives[HASH]::Trait::Assoc),
47+
},
48+
args: [
49+
T/#0,
50+
],
51+
..
52+
},
53+
),
54+
'!1_0.Named(DefId(0:11 ~ min_coroutines_alias_outlives[HASH]::{test_binder_constraints#1}::'a)),
55+
$DIR/min-coroutines-alias-outlives.rs:40:9: 40:15 (#0),
56+
),
57+
],
58+
)
59+
60+
error: aborting due to 2 previous errors
61+

tests/ui/assumptions_on_binders/test-infra-works.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,15 @@ trait Trait {
5252
// `impl` should fail because the constraints asserted in `expect` should fail to prove true. Might
5353
// be https://github.com/rust-lang/project-assumptions-on-binders/issues/26
5454
//
55+
// The `expect` clauses of this and the next test assert on the full mode's rewrite of alias
56+
// outlives constraints into lower universes. `min_coroutines` deliberately does not rewrite, it
57+
// only drops constraints directly implied by the binder's assumptions and keeps the rest as they
58+
// are, so the rewritten form is specific to `assumptions`. The retained form cannot be spelled in
59+
// an `expect` clause because it still mentions the binder's own lifetime, so `min_coroutines`
60+
// coverage for aliases lives in `min-coroutines-alias-outlives.rs` instead.
61+
//
5562
// for<> syntax does direct insert into constraint storage
63+
#[cfg(assumptions)]
5664
core::test_binder_constraints! {
5765
impl<T: Trait> {
5866
forall<'a> {
@@ -71,6 +79,7 @@ core::test_binder_constraints! {
7179
// be https://github.com/rust-lang/project-assumptions-on-binders/issues/26
7280
//
7381
// `where` syntax goes through the full clause destructuring and register_obligation pipeline
82+
#[cfg(assumptions)]
7483
core::test_binder_constraints! {
7584
impl<T: Trait> {
7685
forall<'a> {
@@ -96,4 +105,16 @@ core::test_binder_constraints! {
96105
}
97106
}
98107

108+
// Minimal mode discharges a type outlives goal when an assumption names the same type. Note that
109+
// this case alone does not pin down whether the constraint was kept whole or destructured, since a
110+
// bare param is its own only component either way; `min-coroutines-alias-outlives.rs` covers that.
111+
#[cfg(min_coroutines)]
112+
core::test_binder_constraints! {
113+
impl<T> {
114+
forall<'a> where T: 'a {
115+
where T: 'a
116+
} expect {}
117+
}
118+
}
119+
99120
fn main() {}

0 commit comments

Comments
 (0)