| author | |
| committer | |
| log | df11512f85e5228ee2393e9dc5fc42294ecba1c9 |
| tree | d428783b71938e855e079a120a6c65e1251717af |
| parent | 140335b99fd9b26c2a827cb464fef68df7636a63 |
| signature |
6 files changed, 52 insertions(+), 41 deletions(-)
doc/langref.html.in+13-10| ... | ... | @@ -6801,6 +6801,19 @@ test "@hasDecl" { |
| 6801 | 6801 | assert(!@hasDecl(Foo, "nope1234")); |
| 6802 | 6802 | } |
| 6803 | 6803 | {#code_end#} |
| 6804 | {#see_also|@hasField#} | |
| 6805 | {#header_close#} | |
| 6806 | ||
| 6807 | {#header_open|@hasField#} | |
| 6808 | <pre>{#syntax#}@hasField(comptime T: type, comptime name: []const u8) bool{#endsyntax#}</pre> | |
| 6809 | <p>Returns whether the field name of a struct, union, or enum exists.</p> | |
| 6810 | <p> | |
| 6811 | The result is a compile time constant. | |
| 6812 | </p> | |
| 6813 | <p> | |
| 6814 | It does not include functions, variables, or constants. | |
| 6815 | </p> | |
| 6816 | {#see_also|@hasDecl#} | |
| 6804 | 6817 | {#header_close#} |
| 6805 | 6818 | |
| 6806 | 6819 | {#header_open|@import#} |
| ... | ... | @@ -6940,16 +6953,6 @@ fn add(a: i32, b: i32) i32 { return a + b; } |
| 6940 | 6953 | It does not include functions, variables, or constants. |
| 6941 | 6954 | </p> |
| 6942 | 6955 | {#header_close#} |
| 6943 | {#header_open|@hasField#} | |
| 6944 | <pre>{#syntax#}@hasField(comptime T: type, comptime name: []const u8) bool{#endsyntax#}</pre> | |
| 6945 | <p>Returns if the field name of a struct, union, or enum exists.</p> | |
| 6946 | <p> | |
| 6947 | The result is a compile time constant. | |
| 6948 | </p> | |
| 6949 | <p> | |
| 6950 | It does not include functions, variables, constants. | |
| 6951 | </p> | |
| 6952 | {#header_close#} | |
| 6953 | 6956 | {#header_open|@memberType#} |
| 6954 | 6957 | <pre>{#syntax#}@memberType(comptime T: type, comptime index: usize) type{#endsyntax#}</pre> |
| 6955 | 6958 | <p>Returns the field type of a struct or union.</p> |
src/all_types.hpp+1-2| ... | ... | @@ -3339,8 +3339,7 @@ struct IrInstructionHasField { |
| 3339 | 3339 | IrInstruction base; |
| 3340 | 3340 | |
| 3341 | 3341 | IrInstruction *container_type; |
| 3342 | Buf *field_name_buffer; | |
| 3343 | IrInstruction *field_name_expr; | |
| 3342 | IrInstruction *field_name; | |
| 3344 | 3343 | }; |
| 3345 | 3344 | |
| 3346 | 3345 | struct IrInstructionTypeId { |
src/ir.cpp+19-26| ... | ... | @@ -1380,15 +1380,14 @@ static IrInstruction *ir_build_field_ptr(IrBuilder *irb, Scope *scope, AstNode * |
| 1380 | 1380 | } |
| 1381 | 1381 | |
| 1382 | 1382 | static IrInstruction *ir_build_has_field(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1383 | IrInstruction *container_type, IrInstruction *field_name_expr) | |
| 1383 | IrInstruction *container_type, IrInstruction *field_name) | |
| 1384 | 1384 | { |
| 1385 | 1385 | IrInstructionHasField *instruction = ir_build_instruction<IrInstructionHasField>(irb, scope, source_node); |
| 1386 | 1386 | instruction->container_type = container_type; |
| 1387 | instruction->field_name_buffer = nullptr; | |
| 1388 | instruction->field_name_expr = field_name_expr; | |
| 1387 | instruction->field_name = field_name; | |
| 1389 | 1388 | |
| 1390 | 1389 | ir_ref_instruction(container_type, irb->current_basic_block); |
| 1391 | ir_ref_instruction(field_name_expr, irb->current_basic_block); | |
| 1390 | ir_ref_instruction(field_name, irb->current_basic_block); | |
| 1392 | 1391 | |
| 1393 | 1392 | return &instruction->base; |
| 1394 | 1393 | } |
| ... | ... | @@ -5132,7 +5131,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 5132 | 5131 | return arg1_value; |
| 5133 | 5132 | |
| 5134 | 5133 | IrInstruction *type_info = ir_build_has_field(irb, scope, node, arg0_value, arg1_value); |
| 5135 | return ir_lval_wrap(irb, scope, type_info, lval); | |
| 5134 | return ir_lval_wrap(irb, scope, type_info, lval, result_loc); | |
| 5136 | 5135 | } |
| 5137 | 5136 | case BuiltinFnIdTypeInfo: |
| 5138 | 5137 | { |
| ... | ... | @@ -22655,36 +22654,30 @@ static IrInstruction *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstr |
| 22655 | 22654 | |
| 22656 | 22655 | static IrInstruction *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstructionHasField *instruction) { |
| 22657 | 22656 | Error err; |
| 22658 | IrInstruction *container_type_value = instruction->container_type->child; | |
| 22659 | ZigType *container_type = ir_resolve_type(ira, container_type_value); | |
| 22657 | ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); | |
| 22660 | 22658 | if (type_is_invalid(container_type)) |
| 22661 | 22659 | return ira->codegen->invalid_instruction; |
| 22662 | 22660 | |
| 22663 | if ((err = ensure_complete_type(ira->codegen, container_type))) | |
| 22661 | if ((err = type_resolve(ira->codegen, container_type, ResolveStatusZeroBitsKnown))) | |
| 22664 | 22662 | return ira->codegen->invalid_instruction; |
| 22665 | 22663 | |
| 22666 | Buf *field_name = instruction->field_name_buffer; | |
| 22667 | if (!field_name) { | |
| 22668 | IrInstruction *field_name_expr = instruction->field_name_expr->child; | |
| 22669 | field_name = ir_resolve_str(ira, field_name_expr); | |
| 22670 | if (!field_name) | |
| 22671 | return ira->codegen->invalid_instruction; | |
| 22672 | } | |
| 22664 | Buf *field_name = ir_resolve_str(ira, instruction->field_name->child); | |
| 22665 | if (field_name == nullptr) | |
| 22666 | return ira->codegen->invalid_instruction; | |
| 22673 | 22667 | |
| 22674 | 22668 | bool result; |
| 22675 | if (container_type->id == ZigTypeIdStruct) | |
| 22676 | result = (bool)find_struct_type_field(container_type, field_name); | |
| 22677 | else if (container_type->id == ZigTypeIdEnum) | |
| 22678 | result = (bool)find_enum_type_field(container_type, field_name); | |
| 22679 | else if (container_type->id == ZigTypeIdUnion) | |
| 22680 | result = (bool)find_union_type_field(container_type, field_name); | |
| 22681 | else { | |
| 22682 | ir_add_error(ira, container_type_value, | |
| 22683 | buf_sprintf("type '%s' does not support @memberName", buf_ptr(&container_type->name))); | |
| 22669 | if (container_type->id == ZigTypeIdStruct) { | |
| 22670 | result = find_struct_type_field(container_type, field_name) != nullptr; | |
| 22671 | } else if (container_type->id == ZigTypeIdEnum) { | |
| 22672 | result = find_enum_type_field(container_type, field_name) != nullptr; | |
| 22673 | } else if (container_type->id == ZigTypeIdUnion) { | |
| 22674 | result = find_union_type_field(container_type, field_name) != nullptr; | |
| 22675 | } else { | |
| 22676 | ir_add_error(ira, instruction->container_type, | |
| 22677 | buf_sprintf("type '%s' does not support @hasField", buf_ptr(&container_type->name))); | |
| 22684 | 22678 | return ira->codegen->invalid_instruction; |
| 22685 | 22679 | } |
| 22686 | return ir_build_const_bool(&ira->new_irb, | |
| 22687 | instruction->base.scope, instruction->base.source_node, result); | |
| 22680 | return ir_const_bool(ira, &instruction->base, result); | |
| 22688 | 22681 | } |
| 22689 | 22682 | |
| 22690 | 22683 | static IrInstruction *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstructionBreakpoint *instruction) { |
src/ir_print.cpp+1-1| ... | ... | @@ -1274,7 +1274,7 @@ static void ir_print_has_field(IrPrint *irp, IrInstructionHasField *instruction) |
| 1274 | 1274 | fprintf(irp->f, "@hasField("); |
| 1275 | 1275 | ir_print_other_instruction(irp, instruction->container_type); |
| 1276 | 1276 | fprintf(irp->f, ","); |
| 1277 | ir_print_other_instruction(irp, instruction->field_name_expr); | |
| 1277 | ir_print_other_instruction(irp, instruction->field_name); | |
| 1278 | 1278 | fprintf(irp->f, ")"); |
| 1279 | 1279 | } |
| 1280 | 1280 |
test/compile_errors.zig+9| ... | ... | @@ -2,6 +2,15 @@ const tests = @import("tests.zig"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.add( | |
| 6 | "wrong type to @hasField", | |
| 7 | \\export fn entry() bool { | |
| 8 | \\ return @hasField(i32, "hi"); | |
| 9 | \\} | |
| 10 | , | |
| 11 | "tmp.zig:2:22: error: type 'i32' does not support @hasField", | |
| 12 | ); | |
| 13 | ||
| 5 | 14 | cases.add( |
| 6 | 15 | "slice passed as array init type with elems", |
| 7 | 16 | \\export fn entry() void { |
test/stage1/behavior/hasfield.zig+9-2| ... | ... | @@ -5,26 +5,33 @@ test "@hasField" { |
| 5 | 5 | const struc = struct { |
| 6 | 6 | a: i32, |
| 7 | 7 | b: []u8, |
| 8 | ||
| 9 | pub const nope = 1; | |
| 8 | 10 | }; |
| 9 | 11 | expect(@hasField(struc, "a") == true); |
| 10 | 12 | expect(@hasField(struc, "b") == true); |
| 11 | 13 | expect(@hasField(struc, "non-existant") == false); |
| 14 | expect(@hasField(struc, "nope") == false); | |
| 12 | 15 | |
| 13 | 16 | const unin = union { |
| 14 | 17 | a: u64, |
| 15 | 18 | b: []u16, |
| 19 | ||
| 20 | pub const nope = 1; | |
| 16 | 21 | }; |
| 17 | 22 | expect(@hasField(unin, "a") == true); |
| 18 | 23 | expect(@hasField(unin, "b") == true); |
| 19 | 24 | expect(@hasField(unin, "non-existant") == false); |
| 25 | expect(@hasField(unin, "nope") == false); | |
| 20 | 26 | |
| 21 | 27 | const enm = enum { |
| 22 | 28 | a, |
| 23 | 29 | b, |
| 30 | ||
| 31 | pub const nope = 1; | |
| 24 | 32 | }; |
| 25 | 33 | expect(@hasField(enm, "a") == true); |
| 26 | 34 | expect(@hasField(enm, "b") == true); |
| 27 | 35 | expect(@hasField(enm, "non-existant") == false); |
| 28 | ||
| 29 | expect(@hasField(builtin, "os") == true); | |
| 36 | expect(@hasField(enm, "nope") == false); | |
| 30 | 37 | } |