How to get the type of a field of an anonymous type?

const A = struct {
	x: B,
	
	// y: @TypeOf(x.foo), // not compile
	// z: @TypeOf(A{}.x.foo), // not compile
	w: @TypeOf(B.foo), // compiles, but looks not right
};

const B = union(enum) {
	foo: struct {
		a: u32,
	},
	bar: struct {
		b: u64,
	},
};

Never mind, figured it out.

const T = @typeInfo(B).Union.fields[@intFromEnum(B.foo)].type;

But could anyone confirm that whether or not @TypeOf(B.foo) should compile?

Is there @intFromEnum alike builtin function to get the index of a struct field?

Out of curiosity, what is wrong with @TypeOf(B.foo)?

Because foo is a field, not a declaration. What compiles should be aValueOfB.foo,

const std = @import("std");

const B = union(enum) {
	foo: struct {
		a: u32,
	},
	bar: struct {
		b: u64,
	},
};

const T = @TypeOf(B.foo); // not compile here

pub fn main() !void {
	var x: T = undefined;
	x = .{.a = 123};
	std.debug.print("{}\n", .{x});
}
1 Like

There’s a helper function in the standard library which does what you’re looking for here: std.meta.FieldType(B, .foo)

B.foo is indeed meant to compile, but it’s not doing what you think. Tagged unions have an underlying “tag type”, which is inferred when you write union(enum) - in this case it’s basically enum { foo, bar }. UnionType.foo is allowed as a convenient shorthand for constructing values of this tag type - union values coerce to their tag, and fields with a void payload can be coerced to from their tag. (That is, MyUnion.my_tag coerces to MyUnion{ .my_tag = {} }.)

If you do @compileLog(B.foo) you’ll see that it has type @typeInfo(main.B).Union.tag_type.?, which is just how the automatically-generated tag type is written.

2 Likes

Thanks very much for the explanations. Not aware of that the meta module also provides some reflection functionalities.