Add some FnDef LUB coercion tests

This commit is contained in:
Oli Scherer 2024-04-11 14:14:15 +00:00
parent 6c6b3027ef
commit ca4a18fafc
4 changed files with 321 additions and 0 deletions

View file

@ -0,0 +1,58 @@
//! Test that coercing between function items of the same function,
//! but with different generic args succeeds in typeck, but then fails
//! in borrowck when the lifetimes can't actually be merged.
fn foo<T>(t: T) -> T {
t
}
fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
let mut x = foo::<&'a ()>; //~ ERROR: lifetime may not live long enough
x = foo::<&'b ()>; //~ ERROR: lifetime may not live long enough
x = foo::<&'c ()>;
x(a);
x(b);
x(c);
}
fn g<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
let x = foo::<&'c ()>;
let _: &'c () = x(a); //~ ERROR lifetime may not live long enough
}
fn h<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
let x = foo::<&'a ()>;
let _: &'a () = x(c);
}
fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
let mut x = foo::<&'c ()>;
x = foo::<&'b ()>; //~ ERROR lifetime may not live long enough
x = foo::<&'a ()>; //~ ERROR lifetime may not live long enough
x(a);
x(b);
x(c);
}
fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
let x = match true {
true => foo::<&'b ()>, //~ ERROR lifetime may not live long enough
false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough
};
x(a);
x(b);
x(c);
}
fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
let x = match true {
true => foo::<&'c ()>,
false => foo::<&'a ()>, //~ ERROR lifetime may not live long enough
};
x(a);
x(b); //~ ERROR lifetime may not live long enough
x(c);
}
fn main() {}

View file

@ -0,0 +1,154 @@
error: lifetime may not live long enough
--> $DIR/fn_def_coercion.rs:10:17
|
LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | let mut x = foo::<&'a ()>;
| ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
= note: requirement occurs because of a function pointer to `foo`
= note: the function `foo` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/fn_def_coercion.rs:11:5
|
LL | fn f<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | let mut x = foo::<&'a ()>;
LL | x = foo::<&'b ()>;
| ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
= note: requirement occurs because of a function pointer to `foo`
= note: the function `foo` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'a` and `'b` must be the same: replace one with the other
error: lifetime may not live long enough
--> $DIR/fn_def_coercion.rs:20:12
|
LL | fn g<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
| -- -- lifetime `'c` defined here
| |
| lifetime `'a` defined here
LL | let x = foo::<&'c ()>;
LL | let _: &'c () = x(a);
| ^^^^^^ type annotation requires that `'a` must outlive `'c`
|
= help: consider adding the following bound: `'a: 'c`
error: lifetime may not live long enough
--> $DIR/fn_def_coercion.rs:30:5
|
LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | let mut x = foo::<&'c ()>;
LL | x = foo::<&'b ()>;
| ^^^^^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
= note: requirement occurs because of a function pointer to `foo`
= note: the function `foo` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/fn_def_coercion.rs:31:5
|
LL | fn i<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | x = foo::<&'a ()>;
| ^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
= note: requirement occurs because of a function pointer to `foo`
= note: the function `foo` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'a` and `'b` must be the same: replace one with the other
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: lifetime may not live long enough
--> $DIR/fn_def_coercion.rs:39:17
|
LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | let x = match true {
LL | true => foo::<&'b ()>,
| ^^^^^^^^^^^^^ assignment requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
= note: requirement occurs because of a function pointer to `foo`
= note: the function `foo` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/fn_def_coercion.rs:40:18
|
LL | fn j<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | false => foo::<&'a ()>,
| ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
= note: requirement occurs because of a function pointer to `foo`
= note: the function `foo` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'a` and `'b` must be the same: replace one with the other
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: lifetime may not live long enough
--> $DIR/fn_def_coercion.rs:50:18
|
LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
| -- -- lifetime `'c` defined here
| |
| lifetime `'a` defined here
...
LL | false => foo::<&'a ()>,
| ^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'c`
|
= help: consider adding the following bound: `'a: 'c`
= note: requirement occurs because of a function pointer to `foo`
= note: the function `foo` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/fn_def_coercion.rs:54:5
|
LL | fn k<'a, 'b, 'c: 'a + 'b>(a: &'a (), b: &'b (), c: &'c ()) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | x(b);
| ^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
help: the following changes may resolve your lifetime errors
|
= help: add bound `'a: 'c`
= help: add bound `'b: 'a`
error: aborting due to 9 previous errors

View file

@ -0,0 +1,67 @@
//! Test that coercing between function items of the same function,
//! but with different args works.
#![feature(type_alias_impl_trait)]
fn foo<T>(t: T) -> T {
t
}
type F = impl Sized;
fn f(a: F) {
let mut x = foo::<F>;
x = foo::<()>;
x(a);
x(());
}
type G = impl Sized;
fn g(a: G) {
let x = foo::<()>;
let _: () = x(a);
}
type H = impl Sized;
fn h(a: H) {
let x = foo::<H>;
let _: H = x(());
}
type I = impl Sized;
fn i(a: I) {
let mut x = foo::<()>;
x = foo::<I>;
x(a);
x(());
}
type J = impl Sized;
fn j(a: J) {
let x = match true {
true => foo::<J>,
false => foo::<()>, //~ ERROR: incompatible types
};
x(a);
x(());
}
fn k() -> impl Sized {
fn bind<T, F: FnOnce(T) -> T>(_: T, f: F) -> F {
f
}
let x = match true {
true => {
let f = foo;
bind(k(), f)
}
false => foo::<()>, //~ ERROR: incompatible types
};
todo!()
}
fn main() {}

View file

@ -0,0 +1,42 @@
error[E0308]: `match` arms have incompatible types
--> $DIR/fn_def_opaque_coercion.rs:47:18
|
LL | type J = impl Sized;
| ---------- the expected opaque type
...
LL | let x = match true {
| _____________-
LL | | true => foo::<J>,
| | -------- this is found to be of type `fn(J) -> J {foo::<J>}`
LL | | false => foo::<()>,
| | ^^^^^^^^^ expected opaque type, found `()`
LL | | };
| |_____- `match` arms have incompatible types
|
= note: expected fn item `fn(J) -> J {foo::<J>}`
found fn item `fn(()) {foo::<()>}`
error[E0308]: `match` arms have incompatible types
--> $DIR/fn_def_opaque_coercion.rs:62:18
|
LL | fn k() -> impl Sized {
| ---------- the expected opaque type
...
LL | let x = match true {
| _____________-
LL | | true => {
LL | | let f = foo;
LL | | bind(k(), f)
| | ------------ this is found to be of type `fn(impl Sized) -> impl Sized {foo::<impl Sized>}`
LL | | }
LL | | false => foo::<()>,
| | ^^^^^^^^^ expected opaque type, found `()`
LL | | };
| |_____- `match` arms have incompatible types
|
= note: expected fn item `fn(impl Sized) -> impl Sized {foo::<impl Sized>}`
found fn item `fn(()) {foo::<()>}`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.