zig icon indicating copy to clipboard operation
zig copied to clipboard

std.ArrayList(non-u8).Writer being a compileError hinders introspection

Open michaelbartnett opened this issue 2 years ago • 0 comments

Zig Version

0.12.0-dev.1835+697b8f7d2

Steps to Reproduce and Observed Behavior

I'm writing some code that does some comptime introspection on types, but in order to check if a declaration is a type I want to recurse into, I need to use @TypeOf(@field(T, decl.name)), which triggers the compileError: "The Writer interface is only defined for ArrayList(u8)".

Here's a reduced example:

const std = @import("std");

pub fn listTypeDecls(comptime T: type) void {
    inline for (comptime std.meta.declarations(T)) |decl| {
        if (comptime @TypeOf(@field(T, decl.name)) == type) {
            std.log.info("{s}.{s} is a type", .{ @typeName(T), decl.name });
        }
    }
}

pub fn main() void {
    listTypeDecls(std.ArrayList(i32));
}

That produces this compiler output, which makes sense because @field is accessing the Writer declaration:

PS C:\Users\micha\dev\zigbug> zig build
zig build-exe zigbug Debug native: error: the following command failed with 1 compilation errors:
C:\standalone_programs\zigup\zig\0.12.0-dev.1835+697b8f7d2\files\zig.exe build-exe C:\Users\micha\dev\zigbug\src\main.zig --cache-dir C:\Users\micha\dev\zigbug\zig-cache --global-cache-dir C:\Users\micha\AppData\Local\zig --name zigbug --listen=-
Build Summary: 0/3 steps succeeded; 1 failed (disable with --summary none)
install transitive failure
└─ install zigbug transitive failure
   └─ zig build-exe zigbug Debug native 1 errors
C:\standalone_programs\zigup\zig\0.12.0-dev.1835+697b8f7d2\files\lib\std\array_list.zig:348:13: error: The Writer interface is only defined for ArrayList(u8) but the given type is ArrayList(i32)
            @compileError("The Writer interface is only defined for ArrayList(u8) " ++
            ^~~~~~~~~~~~~
referenced by:
    listTypeDecls__anon_2708: src\main.zig:6:30
    main: src\main.zig:19:18
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

Checking for well-known types (e.g. if (comptime !std.mem.startsWith(@typeName(T), "array_list.ArrayList") and std.mem.eql(decl.name, "Writer")) {) doesn't prevent the error.

That listTypeDecls function resembles std.testing.refAllDecls, which also will not compile if you pass it std.ArrayList(non-u8) and try to run tests:

const std = @import("std");

test "refAllDecls error" {
    std.testing.refAllDecls(std.ArrayList(i32));
}

Expected Behavior

Barring some other overriding concern, if a standard library type is commonly used I expect to be able to iterate over its decls and check the type of those decls so I can introspect on nested types.

I also expect to still have a nice error when I try to call ArrayList(non-u8).writer(), but in a way that doesn't prevent looking at the decls of ArrayList (and other types using this idiom) at comptime.

michaelbartnett avatar Dec 22 '23 21:12 michaelbartnett