From b728cb6d4e882592129eef2e37f8fcd8fda78822 Mon Sep 17 00:00:00 2001 From: Jonathan Marler Date: Fri, 23 Aug 2019 09:33:33 -0600 Subject: [PATCH 1/2] Add @Type builtin --- src/all_types.hpp | 8 ++ src/codegen.cpp | 2 + src/ir.cpp | 179 ++++++++++++++++++++++++++++++++++ src/ir_print.cpp | 11 +++ test/compile_errors.zig | 52 ++++++++++ test/stage1/behavior.zig | 1 + test/stage1/behavior/type.zig | 111 +++++++++++++++++++++ 7 files changed, 364 insertions(+) create mode 100644 test/stage1/behavior/type.zig diff --git a/src/all_types.hpp b/src/all_types.hpp index 1a97cf2814..4253a346f8 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1534,6 +1534,7 @@ enum BuiltinFnId { BuiltinFnIdMemberName, BuiltinFnIdField, BuiltinFnIdTypeInfo, + BuiltinFnIdType, BuiltinFnIdHasField, BuiltinFnIdTypeof, BuiltinFnIdAddWithOverflow, @@ -2436,6 +2437,7 @@ enum IrInstructionId { IrInstructionIdByteOffsetOf, IrInstructionIdBitOffsetOf, IrInstructionIdTypeInfo, + IrInstructionIdType, IrInstructionIdHasField, IrInstructionIdTypeId, IrInstructionIdSetEvalBranchQuota, @@ -3472,6 +3474,12 @@ struct IrInstructionTypeInfo { IrInstruction *type_value; }; +struct IrInstructionType { + IrInstruction base; + + IrInstruction *type_info; +}; + struct IrInstructionHasField { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index d1499592d2..d7d4b44437 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5770,6 +5770,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdByteOffsetOf: case IrInstructionIdBitOffsetOf: case IrInstructionIdTypeInfo: + case IrInstructionIdType: case IrInstructionIdHasField: case IrInstructionIdTypeId: case IrInstructionIdSetEvalBranchQuota: @@ -7597,6 +7598,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2); create_builtin_fn(g, BuiltinFnIdField, "field", 2); create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1); + create_builtin_fn(g, BuiltinFnIdType, "Type", 1); create_builtin_fn(g, BuiltinFnIdHasField, "hasField", 2); create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4); diff --git a/src/ir.cpp b/src/ir.cpp index 7415a2dd6b..953467c185 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -912,6 +912,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) { return IrInstructionIdTypeInfo; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionType *) { + return IrInstructionIdType; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionHasField *) { return IrInstructionIdHasField; } @@ -2907,6 +2911,15 @@ static IrInstruction *ir_build_type_info(IrBuilder *irb, Scope *scope, AstNode * return &instruction->base; } +static IrInstruction *ir_build_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_info) { + IrInstructionType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type_info = type_info; + + ir_ref_instruction(type_info, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) { @@ -5046,6 +5059,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *type_info = ir_build_type_info(irb, scope, node, arg0_value); return ir_lval_wrap(irb, scope, type_info, lval, result_loc); } + case BuiltinFnIdType: + { + AstNode *arg_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg = ir_gen_node(irb, arg_node, scope); + if (arg == irb->codegen->invalid_instruction) + return arg; + + IrInstruction *type = ir_build_type(irb, scope, node, arg); + return ir_lval_wrap(irb, scope, type, lval, result_loc); + } case BuiltinFnIdBreakpoint: return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval, result_loc); case BuiltinFnIdReturnAddress: @@ -20104,6 +20127,18 @@ static uint32_t ptr_len_to_size_enum_index(PtrLen ptr_len) { zig_unreachable(); } +static PtrLen size_enum_index_to_ptr_len(uint32_t size_enum_index) { + switch (size_enum_index) { + case 0: + return PtrLenSingle; + case 1: + return PtrLenUnknown; + case 3: + return PtrLenC; + } + zig_unreachable(); +} + static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_type_entry) { Error err; ZigType *attrs_type; @@ -20789,6 +20824,147 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira, return result; } +static ConstExprValue *get_const_field(IrAnalyze *ira, ConstExprValue *struct_value, const char *name, size_t field_index) +{ + ensure_field_index(struct_value->type, name, field_index); + assert(struct_value->data.x_struct.fields[field_index].special == ConstValSpecialStatic); + return &struct_value->data.x_struct.fields[field_index]; +} + +static bool get_const_field_bool(IrAnalyze *ira, ConstExprValue *struct_value, const char *name, size_t field_index) +{ + ConstExprValue *value = get_const_field(ira, struct_value, name, field_index); + assert(value->type == ira->codegen->builtin_types.entry_bool); + return value->data.x_bool; +} + +static BigInt *get_const_field_lit_int(IrAnalyze *ira, ConstExprValue *struct_value, const char *name, size_t field_index) +{ + ConstExprValue *value = get_const_field(ira, struct_value, name, field_index); + assert(value->type == ira->codegen->builtin_types.entry_num_lit_int); + return &value->data.x_bigint; +} + +static ZigType *get_const_field_meta_type(IrAnalyze *ira, ConstExprValue *struct_value, const char *name, size_t field_index) +{ + ConstExprValue *value = get_const_field(ira, struct_value, name, field_index); + assert(value->type == ira->codegen->builtin_types.entry_type); + return value->data.x_type; +} + +static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, ZigTypeId tagTypeId, ConstExprValue *payload) { + switch (tagTypeId) { + case ZigTypeIdInvalid: + zig_unreachable(); + case ZigTypeIdMetaType: + return ira->codegen->builtin_types.entry_type; + case ZigTypeIdVoid: + return ira->codegen->builtin_types.entry_void; + case ZigTypeIdBool: + return ira->codegen->builtin_types.entry_bool; + case ZigTypeIdUnreachable: + return ira->codegen->builtin_types.entry_unreachable; + case ZigTypeIdInt: + assert(payload->special == ConstValSpecialStatic); + assert(payload->type == ir_type_info_get_type(ira, "Int", nullptr)); + return get_int_type(ira->codegen, + get_const_field_bool(ira, payload, "is_signed", 0), + bigint_as_u32(get_const_field_lit_int(ira, payload, "bits", 1))); + case ZigTypeIdFloat: + { + assert(payload->special == ConstValSpecialStatic); + assert(payload->type == ir_type_info_get_type(ira, "Float", nullptr)); + uint32_t bits = bigint_as_u32(get_const_field_lit_int(ira, payload, "bits", 0)); + switch (bits) { + case 16: return ira->codegen->builtin_types.entry_f16; + case 32: return ira->codegen->builtin_types.entry_f32; + case 64: return ira->codegen->builtin_types.entry_f64; + case 128: return ira->codegen->builtin_types.entry_f128; + } + ir_add_error(ira, instruction, + buf_sprintf("%d-bit float unsupported", bits)); + return nullptr; + } + case ZigTypeIdPointer: + { + ZigType *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer", nullptr); + assert(payload->special == ConstValSpecialStatic); + assert(payload->type == type_info_pointer_type); + ConstExprValue *size_value = get_const_field(ira, payload, "size", 0); + assert(size_value->type == ir_type_info_get_type(ira, "Size", type_info_pointer_type)); + uint32_t size_enum_index = bigint_as_u32(&size_value->data.x_enum_tag); + PtrLen ptr_len; + if (size_enum_index == 2) { + ptr_len = PtrLenUnknown; // TODO: is this right? + } else { + ptr_len = size_enum_index_to_ptr_len(size_enum_index); + } + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, + get_const_field_meta_type(ira, payload, "child", 4), + get_const_field_bool(ira, payload, "is_const", 1), + get_const_field_bool(ira, payload, "is_volatile", 2), + ptr_len, + bigint_as_u32(get_const_field_lit_int(ira, payload, "alignment", 3)), + 0, // bit_offset_in_host??? + 0, // host_int_bytes??? + get_const_field_bool(ira, payload, "is_allowzero", 5) + ); + if (size_enum_index != 2) + return ptr_type; + return get_slice_type(ira->codegen, ptr_type); + } + case ZigTypeIdComptimeFloat: + return ira->codegen->builtin_types.entry_num_lit_float; + case ZigTypeIdComptimeInt: + return ira->codegen->builtin_types.entry_num_lit_int; + case ZigTypeIdUndefined: + return ira->codegen->builtin_types.entry_undef; + case ZigTypeIdNull: + return ira->codegen->builtin_types.entry_null; + case ZigTypeIdArray: + case ZigTypeIdOptional: + case ZigTypeIdErrorUnion: + case ZigTypeIdErrorSet: + case ZigTypeIdEnum: + case ZigTypeIdOpaque: + case ZigTypeIdFnFrame: + case ZigTypeIdAnyFrame: + case ZigTypeIdVector: + case ZigTypeIdEnumLiteral: + ir_add_error(ira, instruction, buf_sprintf( + "TODO implement @Type forr 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907\n", type_id_name(tagTypeId))); + return nullptr; + case ZigTypeIdUnion: + case ZigTypeIdFn: + case ZigTypeIdBoundFn: + case ZigTypeIdArgTuple: + case ZigTypeIdStruct: + ir_add_error(ira, instruction, buf_sprintf( + "@Type not availble for 'TypeInfo.%s'\n", type_id_name(tagTypeId))); + return nullptr; + } + zig_unreachable(); +} + +static IrInstruction *ir_analyze_instruction_type(IrAnalyze *ira, IrInstructionType *instruction) { + IrInstruction *type_info_ir = instruction->type_info->child; + if (type_is_invalid(type_info_ir->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *casted_ir = ir_implicit_cast(ira, type_info_ir, ir_type_info_get_type(ira, nullptr, nullptr)); + if (type_is_invalid(casted_ir->value.type)) + return ira->codegen->invalid_instruction; + + ConstExprValue *type_info_value = ir_resolve_const(ira, casted_ir, UndefBad); + if (!type_info_value) + return ira->codegen->invalid_instruction; + ZigTypeId typeId = type_id_at_index(bigint_as_usize(&type_info_value->data.x_union.tag)); + ZigType *type = type_info_to_type(ira, type_info_ir, typeId, type_info_value->data.x_union.payload); + if (!type) + return ira->codegen->invalid_instruction; + return ir_const_type(ira, &instruction->base, type); +} + static IrInstruction *ir_analyze_instruction_type_id(IrAnalyze *ira, IrInstructionTypeId *instruction) { @@ -25295,6 +25471,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_bit_offset_of(ira, (IrInstructionBitOffsetOf *)instruction); case IrInstructionIdTypeInfo: return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction); + case IrInstructionIdType: + return ir_analyze_instruction_type(ira, (IrInstructionType *)instruction); case IrInstructionIdHasField: return ir_analyze_instruction_has_field(ira, (IrInstructionHasField *) instruction); case IrInstructionIdTypeId: @@ -25598,6 +25776,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdByteOffsetOf: case IrInstructionIdBitOffsetOf: case IrInstructionIdTypeInfo: + case IrInstructionIdType: case IrInstructionIdHasField: case IrInstructionIdTypeId: case IrInstructionIdAlignCast: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 6de585ec6f..25eb01365f 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -280,6 +280,8 @@ static const char* ir_instruction_type_str(IrInstruction* instruction) { return "BitOffsetOf"; case IrInstructionIdTypeInfo: return "TypeInfo"; + case IrInstructionIdType: + return "Type"; case IrInstructionIdHasField: return "HasField"; case IrInstructionIdTypeId: @@ -1627,6 +1629,12 @@ static void ir_print_type_info(IrPrint *irp, IrInstructionTypeInfo *instruction) fprintf(irp->f, ")"); } +static void ir_print_type(IrPrint *irp, IrInstructionType *instruction) { + fprintf(irp->f, "@Type("); + ir_print_other_instruction(irp, instruction->type_info); + fprintf(irp->f, ")"); +} + static void ir_print_has_field(IrPrint *irp, IrInstructionHasField *instruction) { fprintf(irp->f, "@hasField("); ir_print_other_instruction(irp, instruction->container_type); @@ -2258,6 +2266,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool case IrInstructionIdTypeInfo: ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction); break; + case IrInstructionIdType: + ir_print_type(irp, (IrInstructionType *)instruction); + break; case IrInstructionIdHasField: ir_print_has_field(irp, (IrInstructionHasField *)instruction); break; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 871ff63e23..1438a59539 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,58 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); pub fn addCases(cases: *tests.CompileErrorContext) void { + + cases.add( + "wrong type for @Type", + \\export fn entry() void { + \\ _ = @Type(0); + \\} + , + "tmp.zig:2:15: error: expected type 'builtin.TypeInfo', found 'comptime_int'", + ); + + cases.add( + "@Type with non-constant expression", + \\const builtin = @import("builtin"); + \\var globalTypeInfo : builtin.TypeInfo = undefined; + \\export fn entry() void { + \\ _ = @Type(globalTypeInfo); + \\} + , + "tmp.zig:4:15: error: unable to evaluate constant expression", + ); + + cases.add( + "@Type with TypeInfo.Int", + \\const builtin = @import("builtin"); + \\export fn entry() void { + \\ _ = @Type(builtin.TypeInfo.Int { + \\ .is_signed = true, + \\ .bits = 8, + \\ }); + \\} + , + "tmp.zig:3:36: error: expected type 'builtin.TypeInfo', found 'builtin.Int'", + ); + + cases.add( + "Struct unavailable for @Type", + \\export fn entry() void { + \\ _ = @Type(@typeInfo(struct { })); + \\} + , + "tmp.zig:2:15: error: @Type not availble for 'TypeInfo.Struct'", + ); + + cases.add( + "array not implemented for @Type", + \\export fn entry() void { + \\ _ = @Type(@typeInfo(enum{x})); + \\} + , + "tmp.zig:2:15: error: TODO implement @Type forr 'TypeInfo.Enum': see https://github.com/ziglang/zig/issues/2907", + ); + cases.add( "wrong type for result ptr to @asyncCall", \\export fn entry() void { diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 23ec3e53ce..db6cdad3b1 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -93,6 +93,7 @@ comptime { _ = @import("behavior/this.zig"); _ = @import("behavior/truncate.zig"); _ = @import("behavior/try.zig"); + _ = @import("behavior/type.zig"); _ = @import("behavior/type_info.zig"); _ = @import("behavior/typename.zig"); _ = @import("behavior/undefined.zig"); diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig new file mode 100644 index 0000000000..318e07fbdf --- /dev/null +++ b/test/stage1/behavior/type.zig @@ -0,0 +1,111 @@ +const builtin = @import("builtin"); +const TypeInfo = builtin.TypeInfo; + +const std = @import("std"); +const testing = std.testing; + +fn testTypes(comptime types: []const type) void { + inline for (types) |testType| { + testing.expect(testType == @Type(@typeInfo(testType))); + } +} + +test "Type.MetaType" { + testing.expect(type == @Type(TypeInfo { .Type = undefined })); + testTypes([_]type {type}); +} + +test "Type.Void" { + testing.expect(void == @Type(TypeInfo { .Void = undefined })); + testTypes([_]type {void}); +} + +test "Type.Bool" { + testing.expect(bool == @Type(TypeInfo { .Bool = undefined })); + testTypes([_]type {bool}); +} + +test "Type.NoReturn" { + testing.expect(noreturn == @Type(TypeInfo { .NoReturn = undefined })); + testTypes([_]type {noreturn}); +} + +test "Type.Int" { + testing.expect(u1 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 1 } })); + testing.expect(i1 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 1 } })); + testing.expect(u8 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 8 } })); + testing.expect(i8 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 8 } })); + testing.expect(u64 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 64 } })); + testing.expect(i64 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 64 } })); + testTypes([_]type {u8,u32,i64}); + // TODO: should this work? + //testing.expect(u1 == @Type(TypeInfo.Int { .is_signed = false, .bits = 1 } )); +} + +test "Type.Float" { + testing.expect(f16 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 16 } })); + testing.expect(f32 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 32 } })); + testing.expect(f64 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 64 } })); + testing.expect(f128 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 128 } })); + testTypes([_]type {f16, f32, f64, f128}); + // error: 17-bit float unsupported + //testing.expect(f16 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 17 } })); +} + +test "Type.Pointer" { + testTypes([_]type { + // One Value Pointer Types + *u8, *const u8, + *volatile u8, *const volatile u8, + *align(4) u8, *const align(4) u8, + *volatile align(4) u8, *const volatile align(4) u8, + *align(8) u8, *const align(8) u8, + *volatile align(8) u8, *const volatile align(8) u8, + *allowzero u8, *const allowzero u8, + *volatile allowzero u8, *const volatile allowzero u8, + *align(4) allowzero u8, *const align(4) allowzero u8, + *volatile align(4) allowzero u8, *const volatile align(4) allowzero u8, + // Many Values Pointer Types + [*]u8, [*]const u8, + [*]volatile u8, [*]const volatile u8, + [*]align(4) u8, [*]const align(4) u8, + [*]volatile align(4) u8, [*]const volatile align(4) u8, + [*]align(8) u8, [*]const align(8) u8, + [*]volatile align(8) u8, [*]const volatile align(8) u8, + [*]allowzero u8, [*]const allowzero u8, + [*]volatile allowzero u8, [*]const volatile allowzero u8, + [*]align(4) allowzero u8, [*]const align(4) allowzero u8, + [*]volatile align(4) allowzero u8, [*]const volatile align(4) allowzero u8, + // Slice Types + []u8, []const u8, + []volatile u8, []const volatile u8, + []align(4) u8, []const align(4) u8, + []volatile align(4) u8, []const volatile align(4) u8, + []align(8) u8, []const align(8) u8, + []volatile align(8) u8, []const volatile align(8) u8, + []allowzero u8, []const allowzero u8, + []volatile allowzero u8, []const volatile allowzero u8, + []align(4) allowzero u8, []const align(4) allowzero u8, + []volatile align(4) allowzero u8, []const volatile align(4) allowzero u8, + // C Pointer Types + [*c]u8, [*c]const u8, + [*c]volatile u8, [*c]const volatile u8, + [*c]align(4) u8, [*c]const align(4) u8, + [*c]volatile align(4) u8, [*c]const volatile align(4) u8, + [*c]align(8) u8, [*c]const align(8) u8, + [*c]volatile align(8) u8, [*c]const volatile align(8) u8, + }); +} + +test "Type.ComptimeFloat" { + testTypes([_]type {comptime_float}); +} +test "Type.ComptimeInt" { + testTypes([_]type {comptime_int}); +} +test "Type.Undefined" { + testTypes([_]type {@typeOf(undefined)}); +} +test "Type.Null" { + testTypes([_]type {@typeOf(null)}); +} From ac7703f65f7acc9137e28ded97659fbaadea4e66 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 4 Sep 2019 11:08:28 -0400 Subject: [PATCH 2/2] fixups and add documentation for `@Type` --- doc/docgen.zig | 26 ++++++++++++++-- doc/langref.html.in | 56 ++++++++++++++++++++++++++++++++++- src/all_types.hpp | 8 +++++ src/codegen.cpp | 29 ++++++++++-------- src/ir.cpp | 38 +++++++++++------------- test/compile_errors.zig | 18 +++++------ test/stage1/behavior/type.zig | 4 --- 7 files changed, 130 insertions(+), 49 deletions(-) diff --git a/doc/docgen.zig b/doc/docgen.zig index a2b4e8501c..eee4c45369 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -321,6 +321,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { var header_stack_size: usize = 0; var last_action = Action.Open; + var last_columns: ?u8 = null; var toc_buf = try std.Buffer.initSize(allocator, 0); defer toc_buf.deinit(); @@ -361,7 +362,23 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { _ = try eatToken(tokenizer, Token.Id.Separator); const content_token = try eatToken(tokenizer, Token.Id.TagContent); const content = tokenizer.buffer[content_token.start..content_token.end]; - _ = try eatToken(tokenizer, Token.Id.BracketClose); + var columns: ?u8 = null; + while (true) { + const bracket_tok = tokenizer.next(); + switch (bracket_tok.id) { + .BracketClose => break, + .Separator => continue, + .TagContent => { + const param = tokenizer.buffer[bracket_tok.start..bracket_tok.end]; + if (mem.eql(u8, param, "3col")) { + columns = 3; + } else { + return parseError(tokenizer, bracket_tok, "unrecognized header_open param: {}", param); + } + }, + else => return parseError(tokenizer, bracket_tok, "invalid header_open token"), + } + } header_stack_size += 1; @@ -381,10 +398,15 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { if (last_action == Action.Open) { try toc.writeByte('\n'); try toc.writeByteNTimes(' ', header_stack_size * 4); - try toc.write("
    \n"); + if (last_columns) |n| { + try toc.print("
      \n", n); + } else { + try toc.write("
        \n"); + } } else { last_action = Action.Open; } + last_columns = columns; try toc.writeByteNTimes(' ', 4 + header_stack_size * 4); try toc.print("
      • {}", urlized, urlized, content); } else if (mem.eql(u8, tag_name, "header_close")) { diff --git a/doc/langref.html.in b/doc/langref.html.in index 44b2256813..2ad86d653e 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6323,7 +6323,7 @@ fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 { {#header_close#} {#header_close#} - {#header_open|Builtin Functions#} + {#header_open|Builtin Functions|3col#}

        Builtin functions are provided by the compiler and are prefixed with @. 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; } This function returns an integer type with the given signness and bit count. The maximum bit count for an integer type is {#syntax#}65535{#endsyntax#}.

        +

        + Deprecated. Use {#link|@Type#}. +

        {#header_close#} {#header_open|@memberCount#} @@ -7871,6 +7874,57 @@ test "integer truncation" {

        {#header_close#} + {#header_open|@Type#} +
        {#syntax#}@Type(comptime info: @import("builtin").TypeInfo) type{#endsyntax#}
        +

        + This function is the inverse of {#link|@typeInfo#}. It reifies type information + into a {#syntax#}type{#endsyntax#}. +

        +

        + It is available for the following types: +

        +
          +
        • {#syntax#}type{#endsyntax#}
        • +
        • {#syntax#}noreturn{#endsyntax#}
        • +
        • {#syntax#}void{#endsyntax#}
        • +
        • {#syntax#}bool{#endsyntax#}
        • +
        • {#link|Integers#}
        • - The maximum bit count for an integer type is {#syntax#}65535{#endsyntax#}. +
        • {#link|Floats#}
        • +
        • {#link|Pointers#}
        • +
        • {#syntax#}comptime_int{#endsyntax#}
        • +
        • {#syntax#}comptime_float{#endsyntax#}
        • +
        • {#syntax#}@typeOf(undefined){#endsyntax#}
        • +
        • {#syntax#}@typeOf(null){#endsyntax#}
        • +
        +

        + For these types it is a + TODO in the compiler to implement: +

        +
          +
        • Array
        • +
        • Optional
        • +
        • ErrorUnion
        • +
        • ErrorSet
        • +
        • Enum
        • +
        • Opaque
        • +
        • FnFrame
        • +
        • AnyFrame
        • +
        • Vector
        • +
        • EnumLiteral
        • +
        +

        + For these types, {#syntax#}@Type{#endsyntax#} is not available. + There is an open proposal to allow unions and structs. +

        +
          +
        • {#link|union#}
        • +
        • {#link|Functions#}
        • +
        • BoundFn
        • +
        • ArgTuple
        • +
        • {#link|struct#}
        • +
        + {#header_close#} + {#header_open|@typeId#}
        {#syntax#}@typeId(comptime T: type) @import("builtin").TypeId{#endsyntax#}

        diff --git a/src/all_types.hpp b/src/all_types.hpp index 4253a346f8..03559ccf12 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -54,6 +54,14 @@ enum PtrLen { PtrLenC, }; +// This one corresponds to the builtin.zig enum. +enum BuiltinPtrSize { + BuiltinPtrSizeOne, + BuiltinPtrSizeMany, + BuiltinPtrSizeSlice, + BuiltinPtrSizeC, +}; + enum UndefAllowed { UndefOk, UndefBad, diff --git a/src/codegen.cpp b/src/codegen.cpp index d7d4b44437..13fb0d625d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8161,20 +8161,25 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " };\n" " };\n" "};\n\n"); - assert(ContainerLayoutAuto == 0); - assert(ContainerLayoutExtern == 1); - assert(ContainerLayoutPacked == 2); + static_assert(ContainerLayoutAuto == 0, ""); + static_assert(ContainerLayoutExtern == 1, ""); + static_assert(ContainerLayoutPacked == 2, ""); - assert(CallingConventionUnspecified == 0); - assert(CallingConventionC == 1); - assert(CallingConventionCold == 2); - assert(CallingConventionNaked == 3); - assert(CallingConventionStdcall == 4); - assert(CallingConventionAsync == 5); + static_assert(CallingConventionUnspecified == 0, ""); + static_assert(CallingConventionC == 1, ""); + static_assert(CallingConventionCold == 2, ""); + static_assert(CallingConventionNaked == 3, ""); + static_assert(CallingConventionStdcall == 4, ""); + static_assert(CallingConventionAsync == 5, ""); - assert(FnInlineAuto == 0); - assert(FnInlineAlways == 1); - assert(FnInlineNever == 2); + static_assert(FnInlineAuto == 0, ""); + static_assert(FnInlineAlways == 1, ""); + static_assert(FnInlineNever == 2, ""); + + static_assert(BuiltinPtrSizeOne == 0, ""); + static_assert(BuiltinPtrSizeMany == 1, ""); + static_assert(BuiltinPtrSizeSlice == 2, ""); + static_assert(BuiltinPtrSizeC == 3, ""); } { buf_appendf(contents, diff --git a/src/ir.cpp b/src/ir.cpp index 953467c185..9547b1ec61 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20115,25 +20115,26 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr return ErrorNone; } -static uint32_t ptr_len_to_size_enum_index(PtrLen ptr_len) { +static BuiltinPtrSize ptr_len_to_size_enum_index(PtrLen ptr_len) { switch (ptr_len) { case PtrLenSingle: - return 0; + return BuiltinPtrSizeOne; case PtrLenUnknown: - return 1; + return BuiltinPtrSizeMany; case PtrLenC: - return 3; + return BuiltinPtrSizeC; } zig_unreachable(); } -static PtrLen size_enum_index_to_ptr_len(uint32_t size_enum_index) { +static PtrLen size_enum_index_to_ptr_len(BuiltinPtrSize size_enum_index) { switch (size_enum_index) { - case 0: + case BuiltinPtrSizeOne: return PtrLenSingle; - case 1: + case BuiltinPtrSizeMany: + case BuiltinPtrSizeSlice: return PtrLenUnknown; - case 3: + case BuiltinPtrSizeC: return PtrLenC; } zig_unreachable(); @@ -20142,10 +20143,10 @@ static PtrLen size_enum_index_to_ptr_len(uint32_t size_enum_index) { static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_type_entry) { Error err; ZigType *attrs_type; - uint32_t size_enum_index; + BuiltinPtrSize size_enum_index; if (is_slice(ptr_type_entry)) { attrs_type = ptr_type_entry->data.structure.fields[slice_ptr_index].type_entry; - size_enum_index = 2; + size_enum_index = BuiltinPtrSizeSlice; } else if (ptr_type_entry->id == ZigTypeIdPointer) { attrs_type = ptr_type_entry; size_enum_index = ptr_len_to_size_enum_index(ptr_type_entry->data.pointer.ptr_len); @@ -20892,21 +20893,16 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi assert(payload->type == type_info_pointer_type); ConstExprValue *size_value = get_const_field(ira, payload, "size", 0); assert(size_value->type == ir_type_info_get_type(ira, "Size", type_info_pointer_type)); - uint32_t size_enum_index = bigint_as_u32(&size_value->data.x_enum_tag); - PtrLen ptr_len; - if (size_enum_index == 2) { - ptr_len = PtrLenUnknown; // TODO: is this right? - } else { - ptr_len = size_enum_index_to_ptr_len(size_enum_index); - } + BuiltinPtrSize size_enum_index = (BuiltinPtrSize)bigint_as_u32(&size_value->data.x_enum_tag); + PtrLen ptr_len = size_enum_index_to_ptr_len(size_enum_index); ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, get_const_field_meta_type(ira, payload, "child", 4), get_const_field_bool(ira, payload, "is_const", 1), get_const_field_bool(ira, payload, "is_volatile", 2), ptr_len, bigint_as_u32(get_const_field_lit_int(ira, payload, "alignment", 3)), - 0, // bit_offset_in_host??? - 0, // host_int_bytes??? + 0, // bit_offset_in_host + 0, // host_int_bytes get_const_field_bool(ira, payload, "is_allowzero", 5) ); if (size_enum_index != 2) @@ -20932,7 +20928,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi case ZigTypeIdVector: case ZigTypeIdEnumLiteral: ir_add_error(ira, instruction, buf_sprintf( - "TODO implement @Type forr 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907\n", type_id_name(tagTypeId))); + "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId))); return nullptr; case ZigTypeIdUnion: case ZigTypeIdFn: @@ -20940,7 +20936,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi case ZigTypeIdArgTuple: case ZigTypeIdStruct: ir_add_error(ira, instruction, buf_sprintf( - "@Type not availble for 'TypeInfo.%s'\n", type_id_name(tagTypeId))); + "@Type not availble for 'TypeInfo.%s'", type_id_name(tagTypeId))); return nullptr; } zig_unreachable(); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 1438a59539..38fca5754d 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,15 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "attempt to create 17 bit float type", + \\const builtin = @import("builtin"); + \\comptime { + \\ _ = @Type(builtin.TypeInfo { .Float = builtin.TypeInfo.Float { .bits = 17 } }); + \\} + , + "tmp.zig:3:32: error: 17-bit float unsupported", + ); cases.add( "wrong type for @Type", @@ -45,15 +54,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:15: error: @Type not availble for 'TypeInfo.Struct'", ); - cases.add( - "array not implemented for @Type", - \\export fn entry() void { - \\ _ = @Type(@typeInfo(enum{x})); - \\} - , - "tmp.zig:2:15: error: TODO implement @Type forr 'TypeInfo.Enum': see https://github.com/ziglang/zig/issues/2907", - ); - cases.add( "wrong type for result ptr to @asyncCall", \\export fn entry() void { diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig index 318e07fbdf..5b2998f088 100644 --- a/test/stage1/behavior/type.zig +++ b/test/stage1/behavior/type.zig @@ -38,8 +38,6 @@ test "Type.Int" { testing.expect(u64 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 64 } })); testing.expect(i64 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 64 } })); testTypes([_]type {u8,u32,i64}); - // TODO: should this work? - //testing.expect(u1 == @Type(TypeInfo.Int { .is_signed = false, .bits = 1 } )); } test "Type.Float" { @@ -48,8 +46,6 @@ test "Type.Float" { testing.expect(f64 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 64 } })); testing.expect(f128 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 128 } })); testTypes([_]type {f16, f32, f64, f128}); - // error: 17-bit float unsupported - //testing.expect(f16 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 17 } })); } test "Type.Pointer" {