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