Weirdness in using std.meta.hasMethod

It looks, std.meta.hasMethod always returns false?
But if I move out its implementation, then it may return true.
(zig version: 0.14.1)

const std = @import("std");

const A = struct {
    fn foo(_: A) void {}
    fn bar() void {}
};

pub inline fn hasFn(comptime T: type, comptime name: []const u8) bool {
    switch (@typeInfo(T)) {
        .@"struct", .@"union", .@"enum", .@"opaque" => {},
        else => return false,
    }
    if (!@hasDecl(T, name))
        return false;

    return @typeInfo(@TypeOf(@field(T, name))) == .@"fn";
}

pub inline fn hasMethod(comptime T: type, comptime name: []const u8) bool {
    return switch (@typeInfo(T)) {
        .pointer => |P| switch (P.size) {
            .one => hasFn(P.child, name),
            .many, .slice, .c => false,
        },
        else => hasFn(T, name),
    };
}

pub fn main() void {
    std.debug.print("{}\n", .{std.meta.hasMethod(A, "foo")}); // false
    std.debug.print("{}\n", .{std.meta.hasMethod(A, "bar")}); // false
    std.debug.print("{}\n", .{hasMethod(A, "foo")}); // true
    std.debug.print("{}\n", .{hasMethod(A, "bar")}); // true
}

A bug or I made some mistake here?

1 Like

I think the methods need to be declared with pub so that they will be visible.

4 Likes

I think the methods need to be declared with pub so that they will be visible.

It looks this is true. The root cause is @hasDecl is called in an external file other than the one declaring the type A. Thanks for the explanation.

Still, there’s an odd smell that’s challenging for me to pinpoint accurately.