Commit ed174b7386
Changed files (5)
src
test
behavior
src/stage1/astgen.cpp
@@ -3454,7 +3454,7 @@ static Stage1ZirInst *astgen_merge_err_sets(Stage1AstGen *ag, Scope *scope, AstN
// TODO only pass type_name when the || operator is the top level AST node in the var decl expr
Buf bare_name = BUF_INIT;
- Buf *type_name = get_anon_type_name(ag->codegen, ag->exec, "error", scope, node, &bare_name);
+ Buf *type_name = get_anon_type_name(ag->codegen, ag->exec, "error", scope, node, &bare_name, nullptr);
return ir_build_merge_err_sets(ag, scope, node, op1, op2, type_name);
}
@@ -7588,42 +7588,73 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o
}
Buf *get_anon_type_name(CodeGen *codegen, Stage1Zir *exec, const char *kind_name,
- Scope *scope, AstNode *source_node, Buf *out_bare_name)
-{
- if (exec != nullptr && exec->name) {
- ZigType *import = get_scope_import(scope);
- Buf *namespace_name = buf_alloc();
- append_namespace_qualification(codegen, namespace_name, import);
- buf_append_buf(namespace_name, exec->name);
- buf_init_from_buf(out_bare_name, exec->name);
- return namespace_name;
- } else if (exec != nullptr && exec->name_fn != nullptr) {
- Buf *name = buf_alloc();
- buf_append_buf(name, &exec->name_fn->symbol_name);
- buf_appendf(name, "(");
- render_instance_name_recursive(codegen, name, &exec->name_fn->fndef_scope->base, exec->begin_scope);
- buf_appendf(name, ")");
- buf_init_from_buf(out_bare_name, name);
- return name;
- } else {
- ZigType *import = get_scope_import(scope);
- Buf *namespace_name = buf_alloc();
- append_namespace_qualification(codegen, namespace_name, import);
- RootStruct *root_struct = source_node->owner->data.structure.root_struct;
- TokenLoc tok_loc = root_struct->token_locs[source_node->main_token];
- buf_appendf(namespace_name, "%s:%u:%u", kind_name,
- tok_loc.line + 1, tok_loc.column + 1);
- buf_init_from_buf(out_bare_name, namespace_name);
- return namespace_name;
+ Scope *scope, AstNode *source_node, Buf *out_bare_name, ResultLoc *result_loc)
+{
+ // See https://ziglang.org/documentation/master/#Struct-Naming .
+ bool force_generic = false;
+ if (result_loc != nullptr
+ && result_loc->source_instruction != nullptr
+ && result_loc->source_instruction->source_node != nullptr
+ ) {
+ switch (result_loc->source_instruction->source_node->type) {
+ case NodeTypeVariableDeclaration: {
+ ZigType *import = get_scope_import(scope);
+ Buf *name = buf_alloc();
+ append_namespace_qualification(codegen, name, import);
+ const auto &basename = result_loc->source_instruction->source_node->data.variable_declaration.symbol;
+ buf_append_buf(name, basename);
+ buf_init_from_buf(out_bare_name, basename);
+ return name;
+ }
+ case NodeTypeFnCallExpr:
+ case NodeTypeStructValueField:
+ force_generic = true;
+ break;
+ default:
+ break;
+ }
}
+
+ if (!force_generic) {
+ if (exec != nullptr && exec->name != nullptr) {
+ ZigType *import = get_scope_import(scope);
+ Buf *namespace_name = buf_alloc();
+ append_namespace_qualification(codegen, namespace_name, import);
+ buf_append_buf(namespace_name, exec->name);
+ buf_init_from_buf(out_bare_name, exec->name);
+ return namespace_name;
+ }
+ if (exec != nullptr && exec->name_fn != nullptr) {
+ Buf *name = buf_alloc();
+ buf_append_buf(name, &exec->name_fn->symbol_name);
+ buf_appendf(name, "(");
+ render_instance_name_recursive(codegen, name, &exec->name_fn->fndef_scope->base, exec->begin_scope);
+ buf_appendf(name, ")");
+ buf_init_from_buf(out_bare_name, name);
+ return name;
+ }
+ }
+
+ ZigType *import = get_scope_import(scope);
+ Buf *namespace_name = buf_alloc();
+ append_namespace_qualification(codegen, namespace_name, import);
+ RootStruct *root_struct = source_node->owner->data.structure.root_struct;
+ TokenLoc tok_loc = root_struct->token_locs[source_node->main_token];
+ buf_appendf(namespace_name, "%s:%u:%u", kind_name,
+ tok_loc.line + 1, tok_loc.column + 1);
+ buf_init_from_buf(out_bare_name, namespace_name);
+ return namespace_name;
}
-static Stage1ZirInst *astgen_container_decl(Stage1AstGen *ag, Scope *parent_scope, AstNode *node) {
+static Stage1ZirInst *astgen_container_decl(Stage1AstGen *ag, Scope *parent_scope,
+ AstNode *node, ResultLoc *result_loc)
+{
assert(node->type == NodeTypeContainerDecl);
ContainerKind kind = node->data.container_decl.kind;
Buf *bare_name = buf_alloc();
- Buf *name = get_anon_type_name(ag->codegen, ag->exec, container_string(kind), parent_scope, node, bare_name);
+ Buf *name = get_anon_type_name(ag->codegen,
+ ag->exec, container_string(kind), parent_scope, node, bare_name, result_loc);
ContainerLayout layout = node->data.container_decl.layout;
ZigType *container_type = get_partial_container_type(ag->codegen, parent_scope,
@@ -7653,7 +7684,7 @@ static Stage1ZirInst *astgen_err_set_decl(Stage1AstGen *ag, Scope *parent_scope,
uint32_t err_count = node->data.err_set_decl.decls.length;
Buf bare_name = BUF_INIT;
- Buf *type_name = get_anon_type_name(ag->codegen, ag->exec, "error", parent_scope, node, &bare_name);
+ Buf *type_name = get_anon_type_name(ag->codegen, ag->exec, "error", parent_scope, node, &bare_name, nullptr);
ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
buf_init_from_buf(&err_set_type->name, type_name);
err_set_type->data.error_set.err_count = err_count;
@@ -7963,7 +7994,7 @@ static Stage1ZirInst *astgen_node_raw(Stage1AstGen *ag, AstNode *node, Scope *sc
case NodeTypeCatchExpr:
return astgen_catch(ag, scope, node, lval, result_loc);
case NodeTypeContainerDecl:
- return ir_lval_wrap(ag, scope, astgen_container_decl(ag, scope, node), lval, result_loc);
+ return ir_lval_wrap(ag, scope, astgen_container_decl(ag, scope, node, result_loc), lval, result_loc);
case NodeTypeFnProto:
return ir_lval_wrap(ag, scope, astgen_fn_proto(ag, scope, node), lval, result_loc);
case NodeTypeErrorSetDecl:
src/stage1/astgen.hpp
@@ -32,6 +32,6 @@ void destroy_instruction_src(Stage1ZirInst *inst);
bool ir_should_inline(Stage1Zir *exec, Scope *scope);
Buf *get_anon_type_name(CodeGen *codegen, Stage1Zir *exec, const char *kind_name,
- Scope *scope, AstNode *source_node, Buf *out_bare_name);
+ Scope *scope, AstNode *source_node, Buf *out_bare_name, ResultLoc *result_loc);
#endif
src/stage1/ir.cpp
@@ -10423,7 +10423,7 @@ static Stage1AirInst *ir_analyze_tuple_cat(IrAnalyze *ira, Scope *scope, AstNode
Buf *bare_name = buf_alloc();
Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct),
- scope, source_node, bare_name);
+ scope, source_node, bare_name, nullptr);
ZigType *new_type = get_partial_container_type(ira->codegen, scope,
ContainerKindStruct, source_node, buf_ptr(name), bare_name, ContainerLayoutAuto);
new_type->data.structure.special = StructSpecialInferredTuple;
@@ -10755,7 +10755,7 @@ static Stage1AirInst *ir_analyze_tuple_mult(IrAnalyze *ira, Scope *scope, AstNod
Buf *bare_name = buf_alloc();
Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct),
- scope, source_node, bare_name);
+ scope, source_node, bare_name, nullptr);
ZigType *new_type = get_partial_container_type(ira->codegen, scope,
ContainerKindStruct, source_node, buf_ptr(name), bare_name, ContainerLayoutAuto);
new_type->data.structure.special = StructSpecialInferredTuple;
@@ -12277,7 +12277,7 @@ static Stage1AirInst *ir_analyze_instruction_resolve_result(IrAnalyze *ira, Stag
if (implicit_elem_type == ira->codegen->builtin_types.entry_anytype) {
Buf *bare_name = buf_alloc();
Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct),
- instruction->base.scope, instruction->base.source_node, bare_name);
+ instruction->base.scope, instruction->base.source_node, bare_name, nullptr);
StructSpecial struct_special = StructSpecialInferredStruct;
if (instruction->base.source_node->type == NodeTypeContainerInitExpr &&
@@ -18898,7 +18898,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
Buf *bare_name = buf_alloc();
Buf *full_name = get_anon_type_name(ira->codegen,
- ira->zir, "opaque", scope, source_node, bare_name);
+ ira->zir, "opaque", scope, source_node, bare_name, nullptr);
return get_opaque_type(ira->codegen,
scope, source_node, buf_ptr(full_name), bare_name);
}
@@ -18945,7 +18945,8 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
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->zir, "error", scope, source_node, &bare_name));
+ buf_init_from_buf(&err_set_type->name,
+ get_anon_type_name(ira->codegen, ira->zir, "error", scope, source_node, &bare_name, nullptr));
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;
@@ -19024,7 +19025,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
ZigType *entry = new_type_table_entry(ZigTypeIdStruct);
buf_init_from_buf(&entry->name,
- get_anon_type_name(ira->codegen, ira->zir, "struct", scope, source_node, &entry->name));
+ get_anon_type_name(ira->codegen, ira->zir, "struct", scope, source_node, &entry->name, nullptr));
entry->data.structure.decl_node = source_node;
entry->data.structure.fields = alloc_type_struct_fields(fields_len);
entry->data.structure.fields_by_name.init(fields_len);
@@ -19134,7 +19135,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
ZigType *entry = new_type_table_entry(ZigTypeIdEnum);
buf_init_from_buf(&entry->name,
- get_anon_type_name(ira->codegen, ira->zir, "enum", scope, source_node, &entry->name));
+ get_anon_type_name(ira->codegen, ira->zir, "enum", scope, source_node, &entry->name, nullptr));
entry->data.enumeration.decl_node = source_node;
entry->data.enumeration.tag_int_type = tag_type;
entry->data.enumeration.decls_scope = create_decls_scope(
@@ -19216,7 +19217,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
ZigType *entry = new_type_table_entry(ZigTypeIdUnion);
buf_init_from_buf(&entry->name,
- get_anon_type_name(ira->codegen, ira->zir, "union", scope, source_node, &entry->name));
+ get_anon_type_name(ira->codegen, ira->zir, "union", scope, source_node, &entry->name, nullptr));
entry->data.unionation.decl_node = source_node;
entry->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(fields_len);
entry->data.unionation.fields_by_name.init(fields_len);
test/behavior/misc.zig
@@ -436,30 +436,6 @@ const AUnion = union {
Two: void,
};
-test "@typeName" {
- const Struct = struct {};
- const Union = union {
- unused: u8,
- };
- const Enum = enum {
- Unused,
- };
- comptime {
- try expect(mem.eql(u8, @typeName(i64), "i64"));
- try expect(mem.eql(u8, @typeName(*usize), "*usize"));
- // https://github.com/ziglang/zig/issues/675
- try expect(mem.eql(u8, "behavior.misc.TypeFromFn(u8)", @typeName(TypeFromFn(u8))));
- try expect(mem.eql(u8, @typeName(Struct), "Struct"));
- try expect(mem.eql(u8, @typeName(Union), "Union"));
- try expect(mem.eql(u8, @typeName(Enum), "Enum"));
- }
-}
-
-fn TypeFromFn(comptime T: type) type {
- _ = T;
- return struct {};
-}
-
test "double implicit cast in same expression" {
var x = @as(i32, @as(u16, nine()));
try expect(x == 9);
test/behavior/typename.zig
@@ -2,6 +2,113 @@ const std = @import("std");
const expect = std.testing.expect;
const expectEqualSlices = std.testing.expectEqualSlices;
-test "slice" {
- try expectEqualSlices(u8, "[]u8", @typeName([]u8));
+// Most tests here can be comptime but use runtime so that a stacktrace
+// can show failure location.
+//
+// Note certain results of `@typeName()` expect `behavior.zig` to be the
+// root file. Running a test against this file as root will result in
+// failures.
+
+// CAUTION: this test is source-location sensitive.
+test "anon fn param - source-location sensitive" {
+ // https://github.com/ziglang/zig/issues/9339
+ try expectEqualSlices(u8, @typeName(TypeFromFn(struct {})), "behavior.typename.TypeFromFn(behavior.typename.struct:15:52)");
+ try expectEqualSlices(u8, @typeName(TypeFromFn(union { unused: u8 })), "behavior.typename.TypeFromFn(behavior.typename.union:16:52)");
+ try expectEqualSlices(u8, @typeName(TypeFromFn(enum { unused })), "behavior.typename.TypeFromFn(behavior.typename.enum:17:52)");
+
+ try expectEqualSlices(
+ u8,
+ @typeName(TypeFromFn3(struct {}, union { unused: u8 }, enum { unused })),
+ "behavior.typename.TypeFromFn3(behavior.typename.struct:21:31,behavior.typename.union:21:42,behavior.typename.enum:21:64)",
+ );
+}
+
+// CAUTION: this test is source-location sensitive.
+test "anon field init" {
+ const Foo = .{
+ .T1 = struct {},
+ .T2 = union { unused: u8 },
+ .T3 = enum { unused },
+ };
+
+ try expectEqualSlices(u8, @typeName(Foo.T1), "behavior.typename.struct:29:15");
+ try expectEqualSlices(u8, @typeName(Foo.T2), "behavior.typename.union:30:15");
+ try expectEqualSlices(u8, @typeName(Foo.T3), "behavior.typename.enum:31:15");
+}
+
+test "basic" {
+ try expectEqualSlices(u8, @typeName(i64), "i64");
+ try expectEqualSlices(u8, @typeName(*usize), "*usize");
+ try expectEqualSlices(u8, @typeName([]u8), "[]u8");
+}
+
+test "top level decl" {
+ try expectEqualSlices(u8, @typeName(A_Struct), "A_Struct");
+ try expectEqualSlices(u8, @typeName(A_Union), "A_Union");
+ try expectEqualSlices(u8, @typeName(A_Enum), "A_Enum");
+
+ // regular fn, without error
+ try expectEqualSlices(u8, @typeName(@TypeOf(regular)), "fn() void");
+ // regular fn inside struct, with error
+ try expectEqualSlices(u8, @typeName(@TypeOf(B.doTest)), "fn() @typeInfo(@typeInfo(@TypeOf(behavior.typename.B.doTest)).Fn.return_type.?).ErrorUnion.error_set!void");
+ // generic fn
+ try expectEqualSlices(u8, @typeName(@TypeOf(TypeFromFn)), "fn(type) anytype");
+}
+
+const A_Struct = struct {};
+const A_Union = union {
+ unused: u8,
+};
+const A_Enum = enum {
+ unused,
+};
+
+fn regular() void {}
+
+test "fn body decl" {
+ try B.doTest();
+}
+
+const B = struct {
+ fn doTest() !void {
+ const B_Struct = struct {};
+ const B_Union = union {
+ unused: u8,
+ };
+ const B_Enum = enum {
+ unused,
+ };
+
+ try expectEqualSlices(u8, @typeName(B_Struct), "B_Struct");
+ try expectEqualSlices(u8, @typeName(B_Union), "B_Union");
+ try expectEqualSlices(u8, @typeName(B_Enum), "B_Enum");
+ }
+};
+
+test "fn param" {
+ // https://github.com/ziglang/zig/issues/675
+ try expectEqualSlices(u8, @typeName(TypeFromFn(u8)), "behavior.typename.TypeFromFn(u8)");
+ try expectEqualSlices(u8, @typeName(TypeFromFn(A_Struct)), "behavior.typename.TypeFromFn(behavior.typename.A_Struct)");
+ try expectEqualSlices(u8, @typeName(TypeFromFn(A_Union)), "behavior.typename.TypeFromFn(behavior.typename.A_Union)");
+ try expectEqualSlices(u8, @typeName(TypeFromFn(A_Enum)), "behavior.typename.TypeFromFn(behavior.typename.A_Enum)");
+
+ try expectEqualSlices(u8, @typeName(TypeFromFn2(u8, bool)), "behavior.typename.TypeFromFn2(u8,bool)");
+}
+
+fn TypeFromFn(comptime T: type) type {
+ _ = T;
+ return struct {};
+}
+
+fn TypeFromFn2(comptime T1: type, comptime T2: type) type {
+ _ = T1;
+ _ = T2;
+ return struct {};
+}
+
+fn TypeFromFn3(comptime T1: type, comptime T2: type, comptime T3: type) type {
+ _ = T1;
+ _ = T2;
+ _ = T3;
+ return struct {};
}