aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-10-17 21:53:59 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-10-17 21:53:59 -0700
commit7b00bef6bf91e69b0bc3a7cec31476573301a3dc (patch)
treee0477b65a71c3068eba481d552f3d11c71fabb80
parent0ef2e2520af59a42014399282ddea983fa526449 (diff)
downloadzig-7b00bef6bf91e69b0bc3a7cec31476573301a3dc.tar.gz
zig-7b00bef6bf91e69b0bc3a7cec31476573301a3dc.zip
Sema: resolveTypeFields before accessing type fields
-rw-r--r--src/Sema.zig34
-rw-r--r--test/behavior.zig1
-rw-r--r--test/behavior/hasfield.zig22
-rw-r--r--test/behavior/hasfield_stage1.zig26
4 files changed, 45 insertions, 38 deletions
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 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 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 = 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);
-}