authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-17 21:53:59-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-17 21:53:59-07:00
log7b00bef6bf91e69b0bc3a7cec31476573301a3dc
treee0477b65a71c3068eba481d552f3d11c71fabb80
parent0ef2e2520af59a42014399282ddea983fa526449

Sema: resolveTypeFields before accessing type fields


4 files changed, 45 insertions(+), 38 deletions(-)

src/Sema.zig+23-11
...@@ -6413,21 +6413,33 @@ fn validateSwitchNoRange(...@@ -6413,21 +6413,33 @@ fn validateSwitchNoRange(
6413fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {6413fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
6414 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;6414 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
6415 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;6415 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
6416 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };6416 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
6417 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };6417 const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
6418 const container_type = try sema.resolveType(block, lhs_src, extra.lhs);6418 const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs);
6419 const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs);6419 const field_name = try sema.resolveConstString(block, name_src, extra.rhs);
64206420 const ty = try sema.resolveTypeFields(block, ty_src, unresolved_ty);
6421 const has_field = switch (container_type.zigTypeTag()) {6421
6422 .Struct => container_type.structFields().contains(field_name),6422 const has_field = hf: {
6423 .Union => container_type.unionFields().contains(field_name),6423 if (ty.isSlice()) {
6424 .Enum => container_type.enumFields().contains(field_name),6424 if (mem.eql(u8, field_name, "ptr")) break :hf true;
6425 else => return sema.fail(block, lhs_src, "expected struct, enum, or union, found '{}'", .{container_type}),6425 if (mem.eql(u8, field_name, "len")) break :hf true;
6426 break :hf false;
6427 }
6428 break :hf switch (ty.zigTypeTag()) {
6429 .Struct => ty.structFields().contains(field_name),
6430 .Union => ty.unionFields().contains(field_name),
6431 .Enum => ty.enumFields().contains(field_name),
6432 .Array => mem.eql(u8, field_name, "len"),
6433 else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{
6434 ty,
6435 }),
6436 };
6426 };6437 };
6427 if (has_field) {6438 if (has_field) {
6428 return Air.Inst.Ref.bool_true;6439 return Air.Inst.Ref.bool_true;
6440 } else {
6441 return Air.Inst.Ref.bool_false;
6429 }6442 }
6430 return Air.Inst.Ref.bool_false;
6431}6443}
64326444
6433fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {6445fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
test/behavior.zig-1
...@@ -128,7 +128,6 @@ test {...@@ -128,7 +128,6 @@ test {
128 _ = @import("behavior/fn_in_struct_in_comptime.zig");128 _ = @import("behavior/fn_in_struct_in_comptime.zig");
129 _ = @import("behavior/for_stage1.zig");129 _ = @import("behavior/for_stage1.zig");
130 _ = @import("behavior/generics_stage1.zig");130 _ = @import("behavior/generics_stage1.zig");
131 _ = @import("behavior/hasfield_stage1.zig");
132 _ = @import("behavior/if_stage1.zig");131 _ = @import("behavior/if_stage1.zig");
133 _ = @import("behavior/import.zig");132 _ = @import("behavior/import.zig");
134 _ = @import("behavior/incomplete_struct_param_tld.zig");133 _ = @import("behavior/incomplete_struct_param_tld.zig");
test/behavior/hasfield.zig+22
...@@ -2,6 +2,28 @@ const expect = @import("std").testing.expect;...@@ -2,6 +2,28 @@ const expect = @import("std").testing.expect;
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4test "@hasField" {4test "@hasField" {
5 const struc = struct {
6 a: i32,
7 b: []u8,
8
9 pub const nope = 1;
10 };
11 try expect(@hasField(struc, "a") == true);
12 try expect(@hasField(struc, "b") == true);
13 try expect(@hasField(struc, "non-existant") == false);
14 try expect(@hasField(struc, "nope") == false);
15
16 const unin = union {
17 a: u64,
18 b: []u16,
19
20 pub const nope = 1;
21 };
22 try expect(@hasField(unin, "a") == true);
23 try expect(@hasField(unin, "b") == true);
24 try expect(@hasField(unin, "non-existant") == false);
25 try expect(@hasField(unin, "nope") == false);
26
5 const enm = enum {27 const enm = enum {
6 a,28 a,
7 b,29 b,
test/behavior/hasfield_stage1.zig deleted-26
...@@ -1,26 +0,0 @@
1const expect = @import("std").testing.expect;
2const builtin = @import("builtin");
3
4test "@hasField" {
5 const struc = struct {
6 a: i32,
7 b: []const u8,
8
9 pub const nope = 1;
10 };
11 try expect(@hasField(struc, "a") == true);
12 try expect(@hasField(struc, "b") == true);
13 try expect(@hasField(struc, "non-existant") == false);
14 try expect(@hasField(struc, "nope") == false);
15
16 const unin = union {
17 a: u64,
18 b: []const u16,
19
20 pub const nope = 1;
21 };
22 try expect(@hasField(unin, "a") == true);
23 try expect(@hasField(unin, "b") == true);
24 try expect(@hasField(unin, "non-existant") == false);
25 try expect(@hasField(unin, "nope") == false);
26}