commit c70633eacdf4e17cfafe0ab44f4ea83323b6d7a3 (tree)
parent b9e3df92db1b5cb137d880a7612b6ee2e7e1f60e
Author: Andrew Kelley <andrew@ziglang.org>
Date: Thu, 18 Jun 2020 21:25:03 -0400
Merge pull request #5203 from tadeokondrak/@type-for-even-more-types
implement @typeInfo for Frame and implement @Type for Frame, EnumLiteral, and ErrorSet
Diffstat:
7 files changed, 171 insertions(+), 23 deletions(-)
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
@@ -166,7 +166,7 @@ pub const TypeInfo = union(enum) {
Fn: Fn,
BoundFn: Fn,
Opaque: void,
- Frame: void,
+ Frame: Frame,
AnyFrame: AnyFrame,
Vector: Vector,
EnumLiteral: void,
@@ -244,8 +244,8 @@ pub const TypeInfo = union(enum) {
/// therefore must be kept in sync with the compiler implementation.
pub const Struct = struct {
layout: ContainerLayout,
- fields: []StructField,
- decls: []Declaration,
+ fields: []const StructField,
+ decls: []const Declaration,
};
/// This data structure is used by the Zig language code generation and
@@ -265,12 +265,13 @@ pub const TypeInfo = union(enum) {
/// therefore must be kept in sync with the compiler implementation.
pub const Error = struct {
name: []const u8,
+ /// This field is ignored when using @Type().
value: comptime_int,
};
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
- pub const ErrorSet = ?[]Error;
+ pub const ErrorSet = ?[]const Error;
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
@@ -284,8 +285,8 @@ pub const TypeInfo = union(enum) {
pub const Enum = struct {
layout: ContainerLayout,
tag_type: type,
- fields: []EnumField,
- decls: []Declaration,
+ fields: []const EnumField,
+ decls: []const Declaration,
is_exhaustive: bool,
};
@@ -302,8 +303,8 @@ pub const TypeInfo = union(enum) {
pub const Union = struct {
layout: ContainerLayout,
tag_type: ?type,
- fields: []UnionField,
- decls: []Declaration,
+ fields: []const UnionField,
+ decls: []const Declaration,
};
/// This data structure is used by the Zig language code generation and
@@ -321,7 +322,13 @@ pub const TypeInfo = union(enum) {
is_generic: bool,
is_var_args: bool,
return_type: ?type,
- args: []FnArg,
+ args: []const FnArg,
+ };
+
+ /// This data structure is used by the Zig language code generation and
+ /// therefore must be kept in sync with the compiler implementation.
+ pub const Frame = struct {
+ function: var,
};
/// This data structure is used by the Zig language code generation and
@@ -361,7 +368,7 @@ pub const TypeInfo = union(enum) {
is_export: bool,
lib_name: ?[]const u8,
return_type: type,
- arg_names: [][]const u8,
+ arg_names: []const []const u8,
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
diff --git a/lib/std/meta.zig b/lib/std/meta.zig
@@ -250,7 +250,7 @@ test "std.meta.containerLayout" {
testing.expect(containerLayout(U3) == .Extern);
}
-pub fn declarations(comptime T: type) []TypeInfo.Declaration {
+pub fn declarations(comptime T: type) []const TypeInfo.Declaration {
return switch (@typeInfo(T)) {
.Struct => |info| info.decls,
.Enum => |info| info.decls,
@@ -274,7 +274,7 @@ test "std.meta.declarations" {
fn a() void {}
};
- const decls = comptime [_][]TypeInfo.Declaration{
+ const decls = comptime [_][]const TypeInfo.Declaration{
declarations(E1),
declarations(S1),
declarations(U1),
@@ -323,10 +323,10 @@ test "std.meta.declarationInfo" {
}
pub fn fields(comptime T: type) switch (@typeInfo(T)) {
- .Struct => []TypeInfo.StructField,
- .Union => []TypeInfo.UnionField,
- .ErrorSet => []TypeInfo.Error,
- .Enum => []TypeInfo.EnumField,
+ .Struct => []const TypeInfo.StructField,
+ .Union => []const TypeInfo.UnionField,
+ .ErrorSet => []const TypeInfo.Error,
+ .Enum => []const TypeInfo.EnumField,
else => @compileError("Expected struct, union, error set or enum type, found '" ++ @typeName(T) ++ "'"),
} {
return switch (@typeInfo(T)) {
diff --git a/src/analyze.cpp b/src/analyze.cpp
@@ -6012,6 +6012,19 @@ ZigValue *create_const_null(CodeGen *g, ZigType *type) {
return const_val;
}
+void init_const_fn(ZigValue *const_val, ZigFn *fn) {
+ const_val->special = ConstValSpecialStatic;
+ const_val->type = fn->type_entry;
+ const_val->data.x_ptr.special = ConstPtrSpecialFunction;
+ const_val->data.x_ptr.data.fn.fn_entry = fn;
+}
+
+ZigValue *create_const_fn(CodeGen *g, ZigFn *fn) {
+ ZigValue *const_val = g->pass1_arena->create<ZigValue>();
+ init_const_fn(const_val, fn);
+ return const_val;
+}
+
void init_const_float(ZigValue *const_val, ZigType *type, double value) {
const_val->special = ConstValSpecialStatic;
const_val->type = type;
diff --git a/src/analyze.hpp b/src/analyze.hpp
@@ -180,6 +180,9 @@ ZigValue *create_const_slice(CodeGen *g, ZigValue *array_val, size_t start, size
void init_const_null(ZigValue *const_val, ZigType *type);
ZigValue *create_const_null(CodeGen *g, ZigType *type);
+void init_const_fn(ZigValue *const_val, ZigFn *fn);
+ZigValue *create_const_fn(CodeGen *g, ZigFn *fn);
+
ZigValue **alloc_const_vals_ptrs(CodeGen *g, size_t count);
ZigValue **realloc_const_vals_ptrs(CodeGen *g, ZigValue **ptr, size_t old_count, size_t new_count);
diff --git a/src/ir.cpp b/src/ir.cpp
@@ -25610,9 +25610,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
break;
}
case ZigTypeIdFnFrame:
- ir_add_error(ira, source_instr,
- buf_sprintf("compiler bug: TODO @typeInfo for async function frames. https://github.com/ziglang/zig/issues/3066"));
- return ErrorSemanticAnalyzeFail;
+ {
+ result = ira->codegen->pass1_arena->create<ZigValue>();
+ result->special = ConstValSpecialStatic;
+ result->type = ir_type_info_get_type(ira, "Frame", nullptr);
+ ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 1);
+ result->data.x_struct.fields = fields;
+ ZigFn *fn = type_entry->data.frame.fn;
+ // function: var
+ ensure_field_index(result->type, "function", 0);
+ fields[0] = create_const_fn(ira->codegen, fn);
+ break;
+ }
}
assert(result != nullptr);
@@ -25881,10 +25890,90 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
ZigType *child_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "child", 0);
return get_any_frame_type(ira->codegen, child_type);
}
- case ZigTypeIdErrorSet:
- case ZigTypeIdEnum:
- case ZigTypeIdFnFrame:
case ZigTypeIdEnumLiteral:
+ return ira->codegen->builtin_types.entry_enum_literal;
+ case ZigTypeIdFnFrame: {
+ assert(payload->special == ConstValSpecialStatic);
+ assert(payload->type == ir_type_info_get_type(ira, "Frame", nullptr));
+ ZigValue *function = get_const_field(ira, source_instr->source_node, payload, "function", 0);
+ assert(function->type->id == ZigTypeIdFn);
+ ZigFn *fn = function->data.x_ptr.data.fn.fn_entry;
+ return get_fn_frame_type(ira->codegen, fn);
+ }
+ case ZigTypeIdErrorSet: {
+ assert(payload->special == ConstValSpecialStatic);
+ assert(payload->type->id == ZigTypeIdOptional);
+ ZigValue *slice = payload->data.x_optional;
+ if (slice == nullptr)
+ return ira->codegen->builtin_types.entry_global_error_set;
+ assert(slice->special == ConstValSpecialStatic);
+ assert(is_slice(slice->type));
+ ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
+ Buf bare_name = BUF_INIT;
+ 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));
+ err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits;
+ err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align;
+ err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size;
+ ZigValue *ptr = slice->data.x_struct.fields[slice_ptr_index];
+ assert(ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);;
+ assert(ptr->data.x_ptr.data.base_array.elem_index == 0);
+ ZigValue *arr = ptr->data.x_ptr.data.base_array.array_val;
+ assert(arr->special == ConstValSpecialStatic);
+ assert(arr->data.x_array.special == ConstArraySpecialNone);
+ ZigValue *len = slice->data.x_struct.fields[slice_len_index];
+ size_t count = bigint_as_usize(&len->data.x_bigint);
+ err_set_type->data.error_set.err_count = count;
+ err_set_type->data.error_set.errors = heap::c_allocator.allocate<ErrorTableEntry *>(count);
+ bool *already_set = heap::c_allocator.allocate<bool>(ira->codegen->errors_by_index.length + count);
+ for (size_t i = 0; i < count; i++) {
+ ZigValue *error = &arr->data.x_array.data.s_none.elements[i];
+ assert(error->type == ir_type_info_get_type(ira, "Error", nullptr));
+ ErrorTableEntry *err_entry = heap::c_allocator.create<ErrorTableEntry>();
+ err_entry->decl_node = source_instr->source_node;
+ ZigValue *name_slice = get_const_field(ira, source_instr->source_node, error, "name", 0);
+ ZigValue *name_ptr = name_slice->data.x_struct.fields[slice_ptr_index];
+ ZigValue *name_len = name_slice->data.x_struct.fields[slice_len_index];
+ assert(name_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
+ assert(name_ptr->data.x_ptr.data.base_array.elem_index == 0);
+ ZigValue *name_arr = name_ptr->data.x_ptr.data.base_array.array_val;
+ assert(name_arr->special == ConstValSpecialStatic);
+ switch (name_arr->data.x_array.special) {
+ case ConstArraySpecialUndef:
+ return ira->codegen->invalid_inst_gen->value->type;
+ case ConstArraySpecialNone: {
+ buf_resize(&err_entry->name, 0);
+ size_t name_count = bigint_as_usize(&name_len->data.x_bigint);
+ for (size_t j = 0; j < name_count; j++) {
+ ZigValue *ch_val = &name_arr->data.x_array.data.s_none.elements[j];
+ unsigned ch = bigint_as_u32(&ch_val->data.x_bigint);
+ buf_append_char(&err_entry->name, ch);
+ }
+ break;
+ }
+ case ConstArraySpecialBuf:
+ buf_init_from_buf(&err_entry->name, name_arr->data.x_array.data.s_buf);
+ break;
+ }
+ auto existing_entry = ira->codegen->error_table.put_unique(&err_entry->name, err_entry);
+ if (existing_entry) {
+ err_entry->value = existing_entry->value->value;
+ } else {
+ size_t error_value_count = ira->codegen->errors_by_index.length;
+ assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count));
+ err_entry->value = error_value_count;
+ ira->codegen->errors_by_index.append(err_entry);
+ }
+ if (already_set[err_entry->value]) {
+ ir_add_error(ira, source_instr, buf_sprintf("duplicate error: %s", buf_ptr(&err_entry->name)));
+ return ira->codegen->invalid_inst_gen->value->type;
+ } else {
+ already_set[err_entry->value] = true;
+ }
+ err_set_type->data.error_set.errors[i] = err_entry;
+ }
+ return err_set_type;
+ }
+ case ZigTypeIdEnum:
ir_add_error(ira, source_instr, buf_sprintf(
"TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));
return ira->codegen->invalid_inst_gen->value->type;
diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig
@@ -213,3 +213,26 @@ test "Type.AnyFrame" {
anyframe->anyframe->u8,
});
}
+
+test "Type.EnumLiteral" {
+ testTypes(&[_]type{
+ @TypeOf(.Dummy),
+ });
+}
+
+fn add(a: i32, b: i32) i32 {
+ return a + b;
+}
+
+test "Type.Frame" {
+ testTypes(&[_]type{
+ @Frame(add),
+ });
+}
+
+test "Type.ErrorSet" {
+ // error sets don't compare equal so just check if they compile
+ _ = @Type(@typeInfo(error{}));
+ _ = @Type(@typeInfo(error{A}));
+ _ = @Type(@typeInfo(error{ A, B, C }));
+}
diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig
@@ -202,7 +202,7 @@ fn testUnion() void {
expect(typeinfo_info.Union.fields[4].enum_field != null);
expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
- expect(typeinfo_info.Union.decls.len == 20);
+ expect(typeinfo_info.Union.decls.len == 21);
const TestNoTagUnion = union {
Foo: void,
@@ -389,3 +389,16 @@ test "defaut value for a var-typed field" {
const S = struct { x: var };
expect(@typeInfo(S).Struct.fields[0].default_value == null);
}
+
+fn add(a: i32, b: i32) i32 {
+ return a + b;
+}
+
+test "type info for async frames" {
+ switch (@typeInfo(@Frame(add))) {
+ .Frame => |frame| {
+ expect(frame.function == add);
+ },
+ else => unreachable,
+ }
+}