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

implement @typeInfo for Frame and implement @Type for Frame, EnumLiteral, and ErrorSet
This commit is contained in:
Andrew Kelley 2020-06-18 21:25:03 -04:00 committed by GitHub
commit c70633eacd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 171 additions and 23 deletions

View File

@ -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.

View File

@ -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)) {

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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 }));
}

View File

@ -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,
}
}