Merge pull request #951 from alexnask/reflect_reify
Metaprogramming - @typeInfo [DONE]
This commit is contained in:
commit
b9e320dd52
@ -4809,6 +4809,182 @@ pub const TypeId = enum {
|
||||
BoundFn,
|
||||
ArgTuple,
|
||||
Opaque,
|
||||
};
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
{#header_open|@typeInfo#}
|
||||
<pre><code class="zig">@typeInfo(comptime T: type) -> @import("builtin").TypeInfo</code></pre>
|
||||
<p>
|
||||
Returns information on the type. Returns a value of the following union:
|
||||
</p>
|
||||
{#code_begin|syntax#}
|
||||
pub const TypeInfo = union(TypeId) {
|
||||
Type: void,
|
||||
Void: void,
|
||||
Bool: void,
|
||||
NoReturn: void,
|
||||
Int: Int,
|
||||
Float: Float,
|
||||
Pointer: Pointer,
|
||||
Array: Array,
|
||||
Struct: Struct,
|
||||
FloatLiteral: void,
|
||||
IntLiteral: void,
|
||||
UndefinedLiteral: void,
|
||||
NullLiteral: void,
|
||||
Nullable: Nullable,
|
||||
ErrorUnion: ErrorUnion,
|
||||
ErrorSet: ErrorSet,
|
||||
Enum: Enum,
|
||||
Union: Union,
|
||||
Fn: Fn,
|
||||
Namespace: void,
|
||||
Block: void,
|
||||
BoundFn: Fn,
|
||||
ArgTuple: void,
|
||||
Opaque: void,
|
||||
Promise: Promise,
|
||||
|
||||
|
||||
pub const Int = struct {
|
||||
is_signed: bool,
|
||||
bits: u8,
|
||||
};
|
||||
|
||||
pub const Float = struct {
|
||||
bits: u8,
|
||||
};
|
||||
|
||||
pub const Pointer = struct {
|
||||
is_const: bool,
|
||||
is_volatile: bool,
|
||||
alignment: u32,
|
||||
child: type,
|
||||
};
|
||||
|
||||
pub const Array = struct {
|
||||
len: usize,
|
||||
child: type,
|
||||
};
|
||||
|
||||
pub const ContainerLayout = enum {
|
||||
Auto,
|
||||
Extern,
|
||||
Packed,
|
||||
};
|
||||
|
||||
pub const StructField = struct {
|
||||
name: []const u8,
|
||||
offset: ?usize,
|
||||
field_type: type,
|
||||
};
|
||||
|
||||
pub const Struct = struct {
|
||||
layout: ContainerLayout,
|
||||
fields: []StructField,
|
||||
defs: []Definition,
|
||||
};
|
||||
|
||||
pub const Nullable = struct {
|
||||
child: type,
|
||||
};
|
||||
|
||||
pub const ErrorUnion = struct {
|
||||
error_set: type,
|
||||
payload: type,
|
||||
};
|
||||
|
||||
pub const Error = struct {
|
||||
name: []const u8,
|
||||
value: usize,
|
||||
};
|
||||
|
||||
pub const ErrorSet = struct {
|
||||
errors: []Error,
|
||||
};
|
||||
|
||||
pub const EnumField = struct {
|
||||
name: []const u8,
|
||||
value: usize,
|
||||
};
|
||||
|
||||
pub const Enum = struct {
|
||||
layout: ContainerLayout,
|
||||
tag_type: type,
|
||||
fields: []EnumField,
|
||||
defs: []Definition,
|
||||
};
|
||||
|
||||
pub const UnionField = struct {
|
||||
name: []const u8,
|
||||
enum_field: ?EnumField,
|
||||
field_type: type,
|
||||
};
|
||||
|
||||
pub const Union = struct {
|
||||
layout: ContainerLayout,
|
||||
tag_type: type,
|
||||
fields: []UnionField,
|
||||
defs: []Definition,
|
||||
};
|
||||
|
||||
pub const CallingConvention = enum {
|
||||
Unspecified,
|
||||
C,
|
||||
Cold,
|
||||
Naked,
|
||||
Stdcall,
|
||||
Async,
|
||||
};
|
||||
|
||||
pub const FnArg = struct {
|
||||
is_generic: bool,
|
||||
is_noalias: bool,
|
||||
arg_type: type,
|
||||
};
|
||||
|
||||
pub const Fn = struct {
|
||||
calling_convention: CallingConvention,
|
||||
is_generic: bool,
|
||||
is_var_args: bool,
|
||||
return_type: type,
|
||||
async_allocator_type: type,
|
||||
args: []FnArg,
|
||||
};
|
||||
|
||||
pub const Promise = struct {
|
||||
child: type,
|
||||
};
|
||||
|
||||
pub const Definition = struct {
|
||||
name: []const u8,
|
||||
is_pub: bool,
|
||||
data: Data,
|
||||
|
||||
pub const Data = union(enum) {
|
||||
Type: type,
|
||||
Var: type,
|
||||
Fn: FnDef,
|
||||
|
||||
pub const FnDef = struct {
|
||||
fn_type: type,
|
||||
inline_type: Inline,
|
||||
calling_convention: CallingConvention,
|
||||
is_var_args: bool,
|
||||
is_extern: bool,
|
||||
is_export: bool,
|
||||
lib_name: ?[]const u8,
|
||||
return_type: type,
|
||||
arg_names: [][] const u8,
|
||||
|
||||
pub const Inline = enum {
|
||||
Auto,
|
||||
Always,
|
||||
Never,
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
@ -5226,7 +5402,6 @@ pub const Os = enum {
|
||||
rtems,
|
||||
nacl,
|
||||
cnk,
|
||||
bitrig,
|
||||
aix,
|
||||
cuda,
|
||||
nvcl,
|
||||
@ -5237,10 +5412,12 @@ pub const Os = enum {
|
||||
watchos,
|
||||
mesa3d,
|
||||
contiki,
|
||||
amdpal,
|
||||
zen,
|
||||
};
|
||||
|
||||
pub const Arch = enum {
|
||||
armv8_3a,
|
||||
armv8_2a,
|
||||
armv8_1a,
|
||||
armv8,
|
||||
@ -5260,9 +5437,29 @@ pub const Arch = enum {
|
||||
armv5,
|
||||
armv5te,
|
||||
armv4t,
|
||||
armeb,
|
||||
armebv8_3a,
|
||||
armebv8_2a,
|
||||
armebv8_1a,
|
||||
armebv8,
|
||||
armebv8r,
|
||||
armebv8m_baseline,
|
||||
armebv8m_mainline,
|
||||
armebv7,
|
||||
armebv7em,
|
||||
armebv7m,
|
||||
armebv7s,
|
||||
armebv7k,
|
||||
armebv7ve,
|
||||
armebv6,
|
||||
armebv6m,
|
||||
armebv6k,
|
||||
armebv6t2,
|
||||
armebv5,
|
||||
armebv5te,
|
||||
armebv4t,
|
||||
aarch64,
|
||||
aarch64_be,
|
||||
arc,
|
||||
avr,
|
||||
bpfel,
|
||||
bpfeb,
|
||||
@ -5315,6 +5512,7 @@ pub const Arch = enum {
|
||||
pub const Environ = enum {
|
||||
unknown,
|
||||
gnu,
|
||||
gnuabin32,
|
||||
gnuabi64,
|
||||
gnueabi,
|
||||
gnueabihf,
|
||||
@ -5332,6 +5530,7 @@ pub const Environ = enum {
|
||||
amdopencl,
|
||||
coreclr,
|
||||
opencl,
|
||||
simulator,
|
||||
};
|
||||
|
||||
pub const ObjectFormat = enum {
|
||||
@ -5358,10 +5557,23 @@ pub const AtomicOrder = enum {
|
||||
SeqCst,
|
||||
};
|
||||
|
||||
pub const AtomicRmwOp = enum {
|
||||
Xchg,
|
||||
Add,
|
||||
Sub,
|
||||
And,
|
||||
Nand,
|
||||
Or,
|
||||
Xor,
|
||||
Max,
|
||||
Min,
|
||||
};
|
||||
|
||||
pub const Mode = enum {
|
||||
Debug,
|
||||
ReleaseSafe,
|
||||
ReleaseFast,
|
||||
ReleaseSmall,
|
||||
};
|
||||
|
||||
pub const TypeId = enum {
|
||||
@ -5380,7 +5592,7 @@ pub const TypeId = enum {
|
||||
NullLiteral,
|
||||
Nullable,
|
||||
ErrorUnion,
|
||||
Error,
|
||||
ErrorSet,
|
||||
Enum,
|
||||
Union,
|
||||
Fn,
|
||||
@ -5389,6 +5601,176 @@ pub const TypeId = enum {
|
||||
BoundFn,
|
||||
ArgTuple,
|
||||
Opaque,
|
||||
Promise,
|
||||
};
|
||||
|
||||
pub const TypeInfo = union(TypeId) {
|
||||
Type: void,
|
||||
Void: void,
|
||||
Bool: void,
|
||||
NoReturn: void,
|
||||
Int: Int,
|
||||
Float: Float,
|
||||
Pointer: Pointer,
|
||||
Array: Array,
|
||||
Struct: Struct,
|
||||
FloatLiteral: void,
|
||||
IntLiteral: void,
|
||||
UndefinedLiteral: void,
|
||||
NullLiteral: void,
|
||||
Nullable: Nullable,
|
||||
ErrorUnion: ErrorUnion,
|
||||
ErrorSet: ErrorSet,
|
||||
Enum: Enum,
|
||||
Union: Union,
|
||||
Fn: Fn,
|
||||
Namespace: void,
|
||||
Block: void,
|
||||
BoundFn: Fn,
|
||||
ArgTuple: void,
|
||||
Opaque: void,
|
||||
Promise: Promise,
|
||||
|
||||
|
||||
pub const Int = struct {
|
||||
is_signed: bool,
|
||||
bits: u8,
|
||||
};
|
||||
|
||||
pub const Float = struct {
|
||||
bits: u8,
|
||||
};
|
||||
|
||||
pub const Pointer = struct {
|
||||
is_const: bool,
|
||||
is_volatile: bool,
|
||||
alignment: u32,
|
||||
child: type,
|
||||
};
|
||||
|
||||
pub const Array = struct {
|
||||
len: usize,
|
||||
child: type,
|
||||
};
|
||||
|
||||
pub const ContainerLayout = enum {
|
||||
Auto,
|
||||
Extern,
|
||||
Packed,
|
||||
};
|
||||
|
||||
pub const StructField = struct {
|
||||
name: []const u8,
|
||||
offset: ?usize,
|
||||
field_type: type,
|
||||
};
|
||||
|
||||
pub const Struct = struct {
|
||||
layout: ContainerLayout,
|
||||
fields: []StructField,
|
||||
defs: []Definition,
|
||||
};
|
||||
|
||||
pub const Nullable = struct {
|
||||
child: type,
|
||||
};
|
||||
|
||||
pub const ErrorUnion = struct {
|
||||
error_set: type,
|
||||
payload: type,
|
||||
};
|
||||
|
||||
pub const Error = struct {
|
||||
name: []const u8,
|
||||
value: usize,
|
||||
};
|
||||
|
||||
pub const ErrorSet = struct {
|
||||
errors: []Error,
|
||||
};
|
||||
|
||||
pub const EnumField = struct {
|
||||
name: []const u8,
|
||||
value: usize,
|
||||
};
|
||||
|
||||
pub const Enum = struct {
|
||||
layout: ContainerLayout,
|
||||
tag_type: type,
|
||||
fields: []EnumField,
|
||||
defs: []Definition,
|
||||
};
|
||||
|
||||
pub const UnionField = struct {
|
||||
name: []const u8,
|
||||
enum_field: ?EnumField,
|
||||
field_type: type,
|
||||
};
|
||||
|
||||
pub const Union = struct {
|
||||
layout: ContainerLayout,
|
||||
tag_type: type,
|
||||
fields: []UnionField,
|
||||
defs: []Definition,
|
||||
};
|
||||
|
||||
pub const CallingConvention = enum {
|
||||
Unspecified,
|
||||
C,
|
||||
Cold,
|
||||
Naked,
|
||||
Stdcall,
|
||||
Async,
|
||||
};
|
||||
|
||||
pub const FnArg = struct {
|
||||
is_generic: bool,
|
||||
is_noalias: bool,
|
||||
arg_type: type,
|
||||
};
|
||||
|
||||
pub const Fn = struct {
|
||||
calling_convention: CallingConvention,
|
||||
is_generic: bool,
|
||||
is_var_args: bool,
|
||||
return_type: type,
|
||||
async_allocator_type: type,
|
||||
args: []FnArg,
|
||||
};
|
||||
|
||||
pub const Promise = struct {
|
||||
child: type,
|
||||
};
|
||||
|
||||
pub const Definition = struct {
|
||||
name: []const u8,
|
||||
is_pub: bool,
|
||||
data: Data,
|
||||
|
||||
pub const Data = union(enum) {
|
||||
Type: type,
|
||||
Var: type,
|
||||
Fn: FnDef,
|
||||
|
||||
pub const FnDef = struct {
|
||||
fn_type: type,
|
||||
inline_type: Inline,
|
||||
calling_convention: CallingConvention,
|
||||
is_var_args: bool,
|
||||
is_extern: bool,
|
||||
is_export: bool,
|
||||
lib_name: ?[]const u8,
|
||||
return_type: type,
|
||||
arg_names: [][] const u8,
|
||||
|
||||
pub const Inline = enum {
|
||||
Auto,
|
||||
Always,
|
||||
Never,
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pub const FloatMode = enum {
|
||||
@ -5402,7 +5784,7 @@ pub const Endian = enum {
|
||||
};
|
||||
|
||||
pub const endian = Endian.Little;
|
||||
pub const is_test = false;
|
||||
pub const is_test = true;
|
||||
pub const os = Os.linux;
|
||||
pub const arch = Arch.x86_64;
|
||||
pub const environ = Environ.gnu;
|
||||
@ -5410,6 +5792,7 @@ pub const object_format = ObjectFormat.elf;
|
||||
pub const mode = Mode.Debug;
|
||||
pub const link_libc = false;
|
||||
pub const have_error_return_tracing = true;
|
||||
pub const __zig_test_fn_slice = {}; // overwritten later
|
||||
{#code_end#}
|
||||
{#see_also|Build Mode#}
|
||||
{#header_close#}
|
||||
@ -6068,7 +6451,7 @@ hljs.registerLanguage("zig", function(t) {
|
||||
a = t.IR + "\\s*\\(",
|
||||
c = {
|
||||
keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
|
||||
built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field",
|
||||
built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo",
|
||||
literal: "true false null undefined"
|
||||
},
|
||||
n = [e, t.CLCM, t.CBCM, s, r];
|
||||
|
@ -1293,6 +1293,7 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdMemberType,
|
||||
BuiltinFnIdMemberName,
|
||||
BuiltinFnIdField,
|
||||
BuiltinFnIdTypeInfo,
|
||||
BuiltinFnIdTypeof,
|
||||
BuiltinFnIdAddWithOverflow,
|
||||
BuiltinFnIdSubWithOverflow,
|
||||
@ -1506,6 +1507,7 @@ struct CodeGen {
|
||||
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names;
|
||||
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
|
||||
HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
|
||||
HashMap<const TypeTableEntry *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
|
||||
|
||||
|
||||
ZigList<ImportTableEntry *> import_queue;
|
||||
@ -2037,6 +2039,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdTagType,
|
||||
IrInstructionIdFieldParentPtr,
|
||||
IrInstructionIdOffsetOf,
|
||||
IrInstructionIdTypeInfo,
|
||||
IrInstructionIdTypeId,
|
||||
IrInstructionIdSetEvalBranchQuota,
|
||||
IrInstructionIdPtrTypeOf,
|
||||
@ -2858,6 +2861,12 @@ struct IrInstructionOffsetOf {
|
||||
IrInstruction *field_name;
|
||||
};
|
||||
|
||||
struct IrInstructionTypeInfo {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *type_value;
|
||||
};
|
||||
|
||||
struct IrInstructionTypeId {
|
||||
IrInstruction base;
|
||||
|
||||
|
187
src/codegen.cpp
187
src/codegen.cpp
@ -88,6 +88,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
|
||||
g->exported_symbol_names.init(8);
|
||||
g->external_prototypes.init(8);
|
||||
g->string_literals_table.init(16);
|
||||
g->type_info_cache.init(32);
|
||||
g->is_test_build = false;
|
||||
g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
|
||||
buf_resize(&g->global_asm, 0);
|
||||
@ -4502,6 +4503,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
case IrInstructionIdDeclRef:
|
||||
case IrInstructionIdSwitchVar:
|
||||
case IrInstructionIdOffsetOf:
|
||||
case IrInstructionIdTypeInfo:
|
||||
case IrInstructionIdTypeId:
|
||||
case IrInstructionIdSetEvalBranchQuota:
|
||||
case IrInstructionIdPtrTypeOf:
|
||||
@ -6125,6 +6127,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);
|
||||
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, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
|
||||
create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
|
||||
create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
|
||||
@ -6344,6 +6347,190 @@ static void define_builtin_compile_vars(CodeGen *g) {
|
||||
}
|
||||
buf_appendf(contents, "};\n\n");
|
||||
}
|
||||
{
|
||||
buf_appendf(contents,
|
||||
"pub const TypeInfo = union(TypeId) {\n"
|
||||
" Type: void,\n"
|
||||
" Void: void,\n"
|
||||
" Bool: void,\n"
|
||||
" NoReturn: void,\n"
|
||||
" Int: Int,\n"
|
||||
" Float: Float,\n"
|
||||
" Pointer: Pointer,\n"
|
||||
" Array: Array,\n"
|
||||
" Struct: Struct,\n"
|
||||
" FloatLiteral: void,\n"
|
||||
" IntLiteral: void,\n"
|
||||
" UndefinedLiteral: void,\n"
|
||||
" NullLiteral: void,\n"
|
||||
" Nullable: Nullable,\n"
|
||||
" ErrorUnion: ErrorUnion,\n"
|
||||
" ErrorSet: ErrorSet,\n"
|
||||
" Enum: Enum,\n"
|
||||
" Union: Union,\n"
|
||||
" Fn: Fn,\n"
|
||||
" Namespace: void,\n"
|
||||
" Block: void,\n"
|
||||
" BoundFn: Fn,\n"
|
||||
" ArgTuple: void,\n"
|
||||
" Opaque: void,\n"
|
||||
" Promise: Promise,\n"
|
||||
"\n\n"
|
||||
" pub const Int = struct {\n"
|
||||
" is_signed: bool,\n"
|
||||
" bits: u8,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Float = struct {\n"
|
||||
" bits: u8,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Pointer = struct {\n"
|
||||
" is_const: bool,\n"
|
||||
" is_volatile: bool,\n"
|
||||
" alignment: u32,\n"
|
||||
" child: type,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Array = struct {\n"
|
||||
" len: usize,\n"
|
||||
" child: type,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const ContainerLayout = enum {\n"
|
||||
" Auto,\n"
|
||||
" Extern,\n"
|
||||
" Packed,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const StructField = struct {\n"
|
||||
" name: []const u8,\n"
|
||||
" offset: ?usize,\n"
|
||||
" field_type: type,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Struct = struct {\n"
|
||||
" layout: ContainerLayout,\n"
|
||||
" fields: []StructField,\n"
|
||||
" defs: []Definition,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Nullable = struct {\n"
|
||||
" child: type,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const ErrorUnion = struct {\n"
|
||||
" error_set: type,\n"
|
||||
" payload: type,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Error = struct {\n"
|
||||
" name: []const u8,\n"
|
||||
" value: usize,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const ErrorSet = struct {\n"
|
||||
" errors: []Error,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const EnumField = struct {\n"
|
||||
" name: []const u8,\n"
|
||||
" value: usize,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Enum = struct {\n"
|
||||
" layout: ContainerLayout,\n"
|
||||
" tag_type: type,\n"
|
||||
" fields: []EnumField,\n"
|
||||
" defs: []Definition,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const UnionField = struct {\n"
|
||||
" name: []const u8,\n"
|
||||
" enum_field: ?EnumField,\n"
|
||||
" field_type: type,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Union = struct {\n"
|
||||
" layout: ContainerLayout,\n"
|
||||
" tag_type: type,\n"
|
||||
" fields: []UnionField,\n"
|
||||
" defs: []Definition,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const CallingConvention = enum {\n"
|
||||
" Unspecified,\n"
|
||||
" C,\n"
|
||||
" Cold,\n"
|
||||
" Naked,\n"
|
||||
" Stdcall,\n"
|
||||
" Async,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const FnArg = struct {\n"
|
||||
" is_generic: bool,\n"
|
||||
" is_noalias: bool,\n"
|
||||
" arg_type: type,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Fn = struct {\n"
|
||||
" calling_convention: CallingConvention,\n"
|
||||
" is_generic: bool,\n"
|
||||
" is_var_args: bool,\n"
|
||||
" return_type: type,\n"
|
||||
" async_allocator_type: type,\n"
|
||||
" args: []FnArg,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Promise = struct {\n"
|
||||
" child: type,\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
" pub const Definition = struct {\n"
|
||||
" name: []const u8,\n"
|
||||
" is_pub: bool,\n"
|
||||
" data: Data,\n"
|
||||
"\n"
|
||||
" pub const Data = union(enum) {\n"
|
||||
" Type: type,\n"
|
||||
" Var: type,\n"
|
||||
" Fn: FnDef,\n"
|
||||
"\n"
|
||||
" pub const FnDef = struct {\n"
|
||||
" fn_type: type,\n"
|
||||
" inline_type: Inline,\n"
|
||||
" calling_convention: CallingConvention,\n"
|
||||
" is_var_args: bool,\n"
|
||||
" is_extern: bool,\n"
|
||||
" is_export: bool,\n"
|
||||
" lib_name: ?[]const u8,\n"
|
||||
" return_type: type,\n"
|
||||
" arg_names: [][] const u8,\n"
|
||||
"\n"
|
||||
" pub const Inline = enum {\n"
|
||||
" Auto,\n"
|
||||
" Always,\n"
|
||||
" Never,\n"
|
||||
" };\n"
|
||||
" };\n"
|
||||
" };\n"
|
||||
" };\n"
|
||||
"};\n\n");
|
||||
assert(ContainerLayoutAuto == 0);
|
||||
assert(ContainerLayoutExtern == 1);
|
||||
assert(ContainerLayoutPacked == 2);
|
||||
|
||||
assert(CallingConventionUnspecified == 0);
|
||||
assert(CallingConventionC == 1);
|
||||
assert(CallingConventionCold == 2);
|
||||
assert(CallingConventionNaked == 3);
|
||||
assert(CallingConventionStdcall == 4);
|
||||
assert(CallingConventionAsync == 5);
|
||||
|
||||
assert(FnInlineAuto == 0);
|
||||
assert(FnInlineAlways == 1);
|
||||
assert(FnInlineNever == 2);
|
||||
}
|
||||
{
|
||||
buf_appendf(contents,
|
||||
"pub const FloatMode = enum {\n"
|
||||
|
962
src/ir.cpp
962
src/ir.cpp
File diff suppressed because it is too large
Load Diff
@ -966,6 +966,12 @@ static void ir_print_offset_of(IrPrint *irp, IrInstructionOffsetOf *instruction)
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_type_info(IrPrint *irp, IrInstructionTypeInfo *instruction) {
|
||||
fprintf(irp->f, "@typeInfo(");
|
||||
ir_print_other_instruction(irp, instruction->type_value);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) {
|
||||
fprintf(irp->f, "@typeId(");
|
||||
ir_print_other_instruction(irp, instruction->type_value);
|
||||
@ -1536,6 +1542,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdOffsetOf:
|
||||
ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction);
|
||||
break;
|
||||
case IrInstructionIdTypeInfo:
|
||||
ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction);
|
||||
break;
|
||||
case IrInstructionIdTypeId:
|
||||
ir_print_type_id(irp, (IrInstructionTypeId *)instruction);
|
||||
break;
|
||||
|
@ -36,6 +36,7 @@ comptime {
|
||||
_ = @import("cases/pub_enum/index.zig");
|
||||
_ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
|
||||
_ = @import("cases/reflection.zig");
|
||||
_ = @import("cases/type_info.zig");
|
||||
_ = @import("cases/sizeof_and_typeof.zig");
|
||||
_ = @import("cases/slice.zig");
|
||||
_ = @import("cases/struct.zig");
|
||||
|
181
test/cases/type_info.zig
Normal file
181
test/cases/type_info.zig
Normal file
@ -0,0 +1,181 @@
|
||||
const assert = @import("std").debug.assert;
|
||||
const mem = @import("std").mem;
|
||||
const TypeInfo = @import("builtin").TypeInfo;
|
||||
const TypeId = @import("builtin").TypeId;
|
||||
|
||||
test "type info: tag type, void info" {
|
||||
comptime {
|
||||
assert(@TagType(TypeInfo) == TypeId);
|
||||
const void_info = @typeInfo(void);
|
||||
assert(TypeId(void_info) == TypeId.Void);
|
||||
assert(void_info.Void == {});
|
||||
}
|
||||
}
|
||||
|
||||
test "type info: integer, floating point type info" {
|
||||
comptime {
|
||||
const u8_info = @typeInfo(u8);
|
||||
assert(TypeId(u8_info) == TypeId.Int);
|
||||
assert(!u8_info.Int.is_signed);
|
||||
assert(u8_info.Int.bits == 8);
|
||||
|
||||
const f64_info = @typeInfo(f64);
|
||||
assert(TypeId(f64_info) == TypeId.Float);
|
||||
assert(f64_info.Float.bits == 64);
|
||||
}
|
||||
}
|
||||
|
||||
test "type info: pointer, array and nullable type info" {
|
||||
comptime {
|
||||
const u32_ptr_info = @typeInfo(&u32);
|
||||
assert(TypeId(u32_ptr_info) == TypeId.Pointer);
|
||||
assert(u32_ptr_info.Pointer.is_const == false);
|
||||
assert(u32_ptr_info.Pointer.is_volatile == false);
|
||||
assert(u32_ptr_info.Pointer.alignment == 4);
|
||||
assert(u32_ptr_info.Pointer.child == u32);
|
||||
|
||||
const arr_info = @typeInfo([42]bool);
|
||||
assert(TypeId(arr_info) == TypeId.Array);
|
||||
assert(arr_info.Array.len == 42);
|
||||
assert(arr_info.Array.child == bool);
|
||||
|
||||
const null_info = @typeInfo(?void);
|
||||
assert(TypeId(null_info) == TypeId.Nullable);
|
||||
assert(null_info.Nullable.child == void);
|
||||
}
|
||||
}
|
||||
|
||||
test "type info: promise info" {
|
||||
comptime {
|
||||
const null_promise_info = @typeInfo(promise);
|
||||
assert(TypeId(null_promise_info) == TypeId.Promise);
|
||||
assert(null_promise_info.Promise.child == @typeOf(undefined));
|
||||
|
||||
const promise_info = @typeInfo(promise->usize);
|
||||
assert(TypeId(promise_info) == TypeId.Promise);
|
||||
assert(promise_info.Promise.child == usize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
test "type info: error set, error union info" {
|
||||
comptime {
|
||||
const TestErrorSet = error {
|
||||
First,
|
||||
Second,
|
||||
Third,
|
||||
};
|
||||
|
||||
const error_set_info = @typeInfo(TestErrorSet);
|
||||
assert(TypeId(error_set_info) == TypeId.ErrorSet);
|
||||
assert(error_set_info.ErrorSet.errors.len == 3);
|
||||
assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
|
||||
assert(error_set_info.ErrorSet.errors[2].value == usize(TestErrorSet.Third));
|
||||
|
||||
const error_union_info = @typeInfo(TestErrorSet!usize);
|
||||
assert(TypeId(error_union_info) == TypeId.ErrorUnion);
|
||||
assert(error_union_info.ErrorUnion.error_set == TestErrorSet);
|
||||
assert(error_union_info.ErrorUnion.payload == usize);
|
||||
}
|
||||
}
|
||||
|
||||
test "type info: enum info" {
|
||||
comptime {
|
||||
const Os = @import("builtin").Os;
|
||||
|
||||
const os_info = @typeInfo(Os);
|
||||
assert(TypeId(os_info) == TypeId.Enum);
|
||||
assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
|
||||
assert(os_info.Enum.fields.len == 32);
|
||||
assert(mem.eql(u8, os_info.Enum.fields[1].name, "ananas"));
|
||||
assert(os_info.Enum.fields[10].value == 10);
|
||||
assert(os_info.Enum.tag_type == u5);
|
||||
assert(os_info.Enum.defs.len == 0);
|
||||
}
|
||||
}
|
||||
|
||||
test "type info: union info" {
|
||||
comptime {
|
||||
const typeinfo_info = @typeInfo(TypeInfo);
|
||||
assert(TypeId(typeinfo_info) == TypeId.Union);
|
||||
assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
|
||||
assert(typeinfo_info.Union.tag_type == TypeId);
|
||||
assert(typeinfo_info.Union.fields.len == 25);
|
||||
assert(typeinfo_info.Union.fields[4].enum_field != null);
|
||||
assert((??typeinfo_info.Union.fields[4].enum_field).value == 4);
|
||||
assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
|
||||
assert(typeinfo_info.Union.defs.len == 20);
|
||||
|
||||
const TestNoTagUnion = union {
|
||||
Foo: void,
|
||||
Bar: u32,
|
||||
};
|
||||
|
||||
const notag_union_info = @typeInfo(TestNoTagUnion);
|
||||
assert(TypeId(notag_union_info) == TypeId.Union);
|
||||
assert(notag_union_info.Union.tag_type == @typeOf(undefined));
|
||||
assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
|
||||
assert(notag_union_info.Union.fields.len == 2);
|
||||
assert(notag_union_info.Union.fields[0].enum_field == null);
|
||||
assert(notag_union_info.Union.fields[1].field_type == u32);
|
||||
|
||||
const TestExternUnion = extern union {
|
||||
foo: &c_void,
|
||||
};
|
||||
|
||||
const extern_union_info = @typeInfo(TestExternUnion);
|
||||
assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
|
||||
assert(extern_union_info.Union.tag_type == @typeOf(undefined));
|
||||
assert(extern_union_info.Union.fields[0].enum_field == null);
|
||||
assert(extern_union_info.Union.fields[0].field_type == &c_void);
|
||||
}
|
||||
}
|
||||
|
||||
test "type info: struct info" {
|
||||
comptime {
|
||||
const struct_info = @typeInfo(TestStruct);
|
||||
assert(TypeId(struct_info) == TypeId.Struct);
|
||||
assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
|
||||
assert(struct_info.Struct.fields.len == 3);
|
||||
assert(struct_info.Struct.fields[1].offset == null);
|
||||
assert(struct_info.Struct.fields[2].field_type == &TestStruct);
|
||||
assert(struct_info.Struct.defs.len == 2);
|
||||
assert(struct_info.Struct.defs[0].is_pub);
|
||||
assert(!struct_info.Struct.defs[0].data.Fn.is_extern);
|
||||
assert(struct_info.Struct.defs[0].data.Fn.lib_name == null);
|
||||
assert(struct_info.Struct.defs[0].data.Fn.return_type == void);
|
||||
assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn(&const TestStruct)void);
|
||||
}
|
||||
}
|
||||
|
||||
const TestStruct = packed struct {
|
||||
const Self = this;
|
||||
|
||||
fieldA: usize,
|
||||
fieldB: void,
|
||||
fieldC: &Self,
|
||||
|
||||
pub fn foo(self: &const Self) void {}
|
||||
};
|
||||
|
||||
test "type info: function type info" {
|
||||
comptime {
|
||||
const fn_info = @typeInfo(@typeOf(foo));
|
||||
assert(TypeId(fn_info) == TypeId.Fn);
|
||||
assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);
|
||||
assert(fn_info.Fn.is_generic);
|
||||
assert(fn_info.Fn.args.len == 2);
|
||||
assert(fn_info.Fn.is_var_args);
|
||||
assert(fn_info.Fn.return_type == @typeOf(undefined));
|
||||
assert(fn_info.Fn.async_allocator_type == @typeOf(undefined));
|
||||
|
||||
const test_instance: TestStruct = undefined;
|
||||
const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
|
||||
assert(TypeId(bound_fn_info) == TypeId.BoundFn);
|
||||
assert(bound_fn_info.BoundFn.args[0].arg_type == &const TestStruct);
|
||||
}
|
||||
}
|
||||
|
||||
fn foo(comptime a: usize, b: bool, args: ...) usize {
|
||||
return 0;
|
||||
}
|
@ -45,6 +45,16 @@ test "basic unions" {
|
||||
assert(foo.float == 12.34);
|
||||
}
|
||||
|
||||
test "comptime union field access" {
|
||||
comptime {
|
||||
var foo = Foo { .int = 0 };
|
||||
assert(foo.int == 0);
|
||||
|
||||
foo = Foo { .float = 42.42 };
|
||||
assert(foo.float == 42.42);
|
||||
}
|
||||
}
|
||||
|
||||
test "init union with runtime value" {
|
||||
var foo: Foo = undefined;
|
||||
|
||||
|
@ -3210,6 +3210,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
|
||||
,
|
||||
".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset");
|
||||
|
||||
cases.add("invalid union field access in comptime",
|
||||
\\const Foo = union {
|
||||
\\ Bar: u8,
|
||||
\\ Baz: void,
|
||||
\\};
|
||||
\\comptime {
|
||||
\\ var foo = Foo {.Baz = {}};
|
||||
\\ const bar_val = foo.Bar;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set");
|
||||
|
||||
cases.add("getting return type of generic function",
|
||||
\\fn generic(a: var) void {}
|
||||
\\comptime {
|
||||
@ -3225,5 +3237,4 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic");
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user