authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-07 17:52:24-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-08 19:15:10+02:00
log8dfddf95fee5982d22512c0ac15278eabac5bcbb
tree0cd22c5bea3cb861971dc4820e59d8b41120e698
parent3239f672d2aa61ad0fea0f400cd7917fa354ea0f

std.meta: deprecate fieldInfo, fieldNames, fieldTypes

Technically there is one valid use case for `fieldNames` which is use with an enum or union so that those types can be used interchangeably. But in practice these functions are mainly abused, because the callsites always know what kind of type it is. This commit encourages Zig users to embrace using `@typeInfo` directly when doing type reflection.

15 files changed, 41 insertions(+), 29 deletions(-)

lib/std/Build.zig+2-2
......@@ -1109,7 +1109,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
11091109 const type_id = comptime typeToEnum(T);
11101110 const enum_options = if (type_id == .@"enum" or type_id == .enum_list) blk: {
11111111 const EnumType = if (type_id == .enum_list) @typeInfo(T).pointer.child else T;
1112 const field_names = comptime std.meta.fieldNames(EnumType);
1112 const field_names = @typeInfo(EnumType).@"enum".field_names;
11131113 var options = std.array_list.Managed([]const u8).initCapacity(b.allocator, field_names.len) catch @panic("OOM");
11141114
11151115 inline for (field_names) |field_name| {
......@@ -1420,7 +1420,7 @@ pub fn parseTargetQuery(options: std.Target.Query.ParseOptions) error{ParseFaile
14201420 \\available operating systems:
14211421 \\
14221422 , .{diags.os_name.?});
1423 inline for (comptime std.meta.fieldNames(Target.Os.Tag)) |field_name| {
1423 inline for (@typeInfo(Target.Os.Tag).@"enum".field_names) |field_name| {
14241424 std.debug.print(" {s}\n", .{field_name});
14251425 }
14261426 return error.ParseFailed;
lib/std/enums.zig+3-2
......@@ -33,7 +33,8 @@ pub fn fromInt(comptime E: type, integer: anytype) ?E {
3333pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type {
3434 @setEvalBranchQuota(@typeInfo(E).@"enum".field_names.len + eval_branch_quota_cushion);
3535 const default_ptr: ?*const anyopaque = if (field_default) |d| @ptrCast(&d) else null;
36 return @Struct(.auto, null, std.meta.fieldNames(E), &@splat(Data), &@splat(.{ .default_value_ptr = default_ptr }));
36 const field_names = @typeInfo(E).@"enum".field_names;
37 return @Struct(.auto, null, field_names, &@splat(Data), &@splat(.{ .default_value_ptr = default_ptr }));
3738}
3839
3940/// Looks up the supplied field values in the given enum type.
......@@ -454,7 +455,7 @@ pub fn EnumMap(comptime E: type, comptime V: type) type {
454455 }
455456 }
456457 } else {
457 inline for (std.meta.fieldNames(E)) |field_name| {
458 inline for (@typeInfo(E).@"enum".field_names) |field_name| {
458459 const key = @field(E, field_name);
459460 if (@field(init_values, field_name)) |*v| {
460461 const i = comptime Indexer.indexOf(key);
lib/std/meta.zig+18-7
......@@ -197,15 +197,17 @@ test containerLayout {
197197 try testing.expect(containerLayout(U3) == .@"extern");
198198}
199199
200/// Instead of this function, prefer to use e.g. `@typeInfo(foo).@"struct".decl_names`
201/// directly when you know what kind of type it is.
200/// Returns the list of declaration names of namespace types.
201///
202/// This function is only useful when the callsite does not know statically
203/// which kind of container it is.
202204pub fn declarations(comptime T: type) []const [:0]const u8 {
203205 return switch (@typeInfo(T)) {
204206 .@"struct" => |info| info.decl_names,
205207 .@"enum" => |info| info.decl_names,
206208 .@"union" => |info| info.decl_names,
207209 .@"opaque" => |info| info.decl_names,
208 else => @compileError("Expected struct, enum, union, or opaque type, found '" ++ @typeName(T) ++ "'"),
210 else => comptime unreachable, // type lacks namespace
209211 };
210212}
211213
......@@ -241,10 +243,13 @@ test declarations {
241243}
242244
243245/// To be removed after Zig 0.17.0 is tagged.
244pub const declarationInfo = @compileError("Deprecated; use '@hasDecl' instead");
246pub const declarationInfo = @compileError("deprecated in favor of @hasDecl");
245247/// To be removed after Zig 0.17.0 is tagged.
246pub const fields = @compileError("Deprecated; use 'fieldNames' and 'fieldTypes' instead");
248pub const fields = @compileError("deprecated in favor of @typeInfo");
247249
250/// Deprecated in favor of `@typeInfo`.
251///
252/// To be removed after 0.17.0 is tagged.
248253pub fn fieldInfo(comptime T: type, comptime field: FieldEnum(T)) switch (@typeInfo(T)) {
249254 .@"struct" => struct { name: [:0]const u8, type: type, attrs: Type.Struct.FieldAttributes },
250255 .@"union" => struct { name: [:0]const u8, type: type, attrs: Type.Union.FieldAttributes },
......@@ -298,13 +303,16 @@ test fieldInfo {
298303 try testing.expect(comptime uf.type == u8);
299304}
300305
306/// Deprecated in favor of `@typeInfo`.
307///
308/// To be removed after 0.17.0 is tagged.
301309pub fn fieldNames(comptime T: type) []const [:0]const u8 {
302310 return switch (@typeInfo(T)) {
303311 .@"struct" => |s| s.field_names,
304312 .@"union" => |u| u.field_names,
305313 .@"enum" => |e| e.field_names,
306314 .error_set => |es| es.error_names.?,
307 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
315 else => comptime unreachable,
308316 };
309317}
310318
......@@ -336,11 +344,14 @@ test fieldNames {
336344 try testing.expectEqualSlices(u8, u1names[1], "b");
337345}
338346
347/// Deprecated in favor of `@typeInfo`.
348///
349/// To be removed after 0.17.0 is tagged.
339350pub fn fieldTypes(comptime T: type) []const type {
340351 return switch (@typeInfo(T)) {
341352 .@"struct" => |s| s.field_types,
342353 .@"union" => |u| u.field_types,
343 else => @compileError("Expected struct or union type, found '" ++ @typeName(T) ++ "'"),
354 else => comptime unreachable,
344355 };
345356}
346357
lib/std/zig/AstGen.zig+2-2
......@@ -74,13 +74,13 @@ src_hasher: std.zig.SrcHasher,
7474const InnerError = error{ OutOfMemory, AnalysisFail };
7575
7676fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 {
77 const field_count = std.meta.fieldNames(@TypeOf(extra)).len;
77 const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len;
7878 try astgen.extra.ensureUnusedCapacity(astgen.gpa, field_count);
7979 return addExtraAssumeCapacity(astgen, extra);
8080}
8181
8282fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 {
83 const field_count = std.meta.fieldNames(@TypeOf(extra)).len;
83 const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len;
8484 const extra_index: u32 = @intCast(astgen.extra.items.len);
8585 astgen.extra.items.len += field_count;
8686 setExtra(astgen, extra_index, extra);
lib/std/zig/LibCInstallation.zig+1-1
......@@ -43,7 +43,7 @@ pub const FindError = error{
4343pub fn parse(allocator: Allocator, io: Io, libc_file: []const u8, target: *const std.Target) !LibCInstallation {
4444 var self: LibCInstallation = .{};
4545
46 const field_names = comptime std.meta.fieldNames(LibCInstallation);
46 const field_names = @typeInfo(LibCInstallation).@"struct".field_names;
4747 const FoundKey = struct {
4848 found: bool,
4949 allocated: ?[]u8,
lib/std/zig/llvm/Builder.zig+2-2
......@@ -9517,7 +9517,7 @@ pub const Metadata = packed struct(u32) {
95179517 nodes: anytype,
95189518 w: *Writer,
95199519 ) !void {
9520 const names = comptime std.meta.fieldNames(@TypeOf(nodes));
9520 const names = @typeInfo(@TypeOf(nodes)).@"struct".field_names;
95219521
95229522 comptime var fmt_str: []const u8 = "{[distinct]s}{[node]s}(";
95239523 inline for (names) |name| fmt_str = fmt_str ++ "{[" ++ name ++ "]f}";
......@@ -13484,7 +13484,7 @@ fn metadataSimpleAssumeCapacity(self: *Builder, tag: Metadata.Tag, value: anytyp
1348413484 builder: *const Builder,
1348513485 pub fn hash(_: @This(), key: Key) u32 {
1348613486 var hasher = std.hash.Wyhash.init(std.hash.int(@backingInt(key.tag)));
13487 inline for (comptime std.meta.fieldNames(@TypeOf(value))) |field_name| {
13487 inline for (@typeInfo(@TypeOf(value)).@"struct".field_names) |field_name| {
1348813488 hasher.update(std.mem.asBytes(&@field(key.value, field_name)));
1348913489 }
1349013490 return @truncate(hasher.final());
lib/std/zig/llvm/bitcode_writer.zig+1-1
......@@ -246,7 +246,7 @@ pub fn BitcodeWriter(comptime types: []const type) type {
246246
247247 try self.bitcode.writeBits(comptime abbrevId(Abbrev), abbrev_len);
248248
249 const field_names = comptime std.meta.fieldNames(Abbrev);
249 const field_names = @typeInfo(Abbrev).@"struct".field_names;
250250
251251 // This abbreviation might only contain literals
252252 if (field_names.len == 0) return;
lib/std/zig/system.zig+1-1
......@@ -973,7 +973,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
973973 // relying on `builtin.target`.
974974 const all_abis = comptime blk: {
975975 assert(@backingInt(Target.Abi.none) == 0);
976 const field_names = std.meta.fieldNames(Target.Abi)[1..];
976 const field_names = @typeInfo(Target.Abi).@"enum".field_names[1..];
977977 var array: [field_names.len]Target.Abi = undefined;
978978 for (field_names, 0..) |field_name, i| {
979979 array[i] = @field(Target.Abi, field_name);
src/Air/Liveness.zig+3-3
......@@ -351,7 +351,7 @@ const Analysis = struct {
351351 extra: std.ArrayList(u32),
352352
353353 fn addExtra(a: *Analysis, extra: anytype) Allocator.Error!u32 {
354 const field_count = std.meta.fieldNames(@TypeOf(extra)).len;
354 const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len;
355355 try a.extra.ensureUnusedCapacity(a.gpa, field_count);
356356 return addExtraAssumeCapacity(a, extra);
357357 }
......@@ -1012,7 +1012,7 @@ fn analyzeInstBlock(
10121012 const block_scope = data.block_scopes.get(inst).?;
10131013 const num_deaths = data.live_set.count() - block_scope.live_set.count();
10141014
1015 try a.extra.ensureUnusedCapacity(gpa, num_deaths + std.meta.fieldNames(Block).len);
1015 try a.extra.ensureUnusedCapacity(gpa, num_deaths + @typeInfo(Block).@"struct".field_names.len);
10161016 const extra_index = a.addExtraAssumeCapacity(Block{
10171017 .death_count = num_deaths,
10181018 });
......@@ -1275,7 +1275,7 @@ fn analyzeInstCondBr(
12751275 // Write the mirrored deaths to `extra`
12761276 const then_death_count = @as(u32, @intCast(then_mirrored_deaths.items.len));
12771277 const else_death_count = @as(u32, @intCast(else_mirrored_deaths.items.len));
1278 try a.extra.ensureUnusedCapacity(gpa, std.meta.fieldNames(CondBr).len + then_death_count + else_death_count);
1278 try a.extra.ensureUnusedCapacity(gpa, @typeInfo(CondBr).@"struct".field_names.len + then_death_count + else_death_count);
12791279 const extra_index = a.addExtraAssumeCapacity(CondBr{
12801280 .then_death_count = then_death_count,
12811281 .else_death_count = else_death_count,
src/Sema.zig+1-1
......@@ -34033,7 +34033,7 @@ pub fn getTmpAir(sema: Sema) Air {
3403334033}
3403434034
3403534035pub fn addExtra(sema: *Sema, extra: anytype) Allocator.Error!u32 {
34036 const field_count = std.meta.fieldNames(@TypeOf(extra)).len;
34036 const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len;
3403734037 try sema.air_extra.ensureUnusedCapacity(sema.gpa, field_count);
3403834038 return sema.addExtraAssumeCapacity(extra);
3403934039}
src/codegen/riscv64/encoding.zig+1-1
......@@ -498,7 +498,7 @@ pub const Instruction = union(Lir.Format) {
498498 extra: u32,
499499
500500 comptime {
501 for (std.meta.fieldTypes(Instruction)) |field_type| {
501 for (@typeInfo(Instruction).@"union".field_types) |field_type| {
502502 assert(@bitSizeOf(field_type) == 32);
503503 }
504504 }
src/codegen/wasm/CodeGen.zig+1-1
......@@ -567,7 +567,7 @@ fn addCallIntrinsic(cg: *CodeGen, intrinsic: Mir.Intrinsic) error{OutOfMemory}!v
567567/// Appends entries to `mir_extra` based on the type of `extra`.
568568/// Returns the index into `mir_extra`
569569fn addExtra(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {
570 const field_count = std.meta.fieldNames(@TypeOf(extra)).len;
570 const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len;
571571 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, field_count);
572572 return cg.addExtraAssumeCapacity(extra);
573573}
src/codegen/x86_64/CodeGen.zig+1-1
......@@ -1301,7 +1301,7 @@ fn addInst(self: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
13011301}
13021302
13031303fn addExtra(self: *CodeGen, extra: anytype) Allocator.Error!u32 {
1304 const field_count = std.meta.fieldNames(@TypeOf(extra)).len;
1304 const field_count = @typeInfo(@TypeOf(extra)).@"struct".field_names.len;
13051305 try self.mir_extra.ensureUnusedCapacity(self.gpa, field_count);
13061306 return self.addExtraAssumeCapacity(extra);
13071307}
src/link/Coff.zig+1-1
......@@ -3654,7 +3654,7 @@ fn verifyParentSectionAttributes(
36543654 parent.name(coff).toSlice(coff),
36553655 });
36563656
3657 inline for (comptime std.meta.fieldNames(ObjectSectionAttributes)) |field| {
3657 inline for (@typeInfo(ObjectSectionAttributes).@"struct".field_names) |field| {
36583658 if (@field(child_attrs, field) != @field(parent_attrs, field)) {
36593659 err.addNote("flags.{s} was {d} in {s}, but {d} in {s}", .{
36603660 field,
src/print_targets.zig+3-3
......@@ -43,9 +43,9 @@ pub fn cmdTargets(
4343 {
4444 var root_obj = try serializer.beginStruct(.{});
4545
46 try root_obj.field("arch", meta.fieldNames(Target.Cpu.Arch), .{});
47 try root_obj.field("os", meta.fieldNames(Target.Os.Tag), .{});
48 try root_obj.field("abi", meta.fieldNames(Target.Abi), .{});
46 try root_obj.field("arch", @typeInfo(Target.Cpu.Arch).@"enum".field_names, .{});
47 try root_obj.field("os", @typeInfo(Target.Os.Tag).@"enum".field_names, .{});
48 try root_obj.field("abi", @typeInfo(Target.Abi).@"enum".field_names, .{});
4949
5050 {
5151 var libc_obj = try root_obj.beginTupleField("libc", .{});