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" {