| author | |
| committer | |
| log | 53a6aea216d7b1e6b6072d30f2d51ed801d9e0f9 |
| tree | 41809dbfec90af3c6320239cd186f9ede7b8b8e1 |
| parent | 77a5f888be664f9ef09e2c93f52338448e992e00 |
| parent | ac7703f65f7acc9137e28ded97659fbaadea4e66 |
| signature |
9 files changed, 468 insertions(+), 23 deletions(-)
doc/docgen.zig+24-2| ... | ... | @@ -321,6 +321,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { |
| 321 | 321 | |
| 322 | 322 | var header_stack_size: usize = 0; |
| 323 | 323 | var last_action = Action.Open; |
| 324 | var last_columns: ?u8 = null; | |
| 324 | 325 | |
| 325 | 326 | var toc_buf = try std.Buffer.initSize(allocator, 0); |
| 326 | 327 | defer toc_buf.deinit(); |
| ... | ... | @@ -361,7 +362,23 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { |
| 361 | 362 | _ = try eatToken(tokenizer, Token.Id.Separator); |
| 362 | 363 | const content_token = try eatToken(tokenizer, Token.Id.TagContent); |
| 363 | 364 | const content = tokenizer.buffer[content_token.start..content_token.end]; |
| 364 | _ = try eatToken(tokenizer, Token.Id.BracketClose); | |
| 365 | var columns: ?u8 = null; | |
| 366 | while (true) { | |
| 367 | const bracket_tok = tokenizer.next(); | |
| 368 | switch (bracket_tok.id) { | |
| 369 | .BracketClose => break, | |
| 370 | .Separator => continue, | |
| 371 | .TagContent => { | |
| 372 | const param = tokenizer.buffer[bracket_tok.start..bracket_tok.end]; | |
| 373 | if (mem.eql(u8, param, "3col")) { | |
| 374 | columns = 3; | |
| 375 | } else { | |
| 376 | return parseError(tokenizer, bracket_tok, "unrecognized header_open param: {}", param); | |
| 377 | } | |
| 378 | }, | |
| 379 | else => return parseError(tokenizer, bracket_tok, "invalid header_open token"), | |
| 380 | } | |
| 381 | } | |
| 365 | 382 | |
| 366 | 383 | header_stack_size += 1; |
| 367 | 384 | |
| ... | ... | @@ -381,10 +398,15 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { |
| 381 | 398 | if (last_action == Action.Open) { |
| 382 | 399 | try toc.writeByte('\n'); |
| 383 | 400 | try toc.writeByteNTimes(' ', header_stack_size * 4); |
| 384 | try toc.write("<ul>\n"); | |
| 401 | if (last_columns) |n| { | |
| 402 | try toc.print("<ul style=\"columns: {}\">\n", n); | |
| 403 | } else { | |
| 404 | try toc.write("<ul>\n"); | |
| 405 | } | |
| 385 | 406 | } else { |
| 386 | 407 | last_action = Action.Open; |
| 387 | 408 | } |
| 409 | last_columns = columns; | |
| 388 | 410 | try toc.writeByteNTimes(' ', 4 + header_stack_size * 4); |
| 389 | 411 | try toc.print("<li><a id=\"toc-{}\" href=\"#{}\">{}</a>", urlized, urlized, content); |
| 390 | 412 | } else if (mem.eql(u8, tag_name, "header_close")) { |
doc/langref.html.in+55-1| ... | ... | @@ -6323,7 +6323,7 @@ fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 { |
| 6323 | 6323 | {#header_close#} |
| 6324 | 6324 | |
| 6325 | 6325 | {#header_close#} |
| 6326 | {#header_open|Builtin Functions#} | |
| 6326 | {#header_open|Builtin Functions|3col#} | |
| 6327 | 6327 | <p> |
| 6328 | 6328 | Builtin functions are provided by the compiler and are prefixed with <code>@</code>. |
| 6329 | 6329 | The {#syntax#}comptime{#endsyntax#} keyword on a parameter means that the parameter must be known |
| ... | ... | @@ -7232,6 +7232,9 @@ fn add(a: i32, b: i32) i32 { return a + b; } |
| 7232 | 7232 | This function returns an integer type with the given signness and bit count. The maximum |
| 7233 | 7233 | bit count for an integer type is {#syntax#}65535{#endsyntax#}. |
| 7234 | 7234 | </p> |
| 7235 | <p> | |
| 7236 | Deprecated. Use {#link|@Type#}. | |
| 7237 | </p> | |
| 7235 | 7238 | {#header_close#} |
| 7236 | 7239 | |
| 7237 | 7240 | {#header_open|@memberCount#} |
| ... | ... | @@ -7871,6 +7874,57 @@ test "integer truncation" { |
| 7871 | 7874 | </p> |
| 7872 | 7875 | {#header_close#} |
| 7873 | 7876 | |
| 7877 | {#header_open|@Type#} | |
| 7878 | <pre>{#syntax#}@Type(comptime info: @import("builtin").TypeInfo) type{#endsyntax#}</pre> | |
| 7879 | <p> | |
| 7880 | This function is the inverse of {#link|@typeInfo#}. It reifies type information | |
| 7881 | into a {#syntax#}type{#endsyntax#}. | |
| 7882 | </p> | |
| 7883 | <p> | |
| 7884 | It is available for the following types: | |
| 7885 | </p> | |
| 7886 | <ul> | |
| 7887 | <li>{#syntax#}type{#endsyntax#}</li> | |
| 7888 | <li>{#syntax#}noreturn{#endsyntax#}</li> | |
| 7889 | <li>{#syntax#}void{#endsyntax#}</li> | |
| 7890 | <li>{#syntax#}bool{#endsyntax#}</li> | |
| 7891 | <li>{#link|Integers#}</li> - The maximum bit count for an integer type is {#syntax#}65535{#endsyntax#}. | |
| 7892 | <li>{#link|Floats#}</li> | |
| 7893 | <li>{#link|Pointers#}</li> | |
| 7894 | <li>{#syntax#}comptime_int{#endsyntax#}</li> | |
| 7895 | <li>{#syntax#}comptime_float{#endsyntax#}</li> | |
| 7896 | <li>{#syntax#}@typeOf(undefined){#endsyntax#}</li> | |
| 7897 | <li>{#syntax#}@typeOf(null){#endsyntax#}</li> | |
| 7898 | </ul> | |
| 7899 | <p> | |
| 7900 | For these types it is a | |
| 7901 | <a href="https://github.com/ziglang/zig/issues/2907">TODO in the compiler to implement</a>: | |
| 7902 | </p> | |
| 7903 | <ul> | |
| 7904 | <li>Array</li> | |
| 7905 | <li>Optional</li> | |
| 7906 | <li>ErrorUnion</li> | |
| 7907 | <li>ErrorSet</li> | |
| 7908 | <li>Enum</li> | |
| 7909 | <li>Opaque</li> | |
| 7910 | <li>FnFrame</li> | |
| 7911 | <li>AnyFrame</li> | |
| 7912 | <li>Vector</li> | |
| 7913 | <li>EnumLiteral</li> | |
| 7914 | </ul> | |
| 7915 | <p> | |
| 7916 | For these types, {#syntax#}@Type{#endsyntax#} is not available. | |
| 7917 | <a href="https://github.com/ziglang/zig/issues/383">There is an open proposal to allow unions and structs</a>. | |
| 7918 | </p> | |
| 7919 | <ul> | |
| 7920 | <li>{#link|union#}</li> | |
| 7921 | <li>{#link|Functions#}</li> | |
| 7922 | <li>BoundFn</li> | |
| 7923 | <li>ArgTuple</li> | |
| 7924 | <li>{#link|struct#}</li> | |
| 7925 | </ul> | |
| 7926 | {#header_close#} | |
| 7927 | ||
| 7874 | 7928 | {#header_open|@typeId#} |
| 7875 | 7929 | <pre>{#syntax#}@typeId(comptime T: type) @import("builtin").TypeId{#endsyntax#}</pre> |
| 7876 | 7930 | <p> |
src/all_types.hpp+16| ... | ... | @@ -54,6 +54,14 @@ enum PtrLen { |
| 54 | 54 | PtrLenC, |
| 55 | 55 | }; |
| 56 | 56 | |
| 57 | // This one corresponds to the builtin.zig enum. | |
| 58 | enum BuiltinPtrSize { | |
| 59 | BuiltinPtrSizeOne, | |
| 60 | BuiltinPtrSizeMany, | |
| 61 | BuiltinPtrSizeSlice, | |
| 62 | BuiltinPtrSizeC, | |
| 63 | }; | |
| 64 | ||
| 57 | 65 | enum UndefAllowed { |
| 58 | 66 | UndefOk, |
| 59 | 67 | UndefBad, |
| ... | ... | @@ -1534,6 +1542,7 @@ enum BuiltinFnId { |
| 1534 | 1542 | BuiltinFnIdMemberName, |
| 1535 | 1543 | BuiltinFnIdField, |
| 1536 | 1544 | BuiltinFnIdTypeInfo, |
| 1545 | BuiltinFnIdType, | |
| 1537 | 1546 | BuiltinFnIdHasField, |
| 1538 | 1547 | BuiltinFnIdTypeof, |
| 1539 | 1548 | BuiltinFnIdAddWithOverflow, |
| ... | ... | @@ -2436,6 +2445,7 @@ enum IrInstructionId { |
| 2436 | 2445 | IrInstructionIdByteOffsetOf, |
| 2437 | 2446 | IrInstructionIdBitOffsetOf, |
| 2438 | 2447 | IrInstructionIdTypeInfo, |
| 2448 | IrInstructionIdType, | |
| 2439 | 2449 | IrInstructionIdHasField, |
| 2440 | 2450 | IrInstructionIdTypeId, |
| 2441 | 2451 | IrInstructionIdSetEvalBranchQuota, |
| ... | ... | @@ -3472,6 +3482,12 @@ struct IrInstructionTypeInfo { |
| 3472 | 3482 | IrInstruction *type_value; |
| 3473 | 3483 | }; |
| 3474 | 3484 | |
| 3485 | struct IrInstructionType { | |
| 3486 | IrInstruction base; | |
| 3487 | ||
| 3488 | IrInstruction *type_info; | |
| 3489 | }; | |
| 3490 | ||
| 3475 | 3491 | struct IrInstructionHasField { |
| 3476 | 3492 | IrInstruction base; |
| 3477 | 3493 |
src/codegen.cpp+21-14| ... | ... | @@ -5770,6 +5770,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5770 | 5770 | case IrInstructionIdByteOffsetOf: |
| 5771 | 5771 | case IrInstructionIdBitOffsetOf: |
| 5772 | 5772 | case IrInstructionIdTypeInfo: |
| 5773 | case IrInstructionIdType: | |
| 5773 | 5774 | case IrInstructionIdHasField: |
| 5774 | 5775 | case IrInstructionIdTypeId: |
| 5775 | 5776 | case IrInstructionIdSetEvalBranchQuota: |
| ... | ... | @@ -7597,6 +7598,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 7597 | 7598 | create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2); |
| 7598 | 7599 | create_builtin_fn(g, BuiltinFnIdField, "field", 2); |
| 7599 | 7600 | create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1); |
| 7601 | create_builtin_fn(g, BuiltinFnIdType, "Type", 1); | |
| 7600 | 7602 | create_builtin_fn(g, BuiltinFnIdHasField, "hasField", 2); |
| 7601 | 7603 | create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf |
| 7602 | 7604 | create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4); |
| ... | ... | @@ -8159,20 +8161,25 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 8159 | 8161 | " };\n" |
| 8160 | 8162 | " };\n" |
| 8161 | 8163 | "};\n\n"); |
| 8162 | assert(ContainerLayoutAuto == 0); | |
| 8163 | assert(ContainerLayoutExtern == 1); | |
| 8164 | assert(ContainerLayoutPacked == 2); | |
| 8165 | ||
| 8166 | assert(CallingConventionUnspecified == 0); | |
| 8167 | assert(CallingConventionC == 1); | |
| 8168 | assert(CallingConventionCold == 2); | |
| 8169 | assert(CallingConventionNaked == 3); | |
| 8170 | assert(CallingConventionStdcall == 4); | |
| 8171 | assert(CallingConventionAsync == 5); | |
| 8172 | ||
| 8173 | assert(FnInlineAuto == 0); | |
| 8174 | assert(FnInlineAlways == 1); | |
| 8175 | assert(FnInlineNever == 2); | |
| 8164 | static_assert(ContainerLayoutAuto == 0, ""); | |
| 8165 | static_assert(ContainerLayoutExtern == 1, ""); | |
| 8166 | static_assert(ContainerLayoutPacked == 2, ""); | |
| 8167 | ||
| 8168 | static_assert(CallingConventionUnspecified == 0, ""); | |
| 8169 | static_assert(CallingConventionC == 1, ""); | |
| 8170 | static_assert(CallingConventionCold == 2, ""); | |
| 8171 | static_assert(CallingConventionNaked == 3, ""); | |
| 8172 | static_assert(CallingConventionStdcall == 4, ""); | |
| 8173 | static_assert(CallingConventionAsync == 5, ""); | |
| 8174 | ||
| 8175 | static_assert(FnInlineAuto == 0, ""); | |
| 8176 | static_assert(FnInlineAlways == 1, ""); | |
| 8177 | static_assert(FnInlineNever == 2, ""); | |
| 8178 | ||
| 8179 | static_assert(BuiltinPtrSizeOne == 0, ""); | |
| 8180 | static_assert(BuiltinPtrSizeMany == 1, ""); | |
| 8181 | static_assert(BuiltinPtrSizeSlice == 2, ""); | |
| 8182 | static_assert(BuiltinPtrSizeC == 3, ""); | |
| 8176 | 8183 | } |
| 8177 | 8184 | { |
| 8178 | 8185 | buf_appendf(contents, |
src/ir.cpp+181-6| ... | ... | @@ -912,6 +912,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) { |
| 912 | 912 | return IrInstructionIdTypeInfo; |
| 913 | 913 | } |
| 914 | 914 | |
| 915 | static constexpr IrInstructionId ir_instruction_id(IrInstructionType *) { | |
| 916 | return IrInstructionIdType; | |
| 917 | } | |
| 918 | ||
| 915 | 919 | static constexpr IrInstructionId ir_instruction_id(IrInstructionHasField *) { |
| 916 | 920 | return IrInstructionIdHasField; |
| 917 | 921 | } |
| ... | ... | @@ -2907,6 +2911,15 @@ static IrInstruction *ir_build_type_info(IrBuilder *irb, Scope *scope, AstNode * |
| 2907 | 2911 | return &instruction->base; |
| 2908 | 2912 | } |
| 2909 | 2913 | |
| 2914 | static IrInstruction *ir_build_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_info) { | |
| 2915 | IrInstructionType *instruction = ir_build_instruction<IrInstructionType>(irb, scope, source_node); | |
| 2916 | instruction->type_info = type_info; | |
| 2917 | ||
| 2918 | ir_ref_instruction(type_info, irb->current_basic_block); | |
| 2919 | ||
| 2920 | return &instruction->base; | |
| 2921 | } | |
| 2922 | ||
| 2910 | 2923 | static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2911 | 2924 | IrInstruction *type_value) |
| 2912 | 2925 | { |
| ... | ... | @@ -5046,6 +5059,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 5046 | 5059 | IrInstruction *type_info = ir_build_type_info(irb, scope, node, arg0_value); |
| 5047 | 5060 | return ir_lval_wrap(irb, scope, type_info, lval, result_loc); |
| 5048 | 5061 | } |
| 5062 | case BuiltinFnIdType: | |
| 5063 | { | |
| 5064 | AstNode *arg_node = node->data.fn_call_expr.params.at(0); | |
| 5065 | IrInstruction *arg = ir_gen_node(irb, arg_node, scope); | |
| 5066 | if (arg == irb->codegen->invalid_instruction) | |
| 5067 | return arg; | |
| 5068 | ||
| 5069 | IrInstruction *type = ir_build_type(irb, scope, node, arg); | |
| 5070 | return ir_lval_wrap(irb, scope, type, lval, result_loc); | |
| 5071 | } | |
| 5049 | 5072 | case BuiltinFnIdBreakpoint: |
| 5050 | 5073 | return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval, result_loc); |
| 5051 | 5074 | case BuiltinFnIdReturnAddress: |
| ... | ... | @@ -20092,14 +20115,27 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr |
| 20092 | 20115 | return ErrorNone; |
| 20093 | 20116 | } |
| 20094 | 20117 | |
| 20095 | static uint32_t ptr_len_to_size_enum_index(PtrLen ptr_len) { | |
| 20118 | static BuiltinPtrSize ptr_len_to_size_enum_index(PtrLen ptr_len) { | |
| 20096 | 20119 | switch (ptr_len) { |
| 20097 | 20120 | case PtrLenSingle: |
| 20098 | return 0; | |
| 20121 | return BuiltinPtrSizeOne; | |
| 20099 | 20122 | case PtrLenUnknown: |
| 20100 | return 1; | |
| 20123 | return BuiltinPtrSizeMany; | |
| 20101 | 20124 | case PtrLenC: |
| 20102 | return 3; | |
| 20125 | return BuiltinPtrSizeC; | |
| 20126 | } | |
| 20127 | zig_unreachable(); | |
| 20128 | } | |
| 20129 | ||
| 20130 | static PtrLen size_enum_index_to_ptr_len(BuiltinPtrSize size_enum_index) { | |
| 20131 | switch (size_enum_index) { | |
| 20132 | case BuiltinPtrSizeOne: | |
| 20133 | return PtrLenSingle; | |
| 20134 | case BuiltinPtrSizeMany: | |
| 20135 | case BuiltinPtrSizeSlice: | |
| 20136 | return PtrLenUnknown; | |
| 20137 | case BuiltinPtrSizeC: | |
| 20138 | return PtrLenC; | |
| 20103 | 20139 | } |
| 20104 | 20140 | zig_unreachable(); |
| 20105 | 20141 | } |
| ... | ... | @@ -20107,10 +20143,10 @@ static uint32_t ptr_len_to_size_enum_index(PtrLen ptr_len) { |
| 20107 | 20143 | static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_type_entry) { |
| 20108 | 20144 | Error err; |
| 20109 | 20145 | ZigType *attrs_type; |
| 20110 | uint32_t size_enum_index; | |
| 20146 | BuiltinPtrSize size_enum_index; | |
| 20111 | 20147 | if (is_slice(ptr_type_entry)) { |
| 20112 | 20148 | attrs_type = ptr_type_entry->data.structure.fields[slice_ptr_index].type_entry; |
| 20113 | size_enum_index = 2; | |
| 20149 | size_enum_index = BuiltinPtrSizeSlice; | |
| 20114 | 20150 | } else if (ptr_type_entry->id == ZigTypeIdPointer) { |
| 20115 | 20151 | attrs_type = ptr_type_entry; |
| 20116 | 20152 | size_enum_index = ptr_len_to_size_enum_index(ptr_type_entry->data.pointer.ptr_len); |
| ... | ... | @@ -20789,6 +20825,142 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira, |
| 20789 | 20825 | return result; |
| 20790 | 20826 | } |
| 20791 | 20827 | |
| 20828 | static ConstExprValue *get_const_field(IrAnalyze *ira, ConstExprValue *struct_value, const char *name, size_t field_index) | |
| 20829 | { | |
| 20830 | ensure_field_index(struct_value->type, name, field_index); | |
| 20831 | assert(struct_value->data.x_struct.fields[field_index].special == ConstValSpecialStatic); | |
| 20832 | return &struct_value->data.x_struct.fields[field_index]; | |
| 20833 | } | |
| 20834 | ||
| 20835 | static bool get_const_field_bool(IrAnalyze *ira, ConstExprValue *struct_value, const char *name, size_t field_index) | |
| 20836 | { | |
| 20837 | ConstExprValue *value = get_const_field(ira, struct_value, name, field_index); | |
| 20838 | assert(value->type == ira->codegen->builtin_types.entry_bool); | |
| 20839 | return value->data.x_bool; | |
| 20840 | } | |
| 20841 | ||
| 20842 | static BigInt *get_const_field_lit_int(IrAnalyze *ira, ConstExprValue *struct_value, const char *name, size_t field_index) | |
| 20843 | { | |
| 20844 | ConstExprValue *value = get_const_field(ira, struct_value, name, field_index); | |
| 20845 | assert(value->type == ira->codegen->builtin_types.entry_num_lit_int); | |
| 20846 | return &value->data.x_bigint; | |
| 20847 | } | |
| 20848 | ||
| 20849 | static ZigType *get_const_field_meta_type(IrAnalyze *ira, ConstExprValue *struct_value, const char *name, size_t field_index) | |
| 20850 | { | |
| 20851 | ConstExprValue *value = get_const_field(ira, struct_value, name, field_index); | |
| 20852 | assert(value->type == ira->codegen->builtin_types.entry_type); | |
| 20853 | return value->data.x_type; | |
| 20854 | } | |
| 20855 | ||
| 20856 | static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, ZigTypeId tagTypeId, ConstExprValue *payload) { | |
| 20857 | switch (tagTypeId) { | |
| 20858 | case ZigTypeIdInvalid: | |
| 20859 | zig_unreachable(); | |
| 20860 | case ZigTypeIdMetaType: | |
| 20861 | return ira->codegen->builtin_types.entry_type; | |
| 20862 | case ZigTypeIdVoid: | |
| 20863 | return ira->codegen->builtin_types.entry_void; | |
| 20864 | case ZigTypeIdBool: | |
| 20865 | return ira->codegen->builtin_types.entry_bool; | |
| 20866 | case ZigTypeIdUnreachable: | |
| 20867 | return ira->codegen->builtin_types.entry_unreachable; | |
| 20868 | case ZigTypeIdInt: | |
| 20869 | assert(payload->special == ConstValSpecialStatic); | |
| 20870 | assert(payload->type == ir_type_info_get_type(ira, "Int", nullptr)); | |
| 20871 | return get_int_type(ira->codegen, | |
| 20872 | get_const_field_bool(ira, payload, "is_signed", 0), | |
| 20873 | bigint_as_u32(get_const_field_lit_int(ira, payload, "bits", 1))); | |
| 20874 | case ZigTypeIdFloat: | |
| 20875 | { | |
| 20876 | assert(payload->special == ConstValSpecialStatic); | |
| 20877 | assert(payload->type == ir_type_info_get_type(ira, "Float", nullptr)); | |
| 20878 | uint32_t bits = bigint_as_u32(get_const_field_lit_int(ira, payload, "bits", 0)); | |
| 20879 | switch (bits) { | |
| 20880 | case 16: return ira->codegen->builtin_types.entry_f16; | |
| 20881 | case 32: return ira->codegen->builtin_types.entry_f32; | |
| 20882 | case 64: return ira->codegen->builtin_types.entry_f64; | |
| 20883 | case 128: return ira->codegen->builtin_types.entry_f128; | |
| 20884 | } | |
| 20885 | ir_add_error(ira, instruction, | |
| 20886 | buf_sprintf("%d-bit float unsupported", bits)); | |
| 20887 | return nullptr; | |
| 20888 | } | |
| 20889 | case ZigTypeIdPointer: | |
| 20890 | { | |
| 20891 | ZigType *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer", nullptr); | |
| 20892 | assert(payload->special == ConstValSpecialStatic); | |
| 20893 | assert(payload->type == type_info_pointer_type); | |
| 20894 | ConstExprValue *size_value = get_const_field(ira, payload, "size", 0); | |
| 20895 | assert(size_value->type == ir_type_info_get_type(ira, "Size", type_info_pointer_type)); | |
| 20896 | BuiltinPtrSize size_enum_index = (BuiltinPtrSize)bigint_as_u32(&size_value->data.x_enum_tag); | |
| 20897 | PtrLen ptr_len = size_enum_index_to_ptr_len(size_enum_index); | |
| 20898 | ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, | |
| 20899 | get_const_field_meta_type(ira, payload, "child", 4), | |
| 20900 | get_const_field_bool(ira, payload, "is_const", 1), | |
| 20901 | get_const_field_bool(ira, payload, "is_volatile", 2), | |
| 20902 | ptr_len, | |
| 20903 | bigint_as_u32(get_const_field_lit_int(ira, payload, "alignment", 3)), | |
| 20904 | 0, // bit_offset_in_host | |
| 20905 | 0, // host_int_bytes | |
| 20906 | get_const_field_bool(ira, payload, "is_allowzero", 5) | |
| 20907 | ); | |
| 20908 | if (size_enum_index != 2) | |
| 20909 | return ptr_type; | |
| 20910 | return get_slice_type(ira->codegen, ptr_type); | |
| 20911 | } | |
| 20912 | case ZigTypeIdComptimeFloat: | |
| 20913 | return ira->codegen->builtin_types.entry_num_lit_float; | |
| 20914 | case ZigTypeIdComptimeInt: | |
| 20915 | return ira->codegen->builtin_types.entry_num_lit_int; | |
| 20916 | case ZigTypeIdUndefined: | |
| 20917 | return ira->codegen->builtin_types.entry_undef; | |
| 20918 | case ZigTypeIdNull: | |
| 20919 | return ira->codegen->builtin_types.entry_null; | |
| 20920 | case ZigTypeIdArray: | |
| 20921 | case ZigTypeIdOptional: | |
| 20922 | case ZigTypeIdErrorUnion: | |
| 20923 | case ZigTypeIdErrorSet: | |
| 20924 | case ZigTypeIdEnum: | |
| 20925 | case ZigTypeIdOpaque: | |
| 20926 | case ZigTypeIdFnFrame: | |
| 20927 | case ZigTypeIdAnyFrame: | |
| 20928 | case ZigTypeIdVector: | |
| 20929 | case ZigTypeIdEnumLiteral: | |
| 20930 | ir_add_error(ira, instruction, buf_sprintf( | |
| 20931 | "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId))); | |
| 20932 | return nullptr; | |
| 20933 | case ZigTypeIdUnion: | |
| 20934 | case ZigTypeIdFn: | |
| 20935 | case ZigTypeIdBoundFn: | |
| 20936 | case ZigTypeIdArgTuple: | |
| 20937 | case ZigTypeIdStruct: | |
| 20938 | ir_add_error(ira, instruction, buf_sprintf( | |
| 20939 | "@Type not availble for 'TypeInfo.%s'", type_id_name(tagTypeId))); | |
| 20940 | return nullptr; | |
| 20941 | } | |
| 20942 | zig_unreachable(); | |
| 20943 | } | |
| 20944 | ||
| 20945 | static IrInstruction *ir_analyze_instruction_type(IrAnalyze *ira, IrInstructionType *instruction) { | |
| 20946 | IrInstruction *type_info_ir = instruction->type_info->child; | |
| 20947 | if (type_is_invalid(type_info_ir->value.type)) | |
| 20948 | return ira->codegen->invalid_instruction; | |
| 20949 | ||
| 20950 | IrInstruction *casted_ir = ir_implicit_cast(ira, type_info_ir, ir_type_info_get_type(ira, nullptr, nullptr)); | |
| 20951 | if (type_is_invalid(casted_ir->value.type)) | |
| 20952 | return ira->codegen->invalid_instruction; | |
| 20953 | ||
| 20954 | ConstExprValue *type_info_value = ir_resolve_const(ira, casted_ir, UndefBad); | |
| 20955 | if (!type_info_value) | |
| 20956 | return ira->codegen->invalid_instruction; | |
| 20957 | ZigTypeId typeId = type_id_at_index(bigint_as_usize(&type_info_value->data.x_union.tag)); | |
| 20958 | ZigType *type = type_info_to_type(ira, type_info_ir, typeId, type_info_value->data.x_union.payload); | |
| 20959 | if (!type) | |
| 20960 | return ira->codegen->invalid_instruction; | |
| 20961 | return ir_const_type(ira, &instruction->base, type); | |
| 20962 | } | |
| 20963 | ||
| 20792 | 20964 | static IrInstruction *ir_analyze_instruction_type_id(IrAnalyze *ira, |
| 20793 | 20965 | IrInstructionTypeId *instruction) |
| 20794 | 20966 | { |
| ... | ... | @@ -25295,6 +25467,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25295 | 25467 | return ir_analyze_instruction_bit_offset_of(ira, (IrInstructionBitOffsetOf *)instruction); |
| 25296 | 25468 | case IrInstructionIdTypeInfo: |
| 25297 | 25469 | return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction); |
| 25470 | case IrInstructionIdType: | |
| 25471 | return ir_analyze_instruction_type(ira, (IrInstructionType *)instruction); | |
| 25298 | 25472 | case IrInstructionIdHasField: |
| 25299 | 25473 | return ir_analyze_instruction_has_field(ira, (IrInstructionHasField *) instruction); |
| 25300 | 25474 | case IrInstructionIdTypeId: |
| ... | ... | @@ -25598,6 +25772,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 25598 | 25772 | case IrInstructionIdByteOffsetOf: |
| 25599 | 25773 | case IrInstructionIdBitOffsetOf: |
| 25600 | 25774 | case IrInstructionIdTypeInfo: |
| 25775 | case IrInstructionIdType: | |
| 25601 | 25776 | case IrInstructionIdHasField: |
| 25602 | 25777 | case IrInstructionIdTypeId: |
| 25603 | 25778 | case IrInstructionIdAlignCast: |
src/ir_print.cpp+11| ... | ... | @@ -280,6 +280,8 @@ static const char* ir_instruction_type_str(IrInstruction* instruction) { |
| 280 | 280 | return "BitOffsetOf"; |
| 281 | 281 | case IrInstructionIdTypeInfo: |
| 282 | 282 | return "TypeInfo"; |
| 283 | case IrInstructionIdType: | |
| 284 | return "Type"; | |
| 283 | 285 | case IrInstructionIdHasField: |
| 284 | 286 | return "HasField"; |
| 285 | 287 | case IrInstructionIdTypeId: |
| ... | ... | @@ -1627,6 +1629,12 @@ static void ir_print_type_info(IrPrint *irp, IrInstructionTypeInfo *instruction) |
| 1627 | 1629 | fprintf(irp->f, ")"); |
| 1628 | 1630 | } |
| 1629 | 1631 | |
| 1632 | static void ir_print_type(IrPrint *irp, IrInstructionType *instruction) { | |
| 1633 | fprintf(irp->f, "@Type("); | |
| 1634 | ir_print_other_instruction(irp, instruction->type_info); | |
| 1635 | fprintf(irp->f, ")"); | |
| 1636 | } | |
| 1637 | ||
| 1630 | 1638 | static void ir_print_has_field(IrPrint *irp, IrInstructionHasField *instruction) { |
| 1631 | 1639 | fprintf(irp->f, "@hasField("); |
| 1632 | 1640 | ir_print_other_instruction(irp, instruction->container_type); |
| ... | ... | @@ -2258,6 +2266,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool |
| 2258 | 2266 | case IrInstructionIdTypeInfo: |
| 2259 | 2267 | ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction); |
| 2260 | 2268 | break; |
| 2269 | case IrInstructionIdType: | |
| 2270 | ir_print_type(irp, (IrInstructionType *)instruction); | |
| 2271 | break; | |
| 2261 | 2272 | case IrInstructionIdHasField: |
| 2262 | 2273 | ir_print_has_field(irp, (IrInstructionHasField *)instruction); |
| 2263 | 2274 | break; |
test/compile_errors.zig+52| ... | ... | @@ -2,6 +2,58 @@ 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 | "attempt to create 17 bit float type", | |
| 7 | \\const builtin = @import("builtin"); | |
| 8 | \\comptime { | |
| 9 | \\ _ = @Type(builtin.TypeInfo { .Float = builtin.TypeInfo.Float { .bits = 17 } }); | |
| 10 | \\} | |
| 11 | , | |
| 12 | "tmp.zig:3:32: error: 17-bit float unsupported", | |
| 13 | ); | |
| 14 | ||
| 15 | cases.add( | |
| 16 | "wrong type for @Type", | |
| 17 | \\export fn entry() void { | |
| 18 | \\ _ = @Type(0); | |
| 19 | \\} | |
| 20 | , | |
| 21 | "tmp.zig:2:15: error: expected type 'builtin.TypeInfo', found 'comptime_int'", | |
| 22 | ); | |
| 23 | ||
| 24 | cases.add( | |
| 25 | "@Type with non-constant expression", | |
| 26 | \\const builtin = @import("builtin"); | |
| 27 | \\var globalTypeInfo : builtin.TypeInfo = undefined; | |
| 28 | \\export fn entry() void { | |
| 29 | \\ _ = @Type(globalTypeInfo); | |
| 30 | \\} | |
| 31 | , | |
| 32 | "tmp.zig:4:15: error: unable to evaluate constant expression", | |
| 33 | ); | |
| 34 | ||
| 35 | cases.add( | |
| 36 | "@Type with TypeInfo.Int", | |
| 37 | \\const builtin = @import("builtin"); | |
| 38 | \\export fn entry() void { | |
| 39 | \\ _ = @Type(builtin.TypeInfo.Int { | |
| 40 | \\ .is_signed = true, | |
| 41 | \\ .bits = 8, | |
| 42 | \\ }); | |
| 43 | \\} | |
| 44 | , | |
| 45 | "tmp.zig:3:36: error: expected type 'builtin.TypeInfo', found 'builtin.Int'", | |
| 46 | ); | |
| 47 | ||
| 48 | cases.add( | |
| 49 | "Struct unavailable for @Type", | |
| 50 | \\export fn entry() void { | |
| 51 | \\ _ = @Type(@typeInfo(struct { })); | |
| 52 | \\} | |
| 53 | , | |
| 54 | "tmp.zig:2:15: error: @Type not availble for 'TypeInfo.Struct'", | |
| 55 | ); | |
| 56 | ||
| 5 | 57 | cases.add( |
| 6 | 58 | "wrong type for result ptr to @asyncCall", |
| 7 | 59 | \\export fn entry() void { |
test/stage1/behavior.zig+1| ... | ... | @@ -93,6 +93,7 @@ comptime { |
| 93 | 93 | _ = @import("behavior/this.zig"); |
| 94 | 94 | _ = @import("behavior/truncate.zig"); |
| 95 | 95 | _ = @import("behavior/try.zig"); |
| 96 | _ = @import("behavior/type.zig"); | |
| 96 | 97 | _ = @import("behavior/type_info.zig"); |
| 97 | 98 | _ = @import("behavior/typename.zig"); |
| 98 | 99 | _ = @import("behavior/undefined.zig"); |
test/stage1/behavior/type.zig created+107| ... | ... | @@ -0,0 +1,107 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const TypeInfo = builtin.TypeInfo; | |
| 3 | ||
| 4 | const std = @import("std"); | |
| 5 | const testing = std.testing; | |
| 6 | ||
| 7 | fn testTypes(comptime types: []const type) void { | |
| 8 | inline for (types) |testType| { | |
| 9 | testing.expect(testType == @Type(@typeInfo(testType))); | |
| 10 | } | |
| 11 | } | |
| 12 | ||
| 13 | test "Type.MetaType" { | |
| 14 | testing.expect(type == @Type(TypeInfo { .Type = undefined })); | |
| 15 | testTypes([_]type {type}); | |
| 16 | } | |
| 17 | ||
| 18 | test "Type.Void" { | |
| 19 | testing.expect(void == @Type(TypeInfo { .Void = undefined })); | |
| 20 | testTypes([_]type {void}); | |
| 21 | } | |
| 22 | ||
| 23 | test "Type.Bool" { | |
| 24 | testing.expect(bool == @Type(TypeInfo { .Bool = undefined })); | |
| 25 | testTypes([_]type {bool}); | |
| 26 | } | |
| 27 | ||
| 28 | test "Type.NoReturn" { | |
| 29 | testing.expect(noreturn == @Type(TypeInfo { .NoReturn = undefined })); | |
| 30 | testTypes([_]type {noreturn}); | |
| 31 | } | |
| 32 | ||
| 33 | test "Type.Int" { | |
| 34 | testing.expect(u1 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 1 } })); | |
| 35 | testing.expect(i1 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 1 } })); | |
| 36 | testing.expect(u8 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 8 } })); | |
| 37 | testing.expect(i8 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 8 } })); | |
| 38 | testing.expect(u64 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 64 } })); | |
| 39 | testing.expect(i64 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 64 } })); | |
| 40 | testTypes([_]type {u8,u32,i64}); | |
| 41 | } | |
| 42 | ||
| 43 | test "Type.Float" { | |
| 44 | testing.expect(f16 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 16 } })); | |
| 45 | testing.expect(f32 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 32 } })); | |
| 46 | testing.expect(f64 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 64 } })); | |
| 47 | testing.expect(f128 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 128 } })); | |
| 48 | testTypes([_]type {f16, f32, f64, f128}); | |
| 49 | } | |
| 50 | ||
| 51 | test "Type.Pointer" { | |
| 52 | testTypes([_]type { | |
| 53 | // One Value Pointer Types | |
| 54 | *u8, *const u8, | |
| 55 | *volatile u8, *const volatile u8, | |
| 56 | *align(4) u8, *const align(4) u8, | |
| 57 | *volatile align(4) u8, *const volatile align(4) u8, | |
| 58 | *align(8) u8, *const align(8) u8, | |
| 59 | *volatile align(8) u8, *const volatile align(8) u8, | |
| 60 | *allowzero u8, *const allowzero u8, | |
| 61 | *volatile allowzero u8, *const volatile allowzero u8, | |
| 62 | *align(4) allowzero u8, *const align(4) allowzero u8, | |
| 63 | *volatile align(4) allowzero u8, *const volatile align(4) allowzero u8, | |
| 64 | // Many Values Pointer Types | |
| 65 | [*]u8, [*]const u8, | |
| 66 | [*]volatile u8, [*]const volatile u8, | |
| 67 | [*]align(4) u8, [*]const align(4) u8, | |
| 68 | [*]volatile align(4) u8, [*]const volatile align(4) u8, | |
| 69 | [*]align(8) u8, [*]const align(8) u8, | |
| 70 | [*]volatile align(8) u8, [*]const volatile align(8) u8, | |
| 71 | [*]allowzero u8, [*]const allowzero u8, | |
| 72 | [*]volatile allowzero u8, [*]const volatile allowzero u8, | |
| 73 | [*]align(4) allowzero u8, [*]const align(4) allowzero u8, | |
| 74 | [*]volatile align(4) allowzero u8, [*]const volatile align(4) allowzero u8, | |
| 75 | // Slice Types | |
| 76 | []u8, []const u8, | |
| 77 | []volatile u8, []const volatile u8, | |
| 78 | []align(4) u8, []const align(4) u8, | |
| 79 | []volatile align(4) u8, []const volatile align(4) u8, | |
| 80 | []align(8) u8, []const align(8) u8, | |
| 81 | []volatile align(8) u8, []const volatile align(8) u8, | |
| 82 | []allowzero u8, []const allowzero u8, | |
| 83 | []volatile allowzero u8, []const volatile allowzero u8, | |
| 84 | []align(4) allowzero u8, []const align(4) allowzero u8, | |
| 85 | []volatile align(4) allowzero u8, []const volatile align(4) allowzero u8, | |
| 86 | // C Pointer Types | |
| 87 | [*c]u8, [*c]const u8, | |
| 88 | [*c]volatile u8, [*c]const volatile u8, | |
| 89 | [*c]align(4) u8, [*c]const align(4) u8, | |
| 90 | [*c]volatile align(4) u8, [*c]const volatile align(4) u8, | |
| 91 | [*c]align(8) u8, [*c]const align(8) u8, | |
| 92 | [*c]volatile align(8) u8, [*c]const volatile align(8) u8, | |
| 93 | }); | |
| 94 | } | |
| 95 | ||
| 96 | test "Type.ComptimeFloat" { | |
| 97 | testTypes([_]type {comptime_float}); | |
| 98 | } | |
| 99 | test "Type.ComptimeInt" { | |
| 100 | testTypes([_]type {comptime_int}); | |
| 101 | } | |
| 102 | test "Type.Undefined" { | |
| 103 | testTypes([_]type {@typeOf(undefined)}); | |
| 104 | } | |
| 105 | test "Type.Null" { | |
| 106 | testTypes([_]type {@typeOf(null)}); | |
| 107 | } |