Rollup merge of #123794 - oli-obk:define_opaque_types2, r=lcnr
More DefineOpaqueTypes::Yes This accepts more code on stable. It is now possible to have match arms return a function item `foo::<ConcreteType>` and a function item `foo::<OpaqueTypeInDefiningScope>` in another, and that will constrain `OpaqueTypeInDefiningScope` to have the hidden type `ConcreteType`. So the following function will now compile, but on master it errors with a type mismatch on the second match arm ```rust // The function item whose generic params we want to merge. fn foo<T>(t: T) -> T { t } // Helper ensuring we can constrain `T` on `F` without explicitly specifying it fn bind<T, F: FnOnce(T) -> T>(_: T, f: F) -> F { f } fn k() -> impl Sized { let x = match true { true => { // `f` is `FnDef(foo, [infer_var])` let f = foo; // Get a value of an opaque type on stable let t = k(); // this returns `FnDef(foo, [k::return])` bind(t, f) } false => foo::<()>, }; todo!() } ``` r? ``@compiler-errors`` cc https://github.com/rust-lang/rust/issues/116652
This commit is contained in:
commit
dc81f6d549
@ -1139,7 +1139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// are the same function and their parameters have a LUB.
|
||||
match self.commit_if_ok(|_| {
|
||||
self.at(cause, self.param_env).lub(
|
||||
DefineOpaqueTypes::No,
|
||||
DefineOpaqueTypes::Yes,
|
||||
prev_ty,
|
||||
new_ty,
|
||||
)
|
||||
|
58
tests/ui/fn/fn_def_coercion.rs
Normal file
58
tests/ui/fn/fn_def_coercion.rs
Normal 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() {}
|
154
tests/ui/fn/fn_def_coercion.stderr
Normal file
154
tests/ui/fn/fn_def_coercion.stderr
Normal 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
|
||||
|
69
tests/ui/fn/fn_def_opaque_coercion.rs
Normal file
69
tests/ui/fn/fn_def_opaque_coercion.rs
Normal file
@ -0,0 +1,69 @@
|
||||
//! Test that coercing between function items of the same function,
|
||||
//! but with different generic args works.
|
||||
|
||||
//@check-pass
|
||||
|
||||
#![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::<()>,
|
||||
};
|
||||
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::<()>,
|
||||
};
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
x
Reference in New Issue
Block a user