| author | |
| committer | |
| log | 140335b99fd9b26c2a827cb464fef68df7636a63 |
| tree | 4a4fdf56706d4eaee8099cce8a8318744366515e |
| parent | b05b5649df341573c0a42de503ceb025c4129473 |
| parent | 5a91dbc16cbe20a95aafb6b3221c4a5a07d9b117 |
| signature | Commit is signed but in an unrecognized format. |
7 files changed, 134 insertions(+), 0 deletions(-)
doc/langref.html.in+10| ... | @@ -6940,6 +6940,16 @@ fn add(a: i32, b: i32) i32 { return a + b; } | ... | @@ -6940,6 +6940,16 @@ fn add(a: i32, b: i32) i32 { return a + b; } |
| 6940 | It does not include functions, variables, or constants. | 6940 | It does not include functions, variables, or constants. |
| 6941 | </p> | 6941 | </p> |
| 6942 | {#header_close#} | 6942 | {#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#} | ||
| 6943 | {#header_open|@memberType#} | 6953 | {#header_open|@memberType#} |
| 6944 | <pre>{#syntax#}@memberType(comptime T: type, comptime index: usize) type{#endsyntax#}</pre> | 6954 | <pre>{#syntax#}@memberType(comptime T: type, comptime index: usize) type{#endsyntax#}</pre> |
| 6945 | <p>Returns the field type of a struct or union.</p> | 6955 | <p>Returns the field type of a struct or union.</p> |
src/all_types.hpp+10| ... | @@ -1416,6 +1416,7 @@ enum BuiltinFnId { | ... | @@ -1416,6 +1416,7 @@ enum BuiltinFnId { |
| 1416 | BuiltinFnIdMemberName, | 1416 | BuiltinFnIdMemberName, |
| 1417 | BuiltinFnIdField, | 1417 | BuiltinFnIdField, |
| 1418 | BuiltinFnIdTypeInfo, | 1418 | BuiltinFnIdTypeInfo, |
| 1419 | BuiltinFnIdHasField, | ||
| 1419 | BuiltinFnIdTypeof, | 1420 | BuiltinFnIdTypeof, |
| 1420 | BuiltinFnIdAddWithOverflow, | 1421 | BuiltinFnIdAddWithOverflow, |
| 1421 | BuiltinFnIdSubWithOverflow, | 1422 | BuiltinFnIdSubWithOverflow, |
| ... | @@ -2307,6 +2308,7 @@ enum IrInstructionId { | ... | @@ -2307,6 +2308,7 @@ enum IrInstructionId { |
| 2307 | IrInstructionIdByteOffsetOf, | 2308 | IrInstructionIdByteOffsetOf, |
| 2308 | IrInstructionIdBitOffsetOf, | 2309 | IrInstructionIdBitOffsetOf, |
| 2309 | IrInstructionIdTypeInfo, | 2310 | IrInstructionIdTypeInfo, |
| 2311 | IrInstructionIdHasField, | ||
| 2310 | IrInstructionIdTypeId, | 2312 | IrInstructionIdTypeId, |
| 2311 | IrInstructionIdSetEvalBranchQuota, | 2313 | IrInstructionIdSetEvalBranchQuota, |
| 2312 | IrInstructionIdPtrType, | 2314 | IrInstructionIdPtrType, |
| ... | @@ -3333,6 +3335,14 @@ struct IrInstructionTypeInfo { | ... | @@ -3333,6 +3335,14 @@ struct IrInstructionTypeInfo { |
| 3333 | IrInstruction *type_value; | 3335 | IrInstruction *type_value; |
| 3334 | }; | 3336 | }; |
| 3335 | 3337 | ||
| 3338 | struct IrInstructionHasField { | ||
| 3339 | IrInstruction base; | ||
| 3340 | |||
| 3341 | IrInstruction *container_type; | ||
| 3342 | Buf *field_name_buffer; | ||
| 3343 | IrInstruction *field_name_expr; | ||
| 3344 | }; | ||
| 3345 | |||
| 3336 | struct IrInstructionTypeId { | 3346 | struct IrInstructionTypeId { |
| 3337 | IrInstruction base; | 3347 | IrInstruction base; |
| 3338 | 3348 |
src/codegen.cpp+2| ... | @@ -5592,6 +5592,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5592,6 +5592,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5592 | case IrInstructionIdByteOffsetOf: | 5592 | case IrInstructionIdByteOffsetOf: |
| 5593 | case IrInstructionIdBitOffsetOf: | 5593 | case IrInstructionIdBitOffsetOf: |
| 5594 | case IrInstructionIdTypeInfo: | 5594 | case IrInstructionIdTypeInfo: |
| 5595 | case IrInstructionIdHasField: | ||
| 5595 | case IrInstructionIdTypeId: | 5596 | case IrInstructionIdTypeId: |
| 5596 | case IrInstructionIdSetEvalBranchQuota: | 5597 | case IrInstructionIdSetEvalBranchQuota: |
| 5597 | case IrInstructionIdPtrType: | 5598 | case IrInstructionIdPtrType: |
| ... | @@ -7328,6 +7329,7 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -7328,6 +7329,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 7328 | create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2); | 7329 | create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2); |
| 7329 | create_builtin_fn(g, BuiltinFnIdField, "field", 2); | 7330 | create_builtin_fn(g, BuiltinFnIdField, "field", 2); |
| 7330 | create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1); | 7331 | create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1); |
| 7332 | create_builtin_fn(g, BuiltinFnIdHasField, "hasField", 2); | ||
| 7331 | create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf | 7333 | create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf |
| 7332 | create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4); | 7334 | create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4); |
| 7333 | create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4); | 7335 | create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4); |
src/ir.cpp+70| ... | @@ -897,6 +897,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) { | ... | @@ -897,6 +897,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) { |
| 897 | return IrInstructionIdTypeInfo; | 897 | return IrInstructionIdTypeInfo; |
| 898 | } | 898 | } |
| 899 | 899 | ||
| 900 | static constexpr IrInstructionId ir_instruction_id(IrInstructionHasField *) { | ||
| 901 | return IrInstructionIdHasField; | ||
| 902 | } | ||
| 903 | |||
| 900 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeId *) { | 904 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeId *) { |
| 901 | return IrInstructionIdTypeId; | 905 | return IrInstructionIdTypeId; |
| 902 | } | 906 | } |
| ... | @@ -1375,6 +1379,20 @@ static IrInstruction *ir_build_field_ptr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -1375,6 +1379,20 @@ static IrInstruction *ir_build_field_ptr(IrBuilder *irb, Scope *scope, AstNode * |
| 1375 | return &instruction->base; | 1379 | return &instruction->base; |
| 1376 | } | 1380 | } |
| 1377 | 1381 | ||
| 1382 | static IrInstruction *ir_build_has_field(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 1383 | IrInstruction *container_type, IrInstruction *field_name_expr) | ||
| 1384 | { | ||
| 1385 | IrInstructionHasField *instruction = ir_build_instruction<IrInstructionHasField>(irb, scope, source_node); | ||
| 1386 | instruction->container_type = container_type; | ||
| 1387 | instruction->field_name_buffer = nullptr; | ||
| 1388 | instruction->field_name_expr = field_name_expr; | ||
| 1389 | |||
| 1390 | ir_ref_instruction(container_type, irb->current_basic_block); | ||
| 1391 | ir_ref_instruction(field_name_expr, irb->current_basic_block); | ||
| 1392 | |||
| 1393 | return &instruction->base; | ||
| 1394 | } | ||
| 1395 | |||
| 1378 | static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, | 1396 | static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1379 | IrInstruction *struct_ptr, TypeStructField *field) | 1397 | IrInstruction *struct_ptr, TypeStructField *field) |
| 1380 | { | 1398 | { |
| ... | @@ -5101,6 +5119,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -5101,6 +5119,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 5101 | IrInstruction *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction); | 5119 | IrInstruction *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction); |
| 5102 | return ir_expr_wrap(irb, scope, load_ptr, result_loc); | 5120 | return ir_expr_wrap(irb, scope, load_ptr, result_loc); |
| 5103 | } | 5121 | } |
| 5122 | case BuiltinFnIdHasField: | ||
| 5123 | { | ||
| 5124 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 5125 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | ||
| 5126 | if (arg0_value == irb->codegen->invalid_instruction) | ||
| 5127 | return arg0_value; | ||
| 5128 | |||
| 5129 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 5130 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | ||
| 5131 | if (arg1_value == irb->codegen->invalid_instruction) | ||
| 5132 | return arg1_value; | ||
| 5133 | |||
| 5134 | IrInstruction *type_info = ir_build_has_field(irb, scope, node, arg0_value, arg1_value); | ||
| 5135 | return ir_lval_wrap(irb, scope, type_info, lval); | ||
| 5136 | } | ||
| 5104 | case BuiltinFnIdTypeInfo: | 5137 | case BuiltinFnIdTypeInfo: |
| 5105 | { | 5138 | { |
| 5106 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | 5139 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| ... | @@ -22620,6 +22653,40 @@ static IrInstruction *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstr | ... | @@ -22620,6 +22653,40 @@ static IrInstruction *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstr |
| 22620 | } | 22653 | } |
| 22621 | } | 22654 | } |
| 22622 | 22655 | ||
| 22656 | static IrInstruction *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstructionHasField *instruction) { | ||
| 22657 | Error err; | ||
| 22658 | IrInstruction *container_type_value = instruction->container_type->child; | ||
| 22659 | ZigType *container_type = ir_resolve_type(ira, container_type_value); | ||
| 22660 | if (type_is_invalid(container_type)) | ||
| 22661 | return ira->codegen->invalid_instruction; | ||
| 22662 | |||
| 22663 | if ((err = ensure_complete_type(ira->codegen, container_type))) | ||
| 22664 | return ira->codegen->invalid_instruction; | ||
| 22665 | |||
| 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 | } | ||
| 22673 | |||
| 22674 | 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))); | ||
| 22684 | return ira->codegen->invalid_instruction; | ||
| 22685 | } | ||
| 22686 | return ir_build_const_bool(&ira->new_irb, | ||
| 22687 | instruction->base.scope, instruction->base.source_node, result); | ||
| 22688 | } | ||
| 22689 | |||
| 22623 | static IrInstruction *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstructionBreakpoint *instruction) { | 22690 | static IrInstruction *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstructionBreakpoint *instruction) { |
| 22624 | IrInstruction *result = ir_build_breakpoint(&ira->new_irb, | 22691 | IrInstruction *result = ir_build_breakpoint(&ira->new_irb, |
| 22625 | instruction->base.scope, instruction->base.source_node); | 22692 | instruction->base.scope, instruction->base.source_node); |
| ... | @@ -25480,6 +25547,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction | ... | @@ -25480,6 +25547,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25480 | return ir_analyze_instruction_bit_offset_of(ira, (IrInstructionBitOffsetOf *)instruction); | 25547 | return ir_analyze_instruction_bit_offset_of(ira, (IrInstructionBitOffsetOf *)instruction); |
| 25481 | case IrInstructionIdTypeInfo: | 25548 | case IrInstructionIdTypeInfo: |
| 25482 | return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction); | 25549 | return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction); |
| 25550 | case IrInstructionIdHasField: | ||
| 25551 | return ir_analyze_instruction_has_field(ira, (IrInstructionHasField *) instruction); | ||
| 25483 | case IrInstructionIdTypeId: | 25552 | case IrInstructionIdTypeId: |
| 25484 | return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction); | 25553 | return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction); |
| 25485 | case IrInstructionIdSetEvalBranchQuota: | 25554 | case IrInstructionIdSetEvalBranchQuota: |
| ... | @@ -25788,6 +25857,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -25788,6 +25857,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 25788 | case IrInstructionIdByteOffsetOf: | 25857 | case IrInstructionIdByteOffsetOf: |
| 25789 | case IrInstructionIdBitOffsetOf: | 25858 | case IrInstructionIdBitOffsetOf: |
| 25790 | case IrInstructionIdTypeInfo: | 25859 | case IrInstructionIdTypeInfo: |
| 25860 | case IrInstructionIdHasField: | ||
| 25791 | case IrInstructionIdTypeId: | 25861 | case IrInstructionIdTypeId: |
| 25792 | case IrInstructionIdAlignCast: | 25862 | case IrInstructionIdAlignCast: |
| 25793 | case IrInstructionIdImplicitCast: | 25863 | case IrInstructionIdImplicitCast: |
src/ir_print.cpp+11| ... | @@ -1270,6 +1270,14 @@ static void ir_print_type_info(IrPrint *irp, IrInstructionTypeInfo *instruction) | ... | @@ -1270,6 +1270,14 @@ static void ir_print_type_info(IrPrint *irp, IrInstructionTypeInfo *instruction) |
| 1270 | fprintf(irp->f, ")"); | 1270 | fprintf(irp->f, ")"); |
| 1271 | } | 1271 | } |
| 1272 | 1272 | ||
| 1273 | static void ir_print_has_field(IrPrint *irp, IrInstructionHasField *instruction) { | ||
| 1274 | fprintf(irp->f, "@hasField("); | ||
| 1275 | ir_print_other_instruction(irp, instruction->container_type); | ||
| 1276 | fprintf(irp->f, ","); | ||
| 1277 | ir_print_other_instruction(irp, instruction->field_name_expr); | ||
| 1278 | fprintf(irp->f, ")"); | ||
| 1279 | } | ||
| 1280 | |||
| 1273 | static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) { | 1281 | static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) { |
| 1274 | fprintf(irp->f, "@typeId("); | 1282 | fprintf(irp->f, "@typeId("); |
| 1275 | ir_print_other_instruction(irp, instruction->type_value); | 1283 | ir_print_other_instruction(irp, instruction->type_value); |
| ... | @@ -1965,6 +1973,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1965,6 +1973,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1965 | case IrInstructionIdTypeInfo: | 1973 | case IrInstructionIdTypeInfo: |
| 1966 | ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction); | 1974 | ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction); |
| 1967 | break; | 1975 | break; |
| 1976 | case IrInstructionIdHasField: | ||
| 1977 | ir_print_has_field(irp, (IrInstructionHasField *)instruction); | ||
| 1978 | break; | ||
| 1968 | case IrInstructionIdTypeId: | 1979 | case IrInstructionIdTypeId: |
| 1969 | ir_print_type_id(irp, (IrInstructionTypeId *)instruction); | 1980 | ir_print_type_id(irp, (IrInstructionTypeId *)instruction); |
| 1970 | break; | 1981 | break; |
test/stage1/behavior.zig+1| ... | @@ -98,4 +98,5 @@ comptime { | ... | @@ -98,4 +98,5 @@ comptime { |
| 98 | _ = @import("behavior/void.zig"); | 98 | _ = @import("behavior/void.zig"); |
| 99 | _ = @import("behavior/while.zig"); | 99 | _ = @import("behavior/while.zig"); |
| 100 | _ = @import("behavior/widening.zig"); | 100 | _ = @import("behavior/widening.zig"); |
| 101 | _ = @import("behavior/hasfield.zig"); | ||
| 101 | } | 102 | } |
test/stage1/behavior/hasfield.zig created+30| ... | @@ -0,0 +1,30 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | |||
| 4 | test "@hasField" { | ||
| 5 | const struc = struct { | ||
| 6 | a: i32, | ||
| 7 | b: []u8, | ||
| 8 | }; | ||
| 9 | expect(@hasField(struc, "a") == true); | ||
| 10 | expect(@hasField(struc, "b") == true); | ||
| 11 | expect(@hasField(struc, "non-existant") == false); | ||
| 12 | |||
| 13 | const unin = union { | ||
| 14 | a: u64, | ||
| 15 | b: []u16, | ||
| 16 | }; | ||
| 17 | expect(@hasField(unin, "a") == true); | ||
| 18 | expect(@hasField(unin, "b") == true); | ||
| 19 | expect(@hasField(unin, "non-existant") == false); | ||
| 20 | |||
| 21 | const enm = enum { | ||
| 22 | a, | ||
| 23 | b, | ||
| 24 | }; | ||
| 25 | expect(@hasField(enm, "a") == true); | ||
| 26 | expect(@hasField(enm, "b") == true); | ||
| 27 | expect(@hasField(enm, "non-existant") == false); | ||
| 28 | |||
| 29 | expect(@hasField(builtin, "os") == true); | ||
| 30 | } | ||