diff --git a/src/stage1/astgen.cpp b/src/stage1/astgen.cpp index a5afe32d8b..44dc1080c2 100644 --- a/src/stage1/astgen.cpp +++ b/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) + Scope *scope, AstNode *source_node, Buf *out_bare_name, ResultLoc *result_loc) { - 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; + // 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: diff --git a/src/stage1/astgen.hpp b/src/stage1/astgen.hpp index d4bb6923a1..c0ca583f56 100644 --- a/src/stage1/astgen.hpp +++ b/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 diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index e9bb7b1d15..b1583cc6b4 100644 --- a/src/stage1/ir.cpp +++ b/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(fields_len); entry->data.unionation.fields_by_name.init(fields_len); diff --git a/test/behavior/misc.zig b/test/behavior/misc.zig index 6fabbf487b..fdd3f3477b 100644 --- a/test/behavior/misc.zig +++ b/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); diff --git a/test/behavior/typename.zig b/test/behavior/typename.zig index bf8464244b..4d87e0030c 100644 --- a/test/behavior/typename.zig +++ b/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 {}; }