Rollup merge of #124297 - oli-obk:define_opaque_types13, r=jackh726
Allow coercing functions whose signature differs in opaque types in their defining scope into a shared function pointer type r? `@compiler-errors` This accepts more code on stable. It is now possible to have match arms return a function item `foo` and a different function item `bar` in another, and that will constrain OpaqueTypeInDefiningScope to have the hidden type ConcreteType and make the type of the match arms a function pointer that matches the signature. So the following function will now compile, but on master it errors with a type mismatch on the second match arm ```rust fn foo<T>(t: T) -> T { t } fn bar<T>(t: T) -> T { t } 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 => bar::<()>, }; todo!() } ``` cc https://github.com/rust-lang/rust/issues/116652 This is very similar to https://github.com/rust-lang/rust/pull/123794, and with the same rationale: > this is for consistency with `-Znext-solver`. the new solver does not have the concept of "non-defining use of opaque" right now and we would like to ideally keep it that way. Moving to `DefineOpaqueTypes::Yes` in more cases removes subtlety from the type system. Right now we have to be careful when relating `Opaque` with another type as the behavior changes depending on whether we later use the `Opaque` or its hidden type directly (even though they are equal), if that later use is with `DefineOpaqueTypes::No`*
This commit is contained in:
commit
abcf400a28
@ -1159,7 +1159,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let sig = self
|
let sig = self
|
||||||
.at(cause, self.param_env)
|
.at(cause, self.param_env)
|
||||||
.trace(prev_ty, new_ty)
|
.trace(prev_ty, new_ty)
|
||||||
.lub(DefineOpaqueTypes::No, a_sig, b_sig)
|
.lub(DefineOpaqueTypes::Yes, a_sig, b_sig)
|
||||||
.map(|ok| self.register_infer_ok_obligations(ok))?;
|
.map(|ok| self.register_infer_ok_obligations(ok))?;
|
||||||
|
|
||||||
// Reify both sides and return the reified fn pointer type.
|
// Reify both sides and return the reified fn pointer type.
|
||||||
|
57
tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs
Normal file
57
tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
//! Test that coercing between function items of different functions works,
|
||||||
|
//! as long as their signatures match. The resulting value is a function pointer.
|
||||||
|
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
fn foo<T>(t: T) -> T {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar<T>(t: T) -> T {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
type F = impl Sized;
|
||||||
|
|
||||||
|
fn f(a: F) {
|
||||||
|
let mut x = bar::<F>;
|
||||||
|
x = foo::<()>; //~ ERROR: mismatched types
|
||||||
|
x(a);
|
||||||
|
x(());
|
||||||
|
}
|
||||||
|
|
||||||
|
type I = impl Sized;
|
||||||
|
|
||||||
|
fn i(a: I) {
|
||||||
|
let mut x = bar::<()>;
|
||||||
|
x = foo::<I>; //~ ERROR: mismatched types
|
||||||
|
x(a);
|
||||||
|
x(());
|
||||||
|
}
|
||||||
|
|
||||||
|
type J = impl Sized;
|
||||||
|
|
||||||
|
fn j(a: J) {
|
||||||
|
let x = match true {
|
||||||
|
true => bar::<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 => bar::<()>,
|
||||||
|
};
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
38
tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr
Normal file
38
tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:18:9
|
||||||
|
|
|
||||||
|
LL | type F = impl Sized;
|
||||||
|
| ---------- the expected opaque type
|
||||||
|
...
|
||||||
|
LL | let mut x = bar::<F>;
|
||||||
|
| -------- expected due to this value
|
||||||
|
LL | x = foo::<()>;
|
||||||
|
| ^^^^^^^^^ expected fn item, found a different fn item
|
||||||
|
|
|
||||||
|
= note: expected fn item `fn(F) -> F {bar::<F>}`
|
||||||
|
found fn item `fn(()) {foo::<()>}`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:27:9
|
||||||
|
|
|
||||||
|
LL | fn foo<T>(t: T) -> T {
|
||||||
|
| -------------------- function `foo` defined here
|
||||||
|
...
|
||||||
|
LL | type I = impl Sized;
|
||||||
|
| ---------- the found opaque type
|
||||||
|
...
|
||||||
|
LL | let mut x = bar::<()>;
|
||||||
|
| --------- expected due to this value
|
||||||
|
LL | x = foo::<I>;
|
||||||
|
| ^^^^^^^^ expected fn item, found a different fn item
|
||||||
|
|
|
||||||
|
= note: expected fn item `fn(()) {bar::<()>}`
|
||||||
|
found fn item `fn(I) -> I {foo::<I>}`
|
||||||
|
help: use parentheses to call this function
|
||||||
|
|
|
||||||
|
LL | x = foo::<I>(/* I */);
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
x
Reference in New Issue
Block a user