Help with `generic function cannot cast into a non-generic function`

Hello,

I’m new to Zig, and I’m trying to create a Fun type (code bellow) that captures a function (S => V) or an immediate value (V) after the function has been applied - via Fun.call.

The code compiles but fails at runtime with the following type mismatch error:

expected type 'fn (u32) root.Fun(u32,u32)', found 'fn (u32) root.Fun(u32,u32)'

The error reports the same type but I’m guessing (with no knowledge of Zig at all) that I’m actually dealing with two different types even if they are rendered exactly the same. (?).

I’ve been trying to search about the (generic function cannot be cast - error) and how to solve it with no success. Any help if greatly appreciated.

[2025-05-15T01:10:18.454Z] Running test: root.zig - basic add functionality
Command failed: zig/linux-x86_64-0.14.0/zig test --test-filter basic add functionality src/root.zig
src/root.zig:34:38: error: expected type 'fn (u32) root.Fun(u32,u32)', found 'fn (u32) root.Fun(u32,u32)'
            return .{ ._fun = closure.call };
                              ~~~~~~~^~~~~
src/root.zig:34:38: note: generic function cannot cast into a non-generic function
src/root.zig:13:31: note: called from here
    const f = Fun(u32, u32).mk(closure.call);
              ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~
const std = @import("std");
const testing = std.testing;

test "basic add functionality" {
    const closure = struct {
        fn call(a: u32) u32 {
            return a + 1;
        }
    };
    const f = Fun(u32, u32).mk(closure.call);
    const g = f.call(22);
    try testing.expect(g.value() == 23);
}

fn Fun(comptime S: type, comptime V: type) type {
    return union(enum) {
        fn call(self: Self, s: S) Self {
            return self._fun(s);
        }

        fn value(self: Self) V {
            return self._imm;
        }

        fn mk(fun: fn (S) V) Self {
            const closure = struct {
                fn call(s: S) Self {
                    return .{ ._imm = fun(s) };
                }
            };
            return .{ ._fun = closure.call };
        }

        const Self = @This();
        _imm: V,
        _fun: fn (S) Self,
    };
}

EDIT: for context, I’m trying to learn Zig by creating an implementation of my Fx.go - Algebraic Effect system for Golang, here’s my current progress – the code above is the minimal failing example I could made. Just wanted to provide some context on why I’m using an union, in my effect library, an Effect (Fx) is a union: either an existing value or a suspended function), but I don’t think that is even part of the issue here.

It’s failing at compile time.

The error is wrong, it should say something about runtime value cannot be determined at compile time.

This is the fix:

-_fun: fn (S) Self,
+_fun: *const fn (S) Self,

Values of type fn whatever... are compile time only. In order to manipulate them at runtime, you need functions pointers.

3 Likes

Thank you so much! Your change makes it work :slight_smile:

Indeed, do you think I should open an issue on Zig for improving the error message?

2 Likes

Yes, I think that would be good.