Why aren't generic functions implicitly comptime?

Why does this switch statement on a pure generic function require a comptime expression? Is this a bug?

const std = @import("std");

fn canBeKeyValuePair(comptime T: type) bool {
    return switch (@typeInfo(T)) {
        .@"struct" => std.meta.fields(T).len == 2,
        else => false,
    };
}

test "this test has compile error" {
    var my_bool: bool = false;
    _ = &my_bool;

    switch (canBeKeyValuePair(@TypeOf(my_bool))) {
        true => @compileError("branch analyzed (without comptime switch expression)"),
        false => {},
    }
}

test "this test passes" {
    var my_bool: bool = false;
    _ = &my_bool;

    switch (comptime canBeKeyValuePair(@TypeOf(my_bool))) {
        true => @compileError("branch analyzed (with comptime switch expression)"),
        false => {},
    }
}

Run the code with zig test test.zig and get the following output:

$ zig test test.zig 
test.zig:15:17: error: branch analyzed (without comptime switch expression)
        true => @compileError("branch analyzed (without comptime switch expression)"),

I guess I have a misunderstanding of zig as being “eagerly comptime” because there are builtins which are automatically comptime (@TypeOf, @typeInfo), but I won’t get the same automatically comptime-ness with my own functions.

I wonder if it would be nice to be able to mark my function as comptime-only…

comptime fn canBeKeyValuePair(comptime T: type) bool {

the compiler will not evaluate function calls at comptime, even if all the parameters are known at comptime, unless you tell it to.

i dont see comptime fn being a thing as then at the call sight you dont know if its called at comptime without checking the fn definition. the function could also be rather expensive to call which would be bad to run at compile time unless it was explicitly asked for.

1 Like

By making the function inline you can essentially get the result you want. This is because inline in Zig means that the function body is semantically inlined at the call site.

I may be mistaken, but should not this:

.@"struct" => std.meta.fields(T).len == 2,

…be this:

.Struct => std.meta.fields(T).len == 2,

Master: .@"struct"

0.13.0: .Struct

1 Like

Rejected: #425 and #6647.

1 Like