authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-10-17 10:19:14+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-10-18 08:50:40+01:00
log097766bba3d7f45df41a4233f849db99e1bb8676
tree71f8f296c31380be83d99639dbfd4ca71d61bb2b
parentfffbb511db5de611ca670fc13a223ddbe255c92c

compiler: implement `@FieldType`

Resolves: #21702

7 files changed, 103 insertions(+), 1 deletions(-)

doc/langref.html.in+7
...@@ -4879,6 +4879,13 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -4879,6 +4879,13 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
4879 </p>4879 </p>
4880 {#header_close#}4880 {#header_close#}
48814881
4882 {#header_open|@FieldType#}
4883 <pre>{#syntax#}@FieldType(comptime Type: type, comptime field_name: []const u8) type{#endsyntax#}</pre>
4884 <p>
4885 Given a type and the name of one of its fields, returns the type of that field.
4886 </p>
4887 {#header_close#}
4888
4882 {#header_open|@floatCast#}4889 {#header_open|@floatCast#}
4883 <pre>{#syntax#}@floatCast(value: anytype) anytype{#endsyntax#}</pre>4890 <pre>{#syntax#}@floatCast(value: anytype) anytype{#endsyntax#}</pre>
4884 <p>4891 <p>
lib/std/zig/AstGen.zig+9
...@@ -9274,6 +9274,15 @@ fn builtinCall(...@@ -9274,6 +9274,15 @@ fn builtinCall(
9274 });9274 });
9275 return rvalue(gz, ri, result, node);9275 return rvalue(gz, ri, result, node);
9276 },9276 },
9277 .FieldType => {
9278 const ty_inst = try typeExpr(gz, scope, params[0]);
9279 const name_inst = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1]);
9280 const result = try gz.addPlNode(.field_type_ref, node, Zir.Inst.FieldTypeRef{
9281 .container_type = ty_inst,
9282 .field_name = name_inst,
9283 });
9284 return rvalue(gz, ri, result, node);
9285 },
92779286
9278 // zig fmt: off9287 // zig fmt: off
9279 .as => return as( gz, scope, ri, node, params[0], params[1]),9288 .as => return as( gz, scope, ri, node, params[0], params[1]),
lib/std/zig/AstRlAnnotate.zig+6-1
...@@ -914,7 +914,6 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast....@@ -914,7 +914,6 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
914 .work_item_id,914 .work_item_id,
915 .work_group_size,915 .work_group_size,
916 .work_group_id,916 .work_group_id,
917 .field_parent_ptr,
918 => {917 => {
919 _ = try astrl.expr(args[0], block, ResultInfo.type_only);918 _ = try astrl.expr(args[0], block, ResultInfo.type_only);
920 return false;919 return false;
...@@ -983,11 +982,17 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast....@@ -983,11 +982,17 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
983 .has_decl,982 .has_decl,
984 .has_field,983 .has_field,
985 .field,984 .field,
985 .FieldType,
986 => {986 => {
987 _ = try astrl.expr(args[0], block, ResultInfo.type_only);987 _ = try astrl.expr(args[0], block, ResultInfo.type_only);
988 _ = try astrl.expr(args[1], block, ResultInfo.type_only);988 _ = try astrl.expr(args[1], block, ResultInfo.type_only);
989 return false;989 return false;
990 },990 },
991 .field_parent_ptr => {
992 _ = try astrl.expr(args[0], block, ResultInfo.type_only);
993 _ = try astrl.expr(args[1], block, ResultInfo.none);
994 return false;
995 },
991 .wasm_memory_grow => {996 .wasm_memory_grow => {
992 _ = try astrl.expr(args[0], block, ResultInfo.type_only);997 _ = try astrl.expr(args[0], block, ResultInfo.type_only);
993 _ = try astrl.expr(args[1], block, ResultInfo.type_only);998 _ = try astrl.expr(args[1], block, ResultInfo.type_only);
lib/std/zig/BuiltinFn.zig+8
...@@ -50,6 +50,7 @@ pub const Tag = enum {...@@ -50,6 +50,7 @@ pub const Tag = enum {
50 @"extern",50 @"extern",
51 field,51 field,
52 field_parent_ptr,52 field_parent_ptr,
53 FieldType,
53 float_cast,54 float_cast,
54 int_from_float,55 int_from_float,
55 frame,56 frame,
...@@ -516,6 +517,13 @@ pub const list = list: {...@@ -516,6 +517,13 @@ pub const list = list: {
516 .param_count = 2,517 .param_count = 2,
517 },518 },
518 },519 },
520 .{
521 "@FieldType",
522 .{
523 .tag = .FieldType,
524 .param_count = 2,
525 },
526 },
519 .{527 .{
520 "@floatCast",528 "@floatCast",
521 .{529 .{
test/behavior/struct.zig+24
...@@ -2159,3 +2159,27 @@ test "matching captures causes struct equivalence" {...@@ -2159,3 +2159,27 @@ test "matching captures causes struct equivalence" {
2159 comptime assert(@TypeOf(a) == @TypeOf(b));2159 comptime assert(@TypeOf(a) == @TypeOf(b));
2160 try expect(a.x == b.x);2160 try expect(a.x == b.x);
2161}2161}
2162
2163test "struct @FieldType" {
2164 const S = struct {
2165 a: u32,
2166 b: f64,
2167 c: *@This(),
2168 };
2169
2170 comptime assert(@FieldType(S, "a") == u32);
2171 comptime assert(@FieldType(S, "b") == f64);
2172 comptime assert(@FieldType(S, "c") == *S);
2173}
2174
2175test "extern struct @FieldType" {
2176 const S = extern struct {
2177 a: u32,
2178 b: f64,
2179 c: *@This(),
2180 };
2181
2182 comptime assert(@FieldType(S, "a") == u32);
2183 comptime assert(@FieldType(S, "b") == f64);
2184 comptime assert(@FieldType(S, "c") == *S);
2185}
test/behavior/union.zig+36
...@@ -2339,3 +2339,39 @@ test "signed enum tag with negative value" {...@@ -2339,3 +2339,39 @@ test "signed enum tag with negative value" {
23392339
2340 try expect(e.a == i);2340 try expect(e.a == i);
2341}2341}
2342
2343test "union @FieldType" {
2344 const U = union {
2345 a: u32,
2346 b: f64,
2347 c: *@This(),
2348 };
2349
2350 comptime assert(@FieldType(U, "a") == u32);
2351 comptime assert(@FieldType(U, "b") == f64);
2352 comptime assert(@FieldType(U, "c") == *U);
2353}
2354
2355test "tagged union @FieldType" {
2356 const U = union(enum) {
2357 a: u32,
2358 b: f64,
2359 c: *@This(),
2360 };
2361
2362 comptime assert(@FieldType(U, "a") == u32);
2363 comptime assert(@FieldType(U, "b") == f64);
2364 comptime assert(@FieldType(U, "c") == *U);
2365}
2366
2367test "extern union @FieldType" {
2368 const U = extern union {
2369 a: u32,
2370 b: f64,
2371 c: *@This(),
2372 };
2373
2374 comptime assert(@FieldType(U, "a") == u32);
2375 comptime assert(@FieldType(U, "b") == f64);
2376 comptime assert(@FieldType(U, "c") == *U);
2377}
test/cases/compile_errors/invalid_field_type_usage.zig created+13
...@@ -0,0 +1,13 @@
1export fn foo() void {
2 _ = @FieldType(u8, "a");
3}
4export fn bar() void {
5 const S = struct { a: u8 };
6 _ = @FieldType(S, "b");
7}
8
9// error
10//
11// :2:20: error: expected struct or union; found 'u8'
12// :6:23: error: no field named 'b' in struct 'tmp.bar.S'
13// :5:15: note: struct declared here