aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMeghan Denny <hello@nektro.net>2021-10-16 22:49:51 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-10-17 21:42:22 -0700
commit0ef2e2520af59a42014399282ddea983fa526449 (patch)
treeb186116f3064299d58a81cacb2f68ae492d26d65
parent7d0a74456b0f239e6cc8532143badeb6781bd47d (diff)
downloadzig-0ef2e2520af59a42014399282ddea983fa526449.tar.gz
zig-0ef2e2520af59a42014399282ddea983fa526449.zip
stage2: implement `@hasField`
struct and union are kept in stage1 because struct/unionFieldCount are returning zero
-rw-r--r--src/Module.zig4
-rw-r--r--src/Sema.zig17
-rw-r--r--src/type.zig72
-rw-r--r--test/behavior.zig3
-rw-r--r--test/behavior/hasfield.zig22
-rw-r--r--test/behavior/hasfield_stage1.zig26
6 files changed, 57 insertions, 87 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 13181ae326..58a5a50698 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -876,10 +876,12 @@ pub const EnumSimple = struct {
/// The Decl that corresponds to the enum itself.
owner_decl: *Decl,
/// Set of field names in declaration order.
- fields: std.StringArrayHashMapUnmanaged(void),
+ fields: NameMap,
/// Offset from `owner_decl`, points to the enum decl AST node.
node_offset: i32,
+ pub const NameMap = EnumFull.NameMap;
+
pub fn srcLoc(self: EnumSimple) SrcLoc {
return .{
.file_scope = self.owner_decl.getFileScope(),
diff --git a/src/Sema.zig b/src/Sema.zig
index 589419be86..75698784d5 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -6413,10 +6413,21 @@ fn validateSwitchNoRange(
fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- _ = extra;
- const src = inst_data.src();
+ const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+ const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
+ const container_type = try sema.resolveType(block, lhs_src, extra.lhs);
+ const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs);
- return sema.fail(block, src, "TODO implement zirHasField", .{});
+ const has_field = switch (container_type.zigTypeTag()) {
+ .Struct => container_type.structFields().contains(field_name),
+ .Union => container_type.unionFields().contains(field_name),
+ .Enum => container_type.enumFields().contains(field_name),
+ else => return sema.fail(block, lhs_src, "expected struct, enum, or union, found '{}'", .{container_type}),
+ };
+ if (has_field) {
+ return Air.Inst.Ref.bool_true;
+ }
+ return Air.Inst.Ref.bool_false;
}
fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
diff --git a/src/type.zig b/src/type.zig
index f7cd00dd06..324901faf0 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -3252,14 +3252,11 @@ pub const Type = extern union {
};
}
- pub fn enumFieldCount(ty: Type) usize {
- switch (ty.tag()) {
- .enum_full, .enum_nonexhaustive => {
- const enum_full = ty.cast(Payload.EnumFull).?.data;
- return enum_full.fields.count();
- },
- .enum_simple => return ty.castTag(.enum_simple).?.data.fields.count(),
- .enum_numbered => return ty.castTag(.enum_numbered).?.data.fields.count(),
+ pub fn enumFields(ty: Type) Module.EnumFull.NameMap {
+ return switch (ty.tag()) {
+ .enum_full, .enum_nonexhaustive => ty.cast(Payload.EnumFull).?.data.fields,
+ .enum_simple => ty.castTag(.enum_simple).?.data.fields,
+ .enum_numbered => ty.castTag(.enum_numbered).?.data.fields,
.atomic_order,
.atomic_rmw_op,
.calling_convention,
@@ -3270,65 +3267,20 @@ pub const Type = extern union {
.export_options,
.extern_options,
=> @panic("TODO resolve std.builtin types"),
-
else => unreachable,
- }
+ };
+ }
+
+ pub fn enumFieldCount(ty: Type) usize {
+ return ty.enumFields().count();
}
pub fn enumFieldName(ty: Type, field_index: usize) []const u8 {
- switch (ty.tag()) {
- .enum_full, .enum_nonexhaustive => {
- const enum_full = ty.cast(Payload.EnumFull).?.data;
- return enum_full.fields.keys()[field_index];
- },
- .enum_simple => {
- const enum_simple = ty.castTag(.enum_simple).?.data;
- return enum_simple.fields.keys()[field_index];
- },
- .enum_numbered => {
- const enum_numbered = ty.castTag(.enum_numbered).?.data;
- return enum_numbered.fields.keys()[field_index];
- },
- .atomic_order,
- .atomic_rmw_op,
- .calling_convention,
- .address_space,
- .float_mode,
- .reduce_op,
- .call_options,
- .export_options,
- .extern_options,
- => @panic("TODO resolve std.builtin types"),
- else => unreachable,
- }
+ return ty.enumFields().keys()[field_index];
}
pub fn enumFieldIndex(ty: Type, field_name: []const u8) ?usize {
- switch (ty.tag()) {
- .enum_full, .enum_nonexhaustive => {
- const enum_full = ty.cast(Payload.EnumFull).?.data;
- return enum_full.fields.getIndex(field_name);
- },
- .enum_simple => {
- const enum_simple = ty.castTag(.enum_simple).?.data;
- return enum_simple.fields.getIndex(field_name);
- },
- .enum_numbered => {
- const enum_numbered = ty.castTag(.enum_numbered).?.data;
- return enum_numbered.fields.getIndex(field_name);
- },
- .atomic_order,
- .atomic_rmw_op,
- .calling_convention,
- .address_space,
- .float_mode,
- .reduce_op,
- .call_options,
- .export_options,
- .extern_options,
- => @panic("TODO resolve std.builtin types"),
- else => unreachable,
- }
+ return ty.enumFields().getIndex(field_name);
}
/// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or
diff --git a/test/behavior.zig b/test/behavior.zig
index 1d9d2b9eee..2371f8ec4a 100644
--- a/test/behavior.zig
+++ b/test/behavior.zig
@@ -35,6 +35,7 @@ test {
_ = @import("behavior/for.zig");
_ = @import("behavior/generics.zig");
_ = @import("behavior/hasdecl.zig");
+ _ = @import("behavior/hasfield.zig");
_ = @import("behavior/if.zig");
_ = @import("behavior/math.zig");
_ = @import("behavior/maximum_minimum.zig");
@@ -127,7 +128,7 @@ test {
_ = @import("behavior/fn_in_struct_in_comptime.zig");
_ = @import("behavior/for_stage1.zig");
_ = @import("behavior/generics_stage1.zig");
- _ = @import("behavior/hasfield.zig");
+ _ = @import("behavior/hasfield_stage1.zig");
_ = @import("behavior/if_stage1.zig");
_ = @import("behavior/import.zig");
_ = @import("behavior/incomplete_struct_param_tld.zig");
diff --git a/test/behavior/hasfield.zig b/test/behavior/hasfield.zig
index 81026273c0..87af991a33 100644
--- a/test/behavior/hasfield.zig
+++ b/test/behavior/hasfield.zig
@@ -2,28 +2,6 @@ const expect = @import("std").testing.expect;
const builtin = @import("builtin");
test "@hasField" {
- const struc = struct {
- a: i32,
- b: []u8,
-
- pub const nope = 1;
- };
- try expect(@hasField(struc, "a") == true);
- try expect(@hasField(struc, "b") == true);
- try expect(@hasField(struc, "non-existant") == false);
- try expect(@hasField(struc, "nope") == false);
-
- const unin = union {
- a: u64,
- b: []u16,
-
- pub const nope = 1;
- };
- try expect(@hasField(unin, "a") == true);
- try expect(@hasField(unin, "b") == true);
- try expect(@hasField(unin, "non-existant") == false);
- try expect(@hasField(unin, "nope") == false);
-
const enm = enum {
a,
b,
diff --git a/test/behavior/hasfield_stage1.zig b/test/behavior/hasfield_stage1.zig
new file mode 100644
index 0000000000..737d4143e6
--- /dev/null
+++ b/test/behavior/hasfield_stage1.zig
@@ -0,0 +1,26 @@
+const expect = @import("std").testing.expect;
+const builtin = @import("builtin");
+
+test "@hasField" {
+ const struc = struct {
+ a: i32,
+ b: []const u8,
+
+ pub const nope = 1;
+ };
+ try expect(@hasField(struc, "a") == true);
+ try expect(@hasField(struc, "b") == true);
+ try expect(@hasField(struc, "non-existant") == false);
+ try expect(@hasField(struc, "nope") == false);
+
+ const unin = union {
+ a: u64,
+ b: []const u16,
+
+ pub const nope = 1;
+ };
+ try expect(@hasField(unin, "a") == true);
+ try expect(@hasField(unin, "b") == true);
+ try expect(@hasField(unin, "non-existant") == false);
+ try expect(@hasField(unin, "nope") == false);
+}