mirror of
https://github.com/ziglang/zig.git
synced 2025-12-16 19:23:08 +00:00
Sema: resolveTypeFields before accessing type fields
This commit is contained in:
parent
0ef2e2520a
commit
7b00bef6bf
32
src/Sema.zig
32
src/Sema.zig
@ -6413,21 +6413,33 @@ fn validateSwitchNoRange(
|
|||||||
fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
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 inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||||
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
|
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 ty_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 name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
|
||||||
const container_type = try sema.resolveType(block, lhs_src, extra.lhs);
|
const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs);
|
||||||
const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs);
|
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()) {
|
const has_field = hf: {
|
||||||
.Struct => container_type.structFields().contains(field_name),
|
if (ty.isSlice()) {
|
||||||
.Union => container_type.unionFields().contains(field_name),
|
if (mem.eql(u8, field_name, "ptr")) break :hf true;
|
||||||
.Enum => container_type.enumFields().contains(field_name),
|
if (mem.eql(u8, field_name, "len")) break :hf true;
|
||||||
else => return sema.fail(block, lhs_src, "expected struct, enum, or union, found '{}'", .{container_type}),
|
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) {
|
if (has_field) {
|
||||||
return Air.Inst.Ref.bool_true;
|
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 {
|
fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
|
|||||||
@ -128,7 +128,6 @@ test {
|
|||||||
_ = @import("behavior/fn_in_struct_in_comptime.zig");
|
_ = @import("behavior/fn_in_struct_in_comptime.zig");
|
||||||
_ = @import("behavior/for_stage1.zig");
|
_ = @import("behavior/for_stage1.zig");
|
||||||
_ = @import("behavior/generics_stage1.zig");
|
_ = @import("behavior/generics_stage1.zig");
|
||||||
_ = @import("behavior/hasfield_stage1.zig");
|
|
||||||
_ = @import("behavior/if_stage1.zig");
|
_ = @import("behavior/if_stage1.zig");
|
||||||
_ = @import("behavior/import.zig");
|
_ = @import("behavior/import.zig");
|
||||||
_ = @import("behavior/incomplete_struct_param_tld.zig");
|
_ = @import("behavior/incomplete_struct_param_tld.zig");
|
||||||
|
|||||||
@ -2,6 +2,28 @@ const expect = @import("std").testing.expect;
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
test "@hasField" {
|
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 {
|
const enm = enum {
|
||||||
a,
|
a,
|
||||||
b,
|
b,
|
||||||
|
|||||||
@ -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);
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user