Skip to content

Commit 652fd2e

Browse files
committed
add tests exercising exists<'a> { forall<'b> { .. } } pattern
Amazingly, this scenario was not tested for trait matching.
1 parent b68fad6 commit 652fd2e

6 files changed

+163
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
2+
//
3+
// In particular, we test this pattern in trait solving, where it is not connected
4+
// to any part of the source code.
5+
6+
trait Trait<T> {}
7+
8+
fn foo<'a>() -> fn(&'a u32) {
9+
panic!()
10+
}
11+
12+
fn main() {
13+
// Here, proving that `(): Trait<for<'b> fn(&'b u32)>` uses the impl:
14+
//
15+
// - The impl provides the clause `forall<'a> { (): Trait<fn(&'a u32)> }`
16+
// - We instantiate `'a` existentially to get `(): Trait<fn(&?a u32)>`
17+
// - We unify `fn(&?a u32)` with `for<'b> fn(&'b u32)`
18+
// - This requires (among other things) instantiating `'b` universally,
19+
// yielding `fn(&!b u32)`, in a fresh universe U1
20+
// - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`.
21+
22+
let _: for<'b> fn(&'b u32) = foo(); //~ ERROR cannot infer
23+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
2+
--> $DIR/hrtb-exists-forall-fn.rs:22:34
3+
|
4+
LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR cannot infer
5+
| ^^^
6+
|
7+
= note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U1, name: BrNamed(crate0:DefIndex(1:11), 'b) })...
8+
= note: ...so that the expression is assignable:
9+
expected for<'b> fn(&'b u32)
10+
found fn(&u32)
11+
note: but, the lifetime must be valid for the call at 22:34...
12+
--> $DIR/hrtb-exists-forall-fn.rs:22:34
13+
|
14+
LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR cannot infer
15+
| ^^^^^
16+
note: ...so type `fn(&u32)` of expression is valid during the expression
17+
--> $DIR/hrtb-exists-forall-fn.rs:22:34
18+
|
19+
LL | let _: for<'b> fn(&'b u32) = foo(); //~ ERROR cannot infer
20+
| ^^^^^
21+
22+
error: aborting due to previous error
23+
24+
For more information about this error, try `rustc --explain E0495`.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
2+
//
3+
// In particular, we test this pattern in trait solving, where it is not connected
4+
// to any part of the source code.
5+
//
6+
// compile-pass
7+
8+
trait Trait<T> {}
9+
10+
fn foo<T>()
11+
where
12+
T: Trait<for<'b> fn(&'b u32)>,
13+
{
14+
}
15+
16+
impl<'a> Trait<fn(&'a u32)> for () {}
17+
18+
fn main() {
19+
// Here, proving that `(): Trait<for<'b> fn(&'b u32)>` uses the impl:
20+
//
21+
// - The impl provides the clause `forall<'a> { (): Trait<fn(&'a u32)> }`
22+
// - We instantiate `'a` existentially to get `(): Trait<fn(&?a u32)>`
23+
// - We unify `fn(&?a u32)` with `for<'b> fn(&'b u32)` -- this does a
24+
// "bidirectional" subtyping check, so we wind up with:
25+
// - `fn(&?a u32) <: for<'b> fn(&'b u32)` :-
26+
// - `&'!b u32 <: &?a u32`
27+
// - `!'b: ?a` -- solveable if `?a` is inferred to `'empty`
28+
// - `for<'b> fn(&'b u32) <: fn(&?a u32)` :-
29+
// - `&?a u32 u32 <: &?b u32`
30+
// - `?a: ?b` -- solveable if `?b` is also inferred to `'empty`
31+
// - So the subtyping check succeeds, somewhat surprisingly.
32+
// This is because we can use `'empty`.
33+
34+
foo::<()>();
35+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
2+
//
3+
// In particular, we test this pattern in trait solving, where it is not connected
4+
// to any part of the source code.
5+
//
6+
// compile-pass
7+
8+
trait Trait<T> {}
9+
10+
fn foo<T>()
11+
where
12+
T: Trait<for<'b> fn(fn(&'b u32))>,
13+
{
14+
}
15+
16+
impl<'a> Trait<fn(fn(&'a u32))> for () {}
17+
18+
fn main() {
19+
// Here, proving that `(): Trait<for<'b> fn(&'b u32)>` uses the impl:
20+
//
21+
// - The impl provides the clause `forall<'a> { (): Trait<fn(fn(&'a u32))> }`
22+
// - We instantiate `'a` existentially to get `(): Trait<fn(fn(&?a u32))>`
23+
// - We unify `fn(fn(&?a u32))` with `for<'b> fn(fn(&'b u32))` -- this does a
24+
// "bidirectional" subtyping check, so we wind up with:
25+
// - `fn(fn(&?a u32)) <: for<'b> fn(fn(&'b u32))` :-
26+
// - `fn(&!b u32) <: fn(&?a u32)`
27+
// - `&?a u32 <: &!b u32`
28+
// - `?a: !'b` -- solveable if `?a` is inferred to `'static`
29+
// - `for<'b> fn(fn(&'b u32)) <: fn(fn(&?a u32))` :-
30+
// - `fn(&?a u32) <: fn(&?b u32)`
31+
// - `&?b u32 <: &?a u32`
32+
// - `?b: ?a` -- solveable if `?b` is inferred to `'static`
33+
// - So the subtyping check succeeds, somewhat surprisingly.
34+
// This is because we can use `'static`.
35+
36+
foo::<()>();
37+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
2+
//
3+
// In particular, we test this pattern in trait solving, where it is not connected
4+
// to any part of the source code.
5+
6+
use std::cell::Cell;
7+
8+
trait Trait<T> {}
9+
10+
fn foo<T>()
11+
where
12+
T: Trait<for<'b> fn(Cell<&'b u32>)>,
13+
{
14+
}
15+
16+
impl<'a> Trait<fn(Cell<&'a u32>)> for () {}
17+
18+
fn main() {
19+
// Here, proving that `(): Trait<for<'b> fn(&'b u32)>` uses the impl:
20+
//
21+
// - The impl provides the clause `forall<'a> { (): Trait<fn(&'a u32)> }`
22+
// - We instantiate `'a` existentially to get `(): Trait<fn(&?a u32)>`
23+
// - We unify `fn(&?a u32)` with `for<'b> fn(&'b u32)`
24+
// - This requires (among other things) instantiating `'b` universally,
25+
// yielding `fn(&!b u32)`, in a fresh universe U1
26+
// - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`.
27+
28+
foo::<()>(); //~ ERROR cannot infer
29+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
2+
--> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
3+
|
4+
LL | foo::<()>(); //~ ERROR cannot infer
5+
| ^^^^^^^^^
6+
|
7+
= note: first, the lifetime cannot outlive lifetime RePlaceholder(Placeholder { universe: U3, name: BrNamed(crate0:DefIndex(1:11), 'b) })...
8+
= note: ...but the lifetime must also be valid for lifetime RePlaceholder(Placeholder { universe: U3, name: BrNamed(crate0:DefIndex(1:11), 'b) })...
9+
= note: ...so that the types are compatible:
10+
expected Trait<for<'b> fn(std::cell::Cell<&'b u32>)>
11+
found Trait<fn(std::cell::Cell<&u32>)>
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0495`.

0 commit comments

Comments
 (0)