diff --git a/src/Sema.zig b/src/Sema.zig index 75698784d5..063a00f876 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6413,21 +6413,33 @@ 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; - 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); + const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; + const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; + const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs); + const field_name = try sema.resolveConstString(block, name_src, extra.rhs); + const ty = try sema.resolveTypeFields(block, ty_src, unresolved_ty); - 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}), + const has_field = hf: { + if (ty.isSlice()) { + if (mem.eql(u8, field_name, "ptr")) break :hf true; + if (mem.eql(u8, field_name, "len")) break :hf true; + break :hf false; + } + break :hf switch (ty.zigTypeTag()) { + .Struct => ty.structFields().contains(field_name), + .Union => ty.unionFields().contains(field_name), + .Enum => ty.enumFields().contains(field_name), + .Array => mem.eql(u8, field_name, "len"), + else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ + ty, + }), + }; }; if (has_field) { return Air.Inst.Ref.bool_true; + } else { + return Air.Inst.Ref.bool_false; } - return Air.Inst.Ref.bool_false; } fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { diff --git a/test/behavior.zig b/test/behavior.zig index 2371f8ec4a..83b82114b4 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -128,7 +128,6 @@ test { _ = @import("behavior/fn_in_struct_in_comptime.zig"); _ = @import("behavior/for_stage1.zig"); _ = @import("behavior/generics_stage1.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 87af991a33..81026273c0 100644 --- a/test/behavior/hasfield.zig +++ b/test/behavior/hasfield.zig @@ -2,6 +2,28 @@ 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 deleted file mode 100644 index 737d4143e6..0000000000 --- a/test/behavior/hasfield_stage1.zig +++ /dev/null @@ -1,26 +0,0 @@ -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); -}