diff options
| author | Meghan Denny <hello@nektro.net> | 2021-10-16 22:49:51 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-10-17 21:42:22 -0700 |
| commit | 0ef2e2520af59a42014399282ddea983fa526449 (patch) | |
| tree | b186116f3064299d58a81cacb2f68ae492d26d65 | |
| parent | 7d0a74456b0f239e6cc8532143badeb6781bd47d (diff) | |
| download | zig-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.zig | 4 | ||||
| -rw-r--r-- | src/Sema.zig | 17 | ||||
| -rw-r--r-- | src/type.zig | 72 | ||||
| -rw-r--r-- | test/behavior.zig | 3 | ||||
| -rw-r--r-- | test/behavior/hasfield.zig | 22 | ||||
| -rw-r--r-- | test/behavior/hasfield_stage1.zig | 26 |
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); +} |
