authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-18 21:25:03-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-06-18 21:25:03-04:00
logc70633eacdf4e17cfafe0ab44f4ea83323b6d7a3
tree8154639afe68f601754de51366af3a6c817eb558
parentb9e3df92db1b5cb137d880a7612b6ee2e7e1f60e
parenta62e9bc8e50296e2d5b201614a78b0e658887aa9
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5203 from tadeokondrak/@type-for-even-more-types

implement @typeInfo for Frame and implement @Type for Frame, EnumLiteral, and ErrorSet

7 files changed, 171 insertions(+), 23 deletions(-)

lib/std/builtin.zig+17-10
...@@ -166,7 +166,7 @@ pub const TypeInfo = union(enum) {...@@ -166,7 +166,7 @@ pub const TypeInfo = union(enum) {
166 Fn: Fn,166 Fn: Fn,
167 BoundFn: Fn,167 BoundFn: Fn,
168 Opaque: void,168 Opaque: void,
169 Frame: void,169 Frame: Frame,
170 AnyFrame: AnyFrame,170 AnyFrame: AnyFrame,
171 Vector: Vector,171 Vector: Vector,
172 EnumLiteral: void,172 EnumLiteral: void,
...@@ -244,8 +244,8 @@ pub const TypeInfo = union(enum) {...@@ -244,8 +244,8 @@ pub const TypeInfo = union(enum) {
244 /// therefore must be kept in sync with the compiler implementation.244 /// therefore must be kept in sync with the compiler implementation.
245 pub const Struct = struct {245 pub const Struct = struct {
246 layout: ContainerLayout,246 layout: ContainerLayout,
247 fields: []StructField,247 fields: []const StructField,
248 decls: []Declaration,248 decls: []const Declaration,
249 };249 };
250250
251 /// This data structure is used by the Zig language code generation and251 /// This data structure is used by the Zig language code generation and
...@@ -265,12 +265,13 @@ pub const TypeInfo = union(enum) {...@@ -265,12 +265,13 @@ pub const TypeInfo = union(enum) {
265 /// therefore must be kept in sync with the compiler implementation.265 /// therefore must be kept in sync with the compiler implementation.
266 pub const Error = struct {266 pub const Error = struct {
267 name: []const u8,267 name: []const u8,
268 /// This field is ignored when using @Type().
268 value: comptime_int,269 value: comptime_int,
269 };270 };
270271
271 /// This data structure is used by the Zig language code generation and272 /// This data structure is used by the Zig language code generation and
272 /// therefore must be kept in sync with the compiler implementation.273 /// therefore must be kept in sync with the compiler implementation.
273 pub const ErrorSet = ?[]Error;274 pub const ErrorSet = ?[]const Error;
274275
275 /// This data structure is used by the Zig language code generation and276 /// This data structure is used by the Zig language code generation and
276 /// therefore must be kept in sync with the compiler implementation.277 /// therefore must be kept in sync with the compiler implementation.
...@@ -284,8 +285,8 @@ pub const TypeInfo = union(enum) {...@@ -284,8 +285,8 @@ pub const TypeInfo = union(enum) {
284 pub const Enum = struct {285 pub const Enum = struct {
285 layout: ContainerLayout,286 layout: ContainerLayout,
286 tag_type: type,287 tag_type: type,
287 fields: []EnumField,288 fields: []const EnumField,
288 decls: []Declaration,289 decls: []const Declaration,
289 is_exhaustive: bool,290 is_exhaustive: bool,
290 };291 };
291292
...@@ -302,8 +303,8 @@ pub const TypeInfo = union(enum) {...@@ -302,8 +303,8 @@ pub const TypeInfo = union(enum) {
302 pub const Union = struct {303 pub const Union = struct {
303 layout: ContainerLayout,304 layout: ContainerLayout,
304 tag_type: ?type,305 tag_type: ?type,
305 fields: []UnionField,306 fields: []const UnionField,
306 decls: []Declaration,307 decls: []const Declaration,
307 };308 };
308309
309 /// This data structure is used by the Zig language code generation and310 /// This data structure is used by the Zig language code generation and
...@@ -321,7 +322,13 @@ pub const TypeInfo = union(enum) {...@@ -321,7 +322,13 @@ pub const TypeInfo = union(enum) {
321 is_generic: bool,322 is_generic: bool,
322 is_var_args: bool,323 is_var_args: bool,
323 return_type: ?type,324 return_type: ?type,
324 args: []FnArg,325 args: []const FnArg,
326 };
327
328 /// This data structure is used by the Zig language code generation and
329 /// therefore must be kept in sync with the compiler implementation.
330 pub const Frame = struct {
331 function: var,
325 };332 };
326333
327 /// This data structure is used by the Zig language code generation and334 /// This data structure is used by the Zig language code generation and
...@@ -361,7 +368,7 @@ pub const TypeInfo = union(enum) {...@@ -361,7 +368,7 @@ pub const TypeInfo = union(enum) {
361 is_export: bool,368 is_export: bool,
362 lib_name: ?[]const u8,369 lib_name: ?[]const u8,
363 return_type: type,370 return_type: type,
364 arg_names: [][]const u8,371 arg_names: []const []const u8,
365372
366 /// This data structure is used by the Zig language code generation and373 /// This data structure is used by the Zig language code generation and
367 /// therefore must be kept in sync with the compiler implementation.374 /// therefore must be kept in sync with the compiler implementation.
lib/std/meta.zig+6-6
...@@ -250,7 +250,7 @@ test "std.meta.containerLayout" {...@@ -250,7 +250,7 @@ test "std.meta.containerLayout" {
250 testing.expect(containerLayout(U3) == .Extern);250 testing.expect(containerLayout(U3) == .Extern);
251}251}
252252
253pub fn declarations(comptime T: type) []TypeInfo.Declaration {253pub fn declarations(comptime T: type) []const TypeInfo.Declaration {
254 return switch (@typeInfo(T)) {254 return switch (@typeInfo(T)) {
255 .Struct => |info| info.decls,255 .Struct => |info| info.decls,
256 .Enum => |info| info.decls,256 .Enum => |info| info.decls,
...@@ -274,7 +274,7 @@ test "std.meta.declarations" {...@@ -274,7 +274,7 @@ test "std.meta.declarations" {
274 fn a() void {}274 fn a() void {}
275 };275 };
276276
277 const decls = comptime [_][]TypeInfo.Declaration{277 const decls = comptime [_][]const TypeInfo.Declaration{
278 declarations(E1),278 declarations(E1),
279 declarations(S1),279 declarations(S1),
280 declarations(U1),280 declarations(U1),
...@@ -323,10 +323,10 @@ test "std.meta.declarationInfo" {...@@ -323,10 +323,10 @@ test "std.meta.declarationInfo" {
323}323}
324324
325pub fn fields(comptime T: type) switch (@typeInfo(T)) {325pub fn fields(comptime T: type) switch (@typeInfo(T)) {
326 .Struct => []TypeInfo.StructField,326 .Struct => []const TypeInfo.StructField,
327 .Union => []TypeInfo.UnionField,327 .Union => []const TypeInfo.UnionField,
328 .ErrorSet => []TypeInfo.Error,328 .ErrorSet => []const TypeInfo.Error,
329 .Enum => []TypeInfo.EnumField,329 .Enum => []const TypeInfo.EnumField,
330 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),330 else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
331} {331} {
332 return switch (@typeInfo(T)) {332 return switch (@typeInfo(T)) {
src/analyze.cpp+13
...@@ -6012,6 +6012,19 @@ ZigValue *create_const_null(CodeGen *g, ZigType *type) {...@@ -6012,6 +6012,19 @@ ZigValue *create_const_null(CodeGen *g, ZigType *type) {
6012 return const_val;6012 return const_val;
6013}6013}
60146014
6015void init_const_fn(ZigValue *const_val, ZigFn *fn) {
6016 const_val->special = ConstValSpecialStatic;
6017 const_val->type = fn->type_entry;
6018 const_val->data.x_ptr.special = ConstPtrSpecialFunction;
6019 const_val->data.x_ptr.data.fn.fn_entry = fn;
6020}
6021
6022ZigValue *create_const_fn(CodeGen *g, ZigFn *fn) {
6023 ZigValue *const_val = g->pass1_arena->create<ZigValue>();
6024 init_const_fn(const_val, fn);
6025 return const_val;
6026}
6027
6015void init_const_float(ZigValue *const_val, ZigType *type, double value) {6028void init_const_float(ZigValue *const_val, ZigType *type, double value) {
6016 const_val->special = ConstValSpecialStatic;6029 const_val->special = ConstValSpecialStatic;
6017 const_val->type = type;6030 const_val->type = type;
src/analyze.hpp+3
...@@ -180,6 +180,9 @@ ZigValue *create_const_slice(CodeGen *g, ZigValue *array_val, size_t start, size...@@ -180,6 +180,9 @@ ZigValue *create_const_slice(CodeGen *g, ZigValue *array_val, size_t start, size
180void init_const_null(ZigValue *const_val, ZigType *type);180void init_const_null(ZigValue *const_val, ZigType *type);
181ZigValue *create_const_null(CodeGen *g, ZigType *type);181ZigValue *create_const_null(CodeGen *g, ZigType *type);
182182
183void init_const_fn(ZigValue *const_val, ZigFn *fn);
184ZigValue *create_const_fn(CodeGen *g, ZigFn *fn);
185
183ZigValue **alloc_const_vals_ptrs(CodeGen *g, size_t count);186ZigValue **alloc_const_vals_ptrs(CodeGen *g, size_t count);
184ZigValue **realloc_const_vals_ptrs(CodeGen *g, ZigValue **ptr, size_t old_count, size_t new_count);187ZigValue **realloc_const_vals_ptrs(CodeGen *g, ZigValue **ptr, size_t old_count, size_t new_count);
185188
src/ir.cpp+95-6
...@@ -25610,9 +25610,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy...@@ -25610,9 +25610,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
25610 break;25610 break;
25611 }25611 }
25612 case ZigTypeIdFnFrame:25612 case ZigTypeIdFnFrame:
25613 ir_add_error(ira, source_instr,25613 {
25614 buf_sprintf("compiler bug: TODO @typeInfo for async function frames. https://github.com/ziglang/zig/issues/3066"));25614 result = ira->codegen->pass1_arena->create<ZigValue>();
25615 return ErrorSemanticAnalyzeFail;25615 result->special = ConstValSpecialStatic;
25616 result->type = ir_type_info_get_type(ira, "Frame", nullptr);
25617 ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 1);
25618 result->data.x_struct.fields = fields;
25619 ZigFn *fn = type_entry->data.frame.fn;
25620 // function: var
25621 ensure_field_index(result->type, "function", 0);
25622 fields[0] = create_const_fn(ira->codegen, fn);
25623 break;
25624 }
25616 }25625 }
2561725626
25618 assert(result != nullptr);25627 assert(result != nullptr);
...@@ -25881,10 +25890,90 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI...@@ -25881,10 +25890,90 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
25881 ZigType *child_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "child", 0);25890 ZigType *child_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "child", 0);
25882 return get_any_frame_type(ira->codegen, child_type);25891 return get_any_frame_type(ira->codegen, child_type);
25883 }25892 }
25884 case ZigTypeIdErrorSet:
25885 case ZigTypeIdEnum:
25886 case ZigTypeIdFnFrame:
25887 case ZigTypeIdEnumLiteral:25893 case ZigTypeIdEnumLiteral:
25894 return ira->codegen->builtin_types.entry_enum_literal;
25895 case ZigTypeIdFnFrame: {
25896 assert(payload->special == ConstValSpecialStatic);
25897 assert(payload->type == ir_type_info_get_type(ira, "Frame", nullptr));
25898 ZigValue *function = get_const_field(ira, source_instr->source_node, payload, "function", 0);
25899 assert(function->type->id == ZigTypeIdFn);
25900 ZigFn *fn = function->data.x_ptr.data.fn.fn_entry;
25901 return get_fn_frame_type(ira->codegen, fn);
25902 }
25903 case ZigTypeIdErrorSet: {
25904 assert(payload->special == ConstValSpecialStatic);
25905 assert(payload->type->id == ZigTypeIdOptional);
25906 ZigValue *slice = payload->data.x_optional;
25907 if (slice == nullptr)
25908 return ira->codegen->builtin_types.entry_global_error_set;
25909 assert(slice->special == ConstValSpecialStatic);
25910 assert(is_slice(slice->type));
25911 ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
25912 Buf bare_name = BUF_INIT;
25913 buf_init_from_buf(&err_set_type->name, get_anon_type_name(ira->codegen, ira->old_irb.exec, "error", source_instr->scope, source_instr->source_node, &bare_name));
25914 err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits;
25915 err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align;
25916 err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size;
25917 ZigValue *ptr = slice->data.x_struct.fields[slice_ptr_index];
25918 assert(ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);;
25919 assert(ptr->data.x_ptr.data.base_array.elem_index == 0);
25920 ZigValue *arr = ptr->data.x_ptr.data.base_array.array_val;
25921 assert(arr->special == ConstValSpecialStatic);
25922 assert(arr->data.x_array.special == ConstArraySpecialNone);
25923 ZigValue *len = slice->data.x_struct.fields[slice_len_index];
25924 size_t count = bigint_as_usize(&len->data.x_bigint);
25925 err_set_type->data.error_set.err_count = count;
25926 err_set_type->data.error_set.errors = heap::c_allocator.allocate<ErrorTableEntry *>(count);
25927 bool *already_set = heap::c_allocator.allocate<bool>(ira->codegen->errors_by_index.length + count);
25928 for (size_t i = 0; i < count; i++) {
25929 ZigValue *error = &arr->data.x_array.data.s_none.elements[i];
25930 assert(error->type == ir_type_info_get_type(ira, "Error", nullptr));
25931 ErrorTableEntry *err_entry = heap::c_allocator.create<ErrorTableEntry>();
25932 err_entry->decl_node = source_instr->source_node;
25933 ZigValue *name_slice = get_const_field(ira, source_instr->source_node, error, "name", 0);
25934 ZigValue *name_ptr = name_slice->data.x_struct.fields[slice_ptr_index];
25935 ZigValue *name_len = name_slice->data.x_struct.fields[slice_len_index];
25936 assert(name_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
25937 assert(name_ptr->data.x_ptr.data.base_array.elem_index == 0);
25938 ZigValue *name_arr = name_ptr->data.x_ptr.data.base_array.array_val;
25939 assert(name_arr->special == ConstValSpecialStatic);
25940 switch (name_arr->data.x_array.special) {
25941 case ConstArraySpecialUndef:
25942 return ira->codegen->invalid_inst_gen->value->type;
25943 case ConstArraySpecialNone: {
25944 buf_resize(&err_entry->name, 0);
25945 size_t name_count = bigint_as_usize(&name_len->data.x_bigint);
25946 for (size_t j = 0; j < name_count; j++) {
25947 ZigValue *ch_val = &name_arr->data.x_array.data.s_none.elements[j];
25948 unsigned ch = bigint_as_u32(&ch_val->data.x_bigint);
25949 buf_append_char(&err_entry->name, ch);
25950 }
25951 break;
25952 }
25953 case ConstArraySpecialBuf:
25954 buf_init_from_buf(&err_entry->name, name_arr->data.x_array.data.s_buf);
25955 break;
25956 }
25957 auto existing_entry = ira->codegen->error_table.put_unique(&err_entry->name, err_entry);
25958 if (existing_entry) {
25959 err_entry->value = existing_entry->value->value;
25960 } else {
25961 size_t error_value_count = ira->codegen->errors_by_index.length;
25962 assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count));
25963 err_entry->value = error_value_count;
25964 ira->codegen->errors_by_index.append(err_entry);
25965 }
25966 if (already_set[err_entry->value]) {
25967 ir_add_error(ira, source_instr, buf_sprintf("duplicate error: %s", buf_ptr(&err_entry->name)));
25968 return ira->codegen->invalid_inst_gen->value->type;
25969 } else {
25970 already_set[err_entry->value] = true;
25971 }
25972 err_set_type->data.error_set.errors[i] = err_entry;
25973 }
25974 return err_set_type;
25975 }
25976 case ZigTypeIdEnum:
25888 ir_add_error(ira, source_instr, buf_sprintf(25977 ir_add_error(ira, source_instr, buf_sprintf(
25889 "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));25978 "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));
25890 return ira->codegen->invalid_inst_gen->value->type;25979 return ira->codegen->invalid_inst_gen->value->type;
test/stage1/behavior/type.zig+23
...@@ -213,3 +213,26 @@ test "Type.AnyFrame" {...@@ -213,3 +213,26 @@ test "Type.AnyFrame" {
213 anyframe->anyframe->u8,213 anyframe->anyframe->u8,
214 });214 });
215}215}
216
217test "Type.EnumLiteral" {
218 testTypes(&[_]type{
219 @TypeOf(.Dummy),
220 });
221}
222
223fn add(a: i32, b: i32) i32 {
224 return a + b;
225}
226
227test "Type.Frame" {
228 testTypes(&[_]type{
229 @Frame(add),
230 });
231}
232
233test "Type.ErrorSet" {
234 // error sets don't compare equal so just check if they compile
235 _ = @Type(@typeInfo(error{}));
236 _ = @Type(@typeInfo(error{A}));
237 _ = @Type(@typeInfo(error{ A, B, C }));
238}
test/stage1/behavior/type_info.zig+14-1
...@@ -202,7 +202,7 @@ fn testUnion() void {...@@ -202,7 +202,7 @@ fn testUnion() void {
202 expect(typeinfo_info.Union.fields[4].enum_field != null);202 expect(typeinfo_info.Union.fields[4].enum_field != null);
203 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);203 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
204 expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));204 expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
205 expect(typeinfo_info.Union.decls.len == 20);205 expect(typeinfo_info.Union.decls.len == 21);
206206
207 const TestNoTagUnion = union {207 const TestNoTagUnion = union {
208 Foo: void,208 Foo: void,
...@@ -389,3 +389,16 @@ test "defaut value for a var-typed field" {...@@ -389,3 +389,16 @@ test "defaut value for a var-typed field" {
389 const S = struct { x: var };389 const S = struct { x: var };
390 expect(@typeInfo(S).Struct.fields[0].default_value == null);390 expect(@typeInfo(S).Struct.fields[0].default_value == null);
391}391}
392
393fn add(a: i32, b: i32) i32 {
394 return a + b;
395}
396
397test "type info for async frames" {
398 switch (@typeInfo(@Frame(add))) {
399 .Frame => |frame| {
400 expect(frame.function == add);
401 },
402 else => unreachable,
403 }
404}