Tuples of functions do not coerce to tuples of function pointers
Hi
Following code does not compile in current nightly even though error message does not seem to have valid meaning. Returning single function in both match arms compiles successfully.
fn m(i:i8) {
let (l, r) = match i {
0 => {
fn f1()-> bool { true };
fn f2()-> bool { true };
(f1, f2)
}
1 => {
fn f1()-> bool { true };
fn f2()-> bool { true };
(f1, f2)
}
};
}
fn main() {
m(0)
}
error[E0308]: match arms have incompatible types
--> src/main.rs:2:16
|
2 | let (l, r) = match i {
| ________________^
3 | | 0 => {
4 | | fn f1()-> bool { true };
5 | | fn f2()-> bool { true };
... |
12 | | }
13 | | };
| |___^ expected fn item, found a different fn item
|
= note: expected type `(fn() -> bool {m::f1}, fn() -> bool {m::f2})` (fn item)
found type `(fn() -> bool {m::f1}, fn() -> bool {m::f2})` (fn item)
note: match arm with an incompatible type
Each function has a unique type. You just happen to have given them the same names so the error message sounds silly. This sounds annoying and pointless but it isn't: the fact that each one is unique means there is only one possible value (namely, a pointer to the unique function), so the value actually isn't stored at all:
f1and(f1, f2)have size zero. When you cast or coerce to a function pointer then they have to store the value and are no longer zero-sized.So you can put in explicit casts and it will work:
(f1 as fn()->bool, f2 as fn()->bool). As for why it works when there is only one function, I believe automatic coercions are attempted to make the match arms compatible, and function "pointers" coerce but tuples don't.Alex Burka at 2017-08-04 18:25:07
Ok, thanks for explanation. Casting works fine. Although, automatic coercion is better, imho.
Denis Golovan at 2017-08-07 08:11:49
I ran into this, here's a simplified example:
fn f() {} fn g() {} fn main() { [f, g]; }The above compiles, but apply this:
- [f, g]; + [(f,), (g,)];And you'll get this error:
error[E0308]: mismatched types --> src/main.rs:5:13 | 5 | [(f,), (g,)]; | ^ expected fn item, found a different fn item | = note: expected fn item `fn() {f}` found fn item `fn() {g}` = note: different fn items have unique types, even if their signatures are the same = help: consider casting both fn items to fn pointers using `as fn()`
I found two workarounds:
- Cast each function with
as fn()(use a type alias if your type is huge).
type MyFn = fn(); [(f as MyFn,), (g as MyFn,)];- Add type annotations.
type MyTuple = (fn(),); let _: [MyTuple; 2] = [(f,), (g,)];I personally prefer annotations over casting repeatedly.
João Marcos at 2024-01-30 02:00:16
- Cast each function with