Skip to content

Commit

Permalink
compiler: implement @FieldType
Browse files Browse the repository at this point in the history
Resolves: #21702
  • Loading branch information
mlugg committed Oct 18, 2024
1 parent fffbb51 commit 097766b
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 1 deletion.
7 changes: 7 additions & 0 deletions doc/langref.html.in
Original file line number Diff line number Diff line change
Expand Up @@ -4879,6 +4879,13 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
</p>
{#header_close#}

{#header_open|@FieldType#}
<pre>{#syntax#}@FieldType(comptime Type: type, comptime field_name: []const u8) type{#endsyntax#}</pre>
<p>
Given a type and the name of one of its fields, returns the type of that field.
</p>
{#header_close#}

{#header_open|@floatCast#}
<pre>{#syntax#}@floatCast(value: anytype) anytype{#endsyntax#}</pre>
<p>
Expand Down
9 changes: 9 additions & 0 deletions lib/std/zig/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9274,6 +9274,15 @@ fn builtinCall(
});
return rvalue(gz, ri, result, node);
},
.FieldType => {
const ty_inst = try typeExpr(gz, scope, params[0]);
const name_inst = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1]);
const result = try gz.addPlNode(.field_type_ref, node, Zir.Inst.FieldTypeRef{
.container_type = ty_inst,
.field_name = name_inst,
});
return rvalue(gz, ri, result, node);
},

// zig fmt: off
.as => return as( gz, scope, ri, node, params[0], params[1]),
Expand Down
7 changes: 6 additions & 1 deletion lib/std/zig/AstRlAnnotate.zig
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,6 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
.work_item_id,
.work_group_size,
.work_group_id,
.field_parent_ptr,
=> {
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
return false;
Expand Down Expand Up @@ -983,11 +982,17 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
.has_decl,
.has_field,
.field,
.FieldType,
=> {
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
_ = try astrl.expr(args[1], block, ResultInfo.type_only);
return false;
},
.field_parent_ptr => {
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
_ = try astrl.expr(args[1], block, ResultInfo.none);
return false;
},
.wasm_memory_grow => {
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
_ = try astrl.expr(args[1], block, ResultInfo.type_only);
Expand Down
8 changes: 8 additions & 0 deletions lib/std/zig/BuiltinFn.zig
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub const Tag = enum {
@"extern",
field,
field_parent_ptr,
FieldType,
float_cast,
int_from_float,
frame,
Expand Down Expand Up @@ -516,6 +517,13 @@ pub const list = list: {
.param_count = 2,
},
},
.{
"@FieldType",
.{
.tag = .FieldType,
.param_count = 2,
},
},
.{
"@floatCast",
.{
Expand Down
24 changes: 24 additions & 0 deletions test/behavior/struct.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2159,3 +2159,27 @@ test "matching captures causes struct equivalence" {
comptime assert(@TypeOf(a) == @TypeOf(b));
try expect(a.x == b.x);
}

test "struct @FieldType" {
const S = struct {
a: u32,
b: f64,
c: *@This(),
};

comptime assert(@FieldType(S, "a") == u32);
comptime assert(@FieldType(S, "b") == f64);
comptime assert(@FieldType(S, "c") == *S);
}

test "extern struct @FieldType" {
const S = extern struct {
a: u32,
b: f64,
c: *@This(),
};

comptime assert(@FieldType(S, "a") == u32);
comptime assert(@FieldType(S, "b") == f64);
comptime assert(@FieldType(S, "c") == *S);
}
36 changes: 36 additions & 0 deletions test/behavior/union.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2339,3 +2339,39 @@ test "signed enum tag with negative value" {

try expect(e.a == i);
}

test "union @FieldType" {
const U = union {
a: u32,
b: f64,
c: *@This(),
};

comptime assert(@FieldType(U, "a") == u32);
comptime assert(@FieldType(U, "b") == f64);
comptime assert(@FieldType(U, "c") == *U);
}

test "tagged union @FieldType" {
const U = union(enum) {
a: u32,
b: f64,
c: *@This(),
};

comptime assert(@FieldType(U, "a") == u32);
comptime assert(@FieldType(U, "b") == f64);
comptime assert(@FieldType(U, "c") == *U);
}

test "extern union @FieldType" {
const U = extern union {
a: u32,
b: f64,
c: *@This(),
};

comptime assert(@FieldType(U, "a") == u32);
comptime assert(@FieldType(U, "b") == f64);
comptime assert(@FieldType(U, "c") == *U);
}
13 changes: 13 additions & 0 deletions test/cases/compile_errors/invalid_field_type_usage.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export fn foo() void {
_ = @FieldType(u8, "a");
}
export fn bar() void {
const S = struct { a: u8 };
_ = @FieldType(S, "b");
}

// error
//
// :2:20: error: expected struct or union; found 'u8'
// :6:23: error: no field named 'b' in struct 'tmp.bar.S'
// :5:15: note: struct declared here

0 comments on commit 097766b

Please sign in to comment.