From a18f04303366d1a7542f8e103adc740bcd90d63f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 23 Apr 2024 14:30:34 +0000 Subject: [PATCH 1/2] Add regression test --- .../ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs | 57 ++++++++++++++ .../fn_def_opaque_coercion_to_fn_ptr.stderr | 77 +++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs create mode 100644 tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr diff --git a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs new file mode 100644 index 0000000000000..4f7be6811eb1c --- /dev/null +++ b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs @@ -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 +} + +fn bar(t: T) -> T { + t +} + +type F = impl Sized; + +fn f(a: F) { + let mut x = bar::; + x = foo::<()>; //~ ERROR: mismatched types + x(a); + x(()); +} + +type I = impl Sized; + +fn i(a: I) { + let mut x = bar::<()>; + x = foo::; //~ ERROR: mismatched types + x(a); + x(()); +} + +type J = impl Sized; + +fn j(a: J) { + let x = match true { + true => bar::, + false => foo::<()>, //~ ERROR: incompatible types + }; + x(a); + x(()); +} + +fn k() -> impl Sized { + fn bind T>(_: T, f: F) -> F { + f + } + let x = match true { + true => { + let f = foo; + bind(k(), f) + } + false => bar::<()>, //~ ERROR: incompatible types + }; + todo!() +} + +fn main() {} diff --git a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr new file mode 100644 index 0000000000000..ca01376ee49da --- /dev/null +++ b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr @@ -0,0 +1,77 @@ +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::; + | -------- expected due to this value +LL | x = foo::<()>; + | ^^^^^^^^^ expected fn item, found a different fn item + | + = note: expected fn item `fn(F) -> F {bar::}` + 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 { + | -------------------- 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::; + | ^^^^^^^^ expected fn item, found a different fn item + | + = note: expected fn item `fn(()) {bar::<()>}` + found fn item `fn(I) -> I {foo::}` +help: use parentheses to call this function + | +LL | x = foo::(/* I */); + | +++++++++ + +error[E0308]: `match` arms have incompatible types + --> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:37:18 + | +LL | type J = impl Sized; + | ---------- the expected opaque type +... +LL | let x = match true { + | _____________- +LL | | true => bar::, + | | -------- this is found to be of type `fn(J) -> J {bar::}` +LL | | false => foo::<()>, + | | ^^^^^^^^^ expected opaque type, found `()` +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected fn item `fn(J) -> J {bar::}` + found fn item `fn(()) {foo::<()>}` + +error[E0308]: `match` arms have incompatible types + --> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:52: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::}` +LL | | } +LL | | false => bar::<()>, + | | ^^^^^^^^^ expected opaque type, found `()` +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected fn item `fn(impl Sized) -> impl Sized {foo::}` + found fn item `fn(()) {bar::<()>}` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. From c24148ef7b1d4a280cca60e2001848da70ff07dc Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 23 Apr 2024 14:38:17 +0000 Subject: [PATCH 2/2] Allow coercing functions whose signature differs in opaque types in their defining scope into a shared function pointer type --- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- .../ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs | 4 +- .../fn_def_opaque_coercion_to_fn_ptr.stderr | 41 +------------------ 3 files changed, 4 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 9ebb5f95f05fd..537f0b6058094 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1189,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sig = self .at(cause, self.param_env) .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))?; // Reify both sides and return the reified fn pointer type. diff --git a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs index 4f7be6811eb1c..5250e3a3d93e6 100644 --- a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs +++ b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.rs @@ -34,7 +34,7 @@ type J = impl Sized; fn j(a: J) { let x = match true { true => bar::, - false => foo::<()>, //~ ERROR: incompatible types + false => foo::<()>, }; x(a); x(()); @@ -49,7 +49,7 @@ fn k() -> impl Sized { let f = foo; bind(k(), f) } - false => bar::<()>, //~ ERROR: incompatible types + false => bar::<()>, }; todo!() } diff --git a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr index ca01376ee49da..0b3331b040d85 100644 --- a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr +++ b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr @@ -33,45 +33,6 @@ help: use parentheses to call this function LL | x = foo::(/* I */); | +++++++++ -error[E0308]: `match` arms have incompatible types - --> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:37:18 - | -LL | type J = impl Sized; - | ---------- the expected opaque type -... -LL | let x = match true { - | _____________- -LL | | true => bar::, - | | -------- this is found to be of type `fn(J) -> J {bar::}` -LL | | false => foo::<()>, - | | ^^^^^^^^^ expected opaque type, found `()` -LL | | }; - | |_____- `match` arms have incompatible types - | - = note: expected fn item `fn(J) -> J {bar::}` - found fn item `fn(()) {foo::<()>}` - -error[E0308]: `match` arms have incompatible types - --> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:52: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::}` -LL | | } -LL | | false => bar::<()>, - | | ^^^^^^^^^ expected opaque type, found `()` -LL | | }; - | |_____- `match` arms have incompatible types - | - = note: expected fn item `fn(impl Sized) -> impl Sized {foo::}` - found fn item `fn(()) {bar::<()>}` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`.