Merge pull request #10753 from ziglang/nerf-type-info

stage1: remove the `data` field from `TypeInfo.Declaration`
This commit is contained in:
Andrew Kelley
2022-02-01 13:16:00 -05:00
committed by GitHub
13 changed files with 113 additions and 268 deletions

View File

@@ -171,6 +171,7 @@ pub const TypeId = std.meta.Tag(TypeInfo);
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
/// TODO: rename to `Type` because "info" is redundant.
pub const TypeInfo = union(enum) {
Type: void,
Void: void,
@@ -338,6 +339,7 @@ pub const TypeInfo = union(enum) {
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
/// TODO rename to Param and put inside `Fn`.
pub const FnArg = struct {
is_generic: bool,
is_noalias: bool,
@@ -385,28 +387,6 @@ pub const TypeInfo = union(enum) {
pub const Declaration = struct {
name: []const u8,
is_pub: bool,
data: Data,
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const Data = union(enum) {
Type: type,
Var: type,
Fn: FnDecl,
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const FnDecl = struct {
fn_type: type,
is_noinline: bool,
is_var_args: bool,
is_extern: bool,
is_export: bool,
lib_name: ?[]const u8,
return_type: type,
arg_names: []const []const u8,
};
};
};
};

View File

@@ -164,31 +164,93 @@ const std = @import("std.zig");
pub const errors = @import("crypto/errors.zig");
test "crypto" {
test {
const please_windows_dont_oom = @import("builtin").os.tag == .windows;
if (please_windows_dont_oom) return error.SkipZigTest;
inline for (std.meta.declarations(@This())) |decl| {
switch (decl.data) {
.Type => |t| {
if (@typeInfo(t) != .ErrorSet) {
std.testing.refAllDecls(t);
}
},
.Var => |v| {
_ = v;
},
.Fn => |f| {
_ = f;
},
}
}
_ = aead.aegis.Aegis128L;
_ = aead.aegis.Aegis256;
_ = @import("crypto/aegis.zig");
_ = @import("crypto/aes_gcm.zig");
_ = @import("crypto/aes_ocb.zig");
_ = @import("crypto/blake2.zig");
_ = @import("crypto/chacha20.zig");
_ = aead.aes_gcm.Aes128Gcm;
_ = aead.aes_gcm.Aes256Gcm;
_ = aead.aes_ocb.Aes128Ocb;
_ = aead.aes_ocb.Aes256Ocb;
_ = aead.Gimli;
_ = aead.chacha_poly.ChaCha20Poly1305;
_ = aead.chacha_poly.ChaCha12Poly1305;
_ = aead.chacha_poly.ChaCha8Poly1305;
_ = aead.chacha_poly.XChaCha20Poly1305;
_ = aead.chacha_poly.XChaCha12Poly1305;
_ = aead.chacha_poly.XChaCha8Poly1305;
_ = aead.isap;
_ = aead.salsa_poly.XSalsa20Poly1305;
_ = auth.hmac;
_ = auth.siphash;
_ = core.aes;
_ = core.Gimli;
_ = core.modes;
_ = dh.X25519;
_ = ecc.Curve25519;
_ = ecc.Edwards25519;
_ = ecc.P256;
_ = ecc.Ristretto255;
_ = hash.blake2;
_ = hash.Blake3;
_ = hash.Gimli;
_ = hash.Md5;
_ = hash.Sha1;
_ = hash.sha2;
_ = hash.sha3;
_ = kdf.hkdf;
_ = onetimeauth.Ghash;
_ = onetimeauth.Poly1305;
_ = pwhash.Encoding;
_ = pwhash.Error;
_ = pwhash.HasherError;
_ = pwhash.KdfError;
_ = pwhash.argon2;
_ = pwhash.bcrypt;
_ = pwhash.scrypt;
_ = pwhash.pbkdf2;
_ = pwhash.phc_format;
_ = sign.Ed25519;
_ = stream.chacha.ChaCha20IETF;
_ = stream.chacha.ChaCha12IETF;
_ = stream.chacha.ChaCha8IETF;
_ = stream.chacha.ChaCha20With64BitNonce;
_ = stream.chacha.ChaCha12With64BitNonce;
_ = stream.chacha.ChaCha8With64BitNonce;
_ = stream.chacha.XChaCha20IETF;
_ = stream.chacha.XChaCha12IETF;
_ = stream.chacha.XChaCha8IETF;
_ = stream.salsa.Salsa20;
_ = stream.salsa.XSalsa20;
_ = nacl.Box;
_ = nacl.SecretBox;
_ = nacl.SealedBox;
_ = utils;
_ = random;
_ = errors;
}
test "CSPRNG" {

View File

@@ -361,6 +361,8 @@ test "std.meta.containerLayout" {
try testing.expect(containerLayout(U3) == .Extern);
}
/// Instead of this function, prefer to use e.g. `@TypeInfo(foo).Struct.decls`
/// directly when you know what kind of type it is.
pub fn declarations(comptime T: type) []const TypeInfo.Declaration {
return switch (@typeInfo(T)) {
.Struct => |info| info.decls,

View File

@@ -1236,7 +1236,7 @@ pub const Target = struct {
}
fn allCpusFromDecls(comptime cpus: type) []const *const Cpu.Model {
const decls = std.meta.declarations(cpus);
const decls = @typeInfo(cpus).Struct.decls;
var array: [decls.len]*const Cpu.Model = undefined;
for (decls) |decl, i| {
array[i] = &@field(cpus, decl.name);

View File

@@ -465,7 +465,7 @@ test {
/// Given a type, reference all the declarations inside, so that the semantic analyzer sees them.
pub fn refAllDecls(comptime T: type) void {
if (!builtin.is_test) return;
inline for (std.meta.declarations(T)) |decl| {
inline for (comptime std.meta.declarations(T)) |decl| {
_ = decl;
}
}

View File

@@ -1713,10 +1713,13 @@ struct ZigFn {
bool calls_or_awaits_errorable_fn;
bool is_cold;
bool is_test;
bool is_noinline;
};
static inline bool fn_is_test(const ZigFn *fn) {
return fn->proto_node->type == NodeTypeTestDecl;
}
uint32_t fn_table_entry_hash(ZigFn*);
bool fn_table_entry_eql(ZigFn *a, ZigFn *b);

View File

@@ -3861,7 +3861,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
fn_table_entry->fndef_scope = create_fndef_scope(g, source_node, tld_fn->base.parent_scope, fn_table_entry);
fn_table_entry->type_entry = get_test_fn_type(g);
fn_table_entry->body_node = source_node->data.test_decl.body;
fn_table_entry->is_test = true;
g->fn_defs.append(fn_table_entry);
g->test_fns.append(fn_table_entry);

View File

@@ -17934,7 +17934,6 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, AstNode *source_node, ZigVa
ensure_field_index(type_info_declaration_type, "name", 0);
ensure_field_index(type_info_declaration_type, "is_pub", 1);
ensure_field_index(type_info_declaration_type, "data", 2);
if (!resolve_types) {
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, type_info_declaration_type,
@@ -17954,61 +17953,27 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, AstNode *source_node, ZigVa
return ErrorNone;
}
ZigType *type_info_declaration_data_type = ir_type_info_get_type(ira, "Data", type_info_declaration_type);
if ((err = type_resolve(ira->codegen, type_info_declaration_data_type, ResolveStatusSizeKnown)))
return err;
ZigType *type_info_fn_decl_type = ir_type_info_get_type(ira, "FnDecl", type_info_declaration_data_type);
if ((err = type_resolve(ira->codegen, type_info_fn_decl_type, ResolveStatusSizeKnown)))
return err;
resolve_container_usingnamespace_decls(ira->codegen, decls_scope);
// The unresolved declarations are collected in a separate queue to avoid
// modifying decl_table while iterating over it
ZigList<Tld*> resolve_decl_queue{};
// Loop through our declarations once to figure out how many declarations
// we will generate info for.
int declaration_count = 0;
auto decl_it = decls_scope->decl_table.entry_iterator();
decltype(decls_scope->decl_table)::Entry *curr_entry = nullptr;
while ((curr_entry = decl_it.next()) != nullptr) {
if (curr_entry->value->resolution == TldResolutionInvalid) {
return ErrorSemanticAnalyzeFail;
}
if (curr_entry->value->resolution == TldResolutionResolving) {
ir_error_dependency_loop(ira, source_node);
return ErrorSemanticAnalyzeFail;
}
// If the declaration is unresolved, force it to be resolved again.
if (curr_entry->value->resolution == TldResolutionUnresolved)
resolve_decl_queue.append(curr_entry->value);
}
for (size_t i = 0; i < resolve_decl_queue.length; i++) {
Tld *decl = resolve_decl_queue.at(i);
resolve_top_level_decl(ira->codegen, decl, decl->source_node, false);
if (decl->resolution == TldResolutionInvalid) {
return ErrorSemanticAnalyzeFail;
}
}
resolve_decl_queue.deinit();
// Loop through our declarations once to figure out how many declarations we will generate info for.
int declaration_count = 0;
decl_it = decls_scope->decl_table.entry_iterator();
while ((curr_entry = decl_it.next()) != nullptr) {
// Skip comptime blocks and test functions.
if (curr_entry->value->id == TldIdCompTime)
continue;
if (curr_entry->value->id == TldIdFn) {
ZigFn *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
if (fn_entry->is_test)
continue;
if (curr_entry->value->id == TldIdFn &&
curr_entry->value->source_node->type == NodeTypeTestDecl)
{
continue;
}
if (curr_entry->value->resolution == TldResolutionInvalid)
return ErrorSemanticAnalyzeFail;
declaration_count += 1;
}
@@ -18027,10 +17992,11 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, AstNode *source_node, ZigVa
// Skip comptime blocks and test functions.
if (curr_entry->value->id == TldIdCompTime) {
continue;
} else if (curr_entry->value->id == TldIdFn) {
ZigFn *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
if (fn_entry->is_test)
continue;
}
if (curr_entry->value->id == TldIdFn &&
curr_entry->value->source_node->type == NodeTypeTestDecl)
{
continue;
}
ZigValue *declaration_val = &declaration_array->data.x_array.data.s_none.elements[declaration_index];
@@ -18038,143 +18004,12 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, AstNode *source_node, ZigVa
declaration_val->special = ConstValSpecialStatic;
declaration_val->type = type_info_declaration_type;
ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 3);
ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2);
ZigValue *name = create_const_str_lit(ira->codegen, curr_entry->key)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(curr_entry->key), true, nullptr);
inner_fields[1]->special = ConstValSpecialStatic;
inner_fields[1]->type = ira->codegen->builtin_types.entry_bool;
inner_fields[1]->data.x_bool = curr_entry->value->visib_mod == VisibModPub;
inner_fields[2]->special = ConstValSpecialStatic;
inner_fields[2]->type = type_info_declaration_data_type;
inner_fields[2]->parent.id = ConstParentIdStruct;
inner_fields[2]->parent.data.p_struct.struct_val = declaration_val;
inner_fields[2]->parent.data.p_struct.field_index = 1;
switch (curr_entry->value->id) {
case TldIdVar:
{
ZigVar *var = ((TldVar *)curr_entry->value)->var;
assert(var != nullptr);
if ((err = type_resolve(ira->codegen, var->const_value->type, ResolveStatusSizeKnown)))
return ErrorSemanticAnalyzeFail;
if (var->const_value->type->id == ZigTypeIdMetaType) {
// We have a variable of type 'type', so it's actually a type declaration.
// 0: Data.Type: type
bigint_init_unsigned(&inner_fields[2]->data.x_union.tag, 0);
inner_fields[2]->data.x_union.payload = var->const_value;
} else {
// We have a variable of another type, so we store the type of the variable.
// 1: Data.Var: type
bigint_init_unsigned(&inner_fields[2]->data.x_union.tag, 1);
ZigValue *payload = ira->codegen->pass1_arena->create<ZigValue>();
payload->special = ConstValSpecialStatic;
payload->type = ira->codegen->builtin_types.entry_type;
payload->data.x_type = var->const_value->type;
inner_fields[2]->data.x_union.payload = payload;
}
break;
}
case TldIdFn:
{
// 2: Data.Fn: Data.FnDecl
bigint_init_unsigned(&inner_fields[2]->data.x_union.tag, 2);
ZigFn *fn_entry = ((TldFn *)curr_entry->value)->fn_entry;
assert(!fn_entry->is_test);
assert(fn_entry->type_entry != nullptr);
AstNodeFnProto *fn_node = &fn_entry->proto_node->data.fn_proto;
ZigValue *fn_decl_val = ira->codegen->pass1_arena->create<ZigValue>();
fn_decl_val->special = ConstValSpecialStatic;
fn_decl_val->type = type_info_fn_decl_type;
fn_decl_val->parent.id = ConstParentIdUnion;
fn_decl_val->parent.data.p_union.union_val = inner_fields[2];
ZigValue **fn_decl_fields = alloc_const_vals_ptrs(ira->codegen, 9);
fn_decl_val->data.x_struct.fields = fn_decl_fields;
// fn_type: type
ensure_field_index(fn_decl_val->type, "fn_type", 0);
fn_decl_fields[0]->special = ConstValSpecialStatic;
fn_decl_fields[0]->type = ira->codegen->builtin_types.entry_type;
fn_decl_fields[0]->data.x_type = fn_entry->type_entry;
// is_noinline: bool
ensure_field_index(fn_decl_val->type, "is_noinline", 1);
fn_decl_fields[1]->special = ConstValSpecialStatic;
fn_decl_fields[1]->type = ira->codegen->builtin_types.entry_bool;
fn_decl_fields[1]->data.x_bool = fn_entry->is_noinline;
// is_var_args: bool
ensure_field_index(fn_decl_val->type, "is_var_args", 2);
bool is_varargs = fn_node->is_var_args;
fn_decl_fields[2]->special = ConstValSpecialStatic;
fn_decl_fields[2]->type = ira->codegen->builtin_types.entry_bool;
fn_decl_fields[2]->data.x_bool = is_varargs;
// is_extern: bool
ensure_field_index(fn_decl_val->type, "is_extern", 3);
fn_decl_fields[3]->special = ConstValSpecialStatic;
fn_decl_fields[3]->type = ira->codegen->builtin_types.entry_bool;
fn_decl_fields[3]->data.x_bool = fn_node->is_extern;
// is_export: bool
ensure_field_index(fn_decl_val->type, "is_export", 4);
fn_decl_fields[4]->special = ConstValSpecialStatic;
fn_decl_fields[4]->type = ira->codegen->builtin_types.entry_bool;
fn_decl_fields[4]->data.x_bool = fn_node->is_export;
// lib_name: ?[]const u8
ensure_field_index(fn_decl_val->type, "lib_name", 5);
fn_decl_fields[5]->special = ConstValSpecialStatic;
ZigType *u8_ptr = get_pointer_to_type_extra(
ira->codegen, ira->codegen->builtin_types.entry_u8,
true, false, PtrLenUnknown,
0, 0, 0, false);
fn_decl_fields[5]->type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr));
if (fn_node->is_extern && fn_node->lib_name != nullptr && buf_len(fn_node->lib_name) > 0) {
ZigValue *slice_val = ira->codegen->pass1_arena->create<ZigValue>();
ZigValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, slice_val, lib_name, 0, buf_len(fn_node->lib_name), true, nullptr);
set_optional_payload(fn_decl_fields[5], slice_val);
} else {
set_optional_payload(fn_decl_fields[5], nullptr);
}
// return_type: type
ensure_field_index(fn_decl_val->type, "return_type", 6);
fn_decl_fields[6]->special = ConstValSpecialStatic;
fn_decl_fields[6]->type = ira->codegen->builtin_types.entry_type;
fn_decl_fields[6]->data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
// arg_names: [][] const u8
ensure_field_index(fn_decl_val->type, "arg_names", 7);
size_t fn_arg_count = fn_entry->variable_list.length;
ZigValue *fn_arg_name_array = ira->codegen->pass1_arena->create<ZigValue>();
fn_arg_name_array->special = ConstValSpecialStatic;
fn_arg_name_array->type = get_array_type(ira->codegen,
get_slice_type(ira->codegen, u8_ptr), fn_arg_count, nullptr);
fn_arg_name_array->data.x_array.special = ConstArraySpecialNone;
fn_arg_name_array->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate<ZigValue>(fn_arg_count);
init_const_slice(ira->codegen, fn_decl_fields[7], fn_arg_name_array, 0, fn_arg_count, false, nullptr);
for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) {
ZigVar *arg_var = fn_entry->variable_list.at(fn_arg_index);
ZigValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.data.s_none.elements[fn_arg_index];
ZigValue *arg_name = create_const_str_lit(ira->codegen,
buf_create_from_str(arg_var->name))->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, strlen(arg_var->name), true, nullptr);
fn_arg_name_val->parent.id = ConstParentIdArray;
fn_arg_name_val->parent.data.p_array.array_val = fn_arg_name_array;
fn_arg_name_val->parent.data.p_array.elem_index = fn_arg_index;
}
inner_fields[2]->data.x_union.payload = fn_decl_val;
break;
}
default:
zig_unreachable();
}
declaration_val->data.x_struct.fields = inner_fields;
declaration_index += 1;

View File

@@ -408,7 +408,7 @@ pub fn translate(
context.pattern_list.deinit(gpa);
}
inline for (meta.declarations(std.zig.c_builtins)) |decl| {
inline for (@typeInfo(std.zig.c_builtins).Struct.decls) |decl| {
if (decl.is_pub) {
const builtin = try Tag.pub_var_simple.create(context.arena, .{
.name = decl.name,
@@ -2009,7 +2009,7 @@ fn transImplicitCastExpr(
}
fn isBuiltinDefined(name: []const u8) bool {
inline for (meta.declarations(std.zig.c_builtins)) |decl| {
inline for (@typeInfo(std.zig.c_builtins).Struct.decls) |decl| {
if (!decl.is_pub) continue;
if (std.mem.eql(u8, name, decl.name)) return true;
}

View File

@@ -149,6 +149,7 @@ test {
_ = @import("behavior/bugs/10147.zig");
_ = @import("behavior/byteswap.zig");
_ = @import("behavior/const_slice_child.zig");
_ = @import("behavior/export_self_referential_type_info.zig");
_ = @import("behavior/field_parent_ptr.zig");
_ = @import("behavior/floatop_stage1.zig");
_ = @import("behavior/fn_delegation.zig");

View File

@@ -0,0 +1 @@
export const foo = @typeInfo(@This()).Struct.decls;

View File

@@ -286,10 +286,6 @@ fn testStruct() !void {
try expect(struct_info.Struct.fields[3].alignment == 1);
try expect(struct_info.Struct.decls.len == 2);
try expect(struct_info.Struct.decls[0].is_pub);
try expect(!struct_info.Struct.decls[0].data.Fn.is_extern);
try expect(struct_info.Struct.decls[0].data.Fn.lib_name == null);
try expect(struct_info.Struct.decls[0].data.Fn.return_type == void);
try expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void);
}
const TestUnpackedStruct = struct {
@@ -420,34 +416,6 @@ test "type info: TypeId -> TypeInfo impl cast" {
_ = comptime passTypeInfo(TypeId.Void);
}
test "type info: extern fns with and without lib names" {
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
const S = struct {
extern fn bar1() void;
extern "cool" fn bar2() void;
};
const info = @typeInfo(S);
comptime {
for (info.Struct.decls) |decl| {
if (std.mem.eql(u8, decl.name, "bar1")) {
try expect(decl.data.Fn.lib_name == null);
} else {
try expectEqualStrings("cool", decl.data.Fn.lib_name.?);
}
}
}
}
test "data field is a compile-time value" {
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
const S = struct {
const Bar = @as(isize, -1);
};
comptime try expect(@typeInfo(S).Struct.decls[0].data.Var == isize);
}
test "sentinel of opaque pointer type" {
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO

View File

@@ -1199,12 +1199,6 @@ pub fn addCases(ctx: *TestContext) !void {
"tmp.zig:5:22: error: expected type 'fn([*c]u8, ...) callconv(.C) void', found 'fn([*:0]u8, ...) callconv(.C) void'",
});
ctx.testErrStage1("dependency loop in top-level decl with @TypeInfo when accessing the decls",
\\export const foo = @typeInfo(@This()).Struct.decls;
, &[_][]const u8{
"tmp.zig:1:20: error: dependency loop detected",
});
ctx.objErrStage1("function call assigned to incorrect type",
\\export fn entry() void {
\\ var arr: [4]f32 = undefined;