| author | |
| committer | |
| log | f3f5a5d05b7056aceb408b701613242d053019ab |
| tree | acb912950d734b0c25b38c1ae82a8558d1313057 |
| parent | 69d78bdae4a5d0ec5877add5936ae8e9daf09140 |
* make it always return a fully qualified name. stage1 is inconsistent
about this.
* AstGen: fix anon_name_strategy to correctly be `func` when anon type
creation happens in the operand of the return expression.
* Sema: implement type names for the "function" naming strategy.
* Put "enum", "union", "opaque", or "struct" in place of "anon" when
creating respective anonymous Decl names.
* std.testing: add `expectStringStartsWith`. Didn't end up using it
after all.
Also this enables the real test runner for stage2 LLVM backend (sans
wasm32) since it works now.11 files changed, 369 insertions(+), 87 deletions(-)
doc/langref.html.in+2-1| ... | @@ -9702,8 +9702,9 @@ test "integer truncation" { | ... | @@ -9702,8 +9702,9 @@ test "integer truncation" { |
| 9702 | <p> | 9702 | <p> |
| 9703 | This function returns the string representation of a type, as | 9703 | This function returns the string representation of a type, as |
| 9704 | an array. It is equivalent to a string literal of the type name. | 9704 | an array. It is equivalent to a string literal of the type name. |
| 9705 | The returned type name is fully qualified with the parent namespace included | ||
| 9706 | as part of the type name with a series of dots. | ||
| 9705 | </p> | 9707 | </p> |
| 9706 | |||
| 9707 | {#header_close#} | 9708 | {#header_close#} |
| 9708 | 9709 | ||
| 9709 | {#header_open|@TypeOf#} | 9710 | {#header_open|@TypeOf#} |
lib/std/special/test_runner.zig+3-1| ... | @@ -23,7 +23,9 @@ fn processArgs() void { | ... | @@ -23,7 +23,9 @@ fn processArgs() void { |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | pub fn main() void { | 25 | pub fn main() void { |
| 26 | if (builtin.zig_backend != .stage1) { | 26 | if (builtin.zig_backend != .stage1 and |
| 27 | (builtin.zig_backend != .stage2_llvm or builtin.cpu.arch == .wasm32)) | ||
| 28 | { | ||
| 27 | return main2() catch @panic("test failure"); | 29 | return main2() catch @panic("test failure"); |
| 28 | } | 30 | } |
| 29 | if (builtin.zig_backend == .stage1) processArgs(); | 31 | if (builtin.zig_backend == .stage1) processArgs(); |
lib/std/testing.zig+20| ... | @@ -445,6 +445,26 @@ pub fn expectEqualStrings(expected: []const u8, actual: []const u8) !void { | ... | @@ -445,6 +445,26 @@ pub fn expectEqualStrings(expected: []const u8, actual: []const u8) !void { |
| 445 | } | 445 | } |
| 446 | } | 446 | } |
| 447 | 447 | ||
| 448 | pub fn expectStringStartsWith(actual: []const u8, expected_starts_with: []const u8) !void { | ||
| 449 | if (std.mem.startsWith(u8, actual, expected_starts_with)) | ||
| 450 | return; | ||
| 451 | |||
| 452 | const shortened_actual = if (actual.len >= expected_starts_with.len) | ||
| 453 | actual[0..expected_starts_with.len] | ||
| 454 | else | ||
| 455 | actual; | ||
| 456 | |||
| 457 | print("\n====== expected to start with: =========\n", .{}); | ||
| 458 | printWithVisibleNewlines(expected_starts_with); | ||
| 459 | print("\n====== instead ended with: ===========\n", .{}); | ||
| 460 | printWithVisibleNewlines(shortened_actual); | ||
| 461 | print("\n========= full output: ==============\n", .{}); | ||
| 462 | printWithVisibleNewlines(actual); | ||
| 463 | print("\n======================================\n", .{}); | ||
| 464 | |||
| 465 | return error.TestExpectedStartsWith; | ||
| 466 | } | ||
| 467 | |||
| 448 | pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) !void { | 468 | pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) !void { |
| 449 | if (std.mem.endsWith(u8, actual, expected_ends_with)) | 469 | if (std.mem.endsWith(u8, actual, expected_ends_with)) |
| 450 | return; | 470 | return; |
src/AstGen.zig+3| ... | @@ -6293,7 +6293,10 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref | ... | @@ -6293,7 +6293,10 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 6293 | } else .{ | 6293 | } else .{ |
| 6294 | .ty = try gz.addNodeExtended(.ret_type, node), | 6294 | .ty = try gz.addNodeExtended(.ret_type, node), |
| 6295 | }; | 6295 | }; |
| 6296 | const prev_anon_name_strategy = gz.anon_name_strategy; | ||
| 6297 | gz.anon_name_strategy = .func; | ||
| 6296 | const operand = try reachableExpr(gz, scope, rl, operand_node, node); | 6298 | const operand = try reachableExpr(gz, scope, rl, operand_node, node); |
| 6299 | gz.anon_name_strategy = prev_anon_name_strategy; | ||
| 6297 | 6300 | ||
| 6298 | switch (nodeMayEvalToError(tree, operand_node)) { | 6301 | switch (nodeMayEvalToError(tree, operand_node)) { |
| 6299 | .never => { | 6302 | .never => { |
src/Sema.zig+47-21| ... | @@ -1767,7 +1767,7 @@ fn zirStructDecl( | ... | @@ -1767,7 +1767,7 @@ fn zirStructDecl( |
| 1767 | const struct_obj = try new_decl_arena_allocator.create(Module.Struct); | 1767 | const struct_obj = try new_decl_arena_allocator.create(Module.Struct); |
| 1768 | const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); | 1768 | const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); |
| 1769 | const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); | 1769 | const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); |
| 1770 | const type_name = try sema.createTypeName(block, small.name_strategy); | 1770 | const type_name = try sema.createTypeName(block, small.name_strategy, "struct"); |
| 1771 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ | 1771 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ |
| 1772 | .ty = Type.type, | 1772 | .ty = Type.type, |
| 1773 | .val = struct_val, | 1773 | .val = struct_val, |
| ... | @@ -1796,28 +1796,54 @@ fn zirStructDecl( | ... | @@ -1796,28 +1796,54 @@ fn zirStructDecl( |
| 1796 | return sema.analyzeDeclVal(block, src, new_decl); | 1796 | return sema.analyzeDeclVal(block, src, new_decl); |
| 1797 | } | 1797 | } |
| 1798 | 1798 | ||
| 1799 | fn createTypeName(sema: *Sema, block: *Block, name_strategy: Zir.Inst.NameStrategy) ![:0]u8 { | 1799 | fn createTypeName( |
| 1800 | sema: *Sema, | ||
| 1801 | block: *Block, | ||
| 1802 | name_strategy: Zir.Inst.NameStrategy, | ||
| 1803 | anon_prefix: []const u8, | ||
| 1804 | ) ![:0]u8 { | ||
| 1800 | switch (name_strategy) { | 1805 | switch (name_strategy) { |
| 1801 | .anon => { | 1806 | .anon => { |
| 1802 | // It would be neat to have "struct:line:column" but this name has | 1807 | // It would be neat to have "struct:line:column" but this name has |
| 1803 | // to survive incremental updates, where it may have been shifted down | 1808 | // to survive incremental updates, where it may have been shifted down |
| 1804 | // or up to a different line, but unchanged, and thus not unnecessarily | 1809 | // or up to a different line, but unchanged, and thus not unnecessarily |
| 1805 | // semantically analyzed. | 1810 | // semantically analyzed. |
| 1811 | // This name is also used as the key in the parent namespace so it cannot be | ||
| 1812 | // renamed. | ||
| 1806 | const name_index = sema.mod.getNextAnonNameIndex(); | 1813 | const name_index = sema.mod.getNextAnonNameIndex(); |
| 1807 | return std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{ | 1814 | return std.fmt.allocPrintZ(sema.gpa, "{s}__{s}_{d}", .{ |
| 1808 | block.src_decl.name, name_index, | 1815 | block.src_decl.name, anon_prefix, name_index, |
| 1809 | }); | 1816 | }); |
| 1810 | }, | 1817 | }, |
| 1811 | .parent => return sema.gpa.dupeZ(u8, mem.sliceTo(block.src_decl.name, 0)), | 1818 | .parent => return sema.gpa.dupeZ(u8, mem.sliceTo(block.src_decl.name, 0)), |
| 1812 | .func => { | 1819 | .func => { |
| 1813 | const name_index = sema.mod.getNextAnonNameIndex(); | 1820 | const fn_info = sema.code.getFnInfo(sema.func.?.zir_body_inst); |
| 1814 | const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{ | 1821 | const zir_tags = sema.code.instructions.items(.tag); |
| 1815 | block.src_decl.name, name_index, | 1822 | |
| 1816 | }); | 1823 | var buf = std.ArrayList(u8).init(sema.gpa); |
| 1817 | log.warn("TODO: handle NameStrategy.func correctly instead of using anon name '{s}'", .{ | 1824 | defer buf.deinit(); |
| 1818 | name, | 1825 | try buf.appendSlice(mem.sliceTo(block.src_decl.name, 0)); |
| 1819 | }); | 1826 | try buf.appendSlice("("); |
| 1820 | return name; | 1827 | |
| 1828 | var arg_i: usize = 0; | ||
| 1829 | for (fn_info.param_body) |zir_inst| switch (zir_tags[zir_inst]) { | ||
| 1830 | .param, .param_comptime, .param_anytype, .param_anytype_comptime => { | ||
| 1831 | const arg = sema.inst_map.get(zir_inst).?; | ||
| 1832 | // The comptime call code in analyzeCall already did this, so we're | ||
| 1833 | // just repeating it here and it's guaranteed to work. | ||
| 1834 | const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg) catch unreachable; | ||
| 1835 | |||
| 1836 | if (arg_i != 0) try buf.appendSlice(","); | ||
| 1837 | try buf.writer().print("{}", .{arg_val}); | ||
| 1838 | |||
| 1839 | arg_i += 1; | ||
| 1840 | continue; | ||
| 1841 | }, | ||
| 1842 | else => continue, | ||
| 1843 | }; | ||
| 1844 | |||
| 1845 | try buf.appendSlice(")"); | ||
| 1846 | return buf.toOwnedSliceSentinel(0); | ||
| 1821 | }, | 1847 | }, |
| 1822 | } | 1848 | } |
| 1823 | } | 1849 | } |
| ... | @@ -1877,7 +1903,7 @@ fn zirEnumDecl( | ... | @@ -1877,7 +1903,7 @@ fn zirEnumDecl( |
| 1877 | }; | 1903 | }; |
| 1878 | const enum_ty = Type.initPayload(&enum_ty_payload.base); | 1904 | const enum_ty = Type.initPayload(&enum_ty_payload.base); |
| 1879 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); | 1905 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); |
| 1880 | const type_name = try sema.createTypeName(block, small.name_strategy); | 1906 | const type_name = try sema.createTypeName(block, small.name_strategy, "enum"); |
| 1881 | const new_decl = try mod.createAnonymousDeclNamed(block, .{ | 1907 | const new_decl = try mod.createAnonymousDeclNamed(block, .{ |
| 1882 | .ty = Type.type, | 1908 | .ty = Type.type, |
| 1883 | .val = enum_val, | 1909 | .val = enum_val, |
| ... | @@ -2088,7 +2114,7 @@ fn zirUnionDecl( | ... | @@ -2088,7 +2114,7 @@ fn zirUnionDecl( |
| 2088 | }; | 2114 | }; |
| 2089 | const union_ty = Type.initPayload(&union_payload.base); | 2115 | const union_ty = Type.initPayload(&union_payload.base); |
| 2090 | const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty); | 2116 | const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty); |
| 2091 | const type_name = try sema.createTypeName(block, small.name_strategy); | 2117 | const type_name = try sema.createTypeName(block, small.name_strategy, "union"); |
| 2092 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ | 2118 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ |
| 2093 | .ty = Type.type, | 2119 | .ty = Type.type, |
| 2094 | .val = union_val, | 2120 | .val = union_val, |
| ... | @@ -2156,7 +2182,7 @@ fn zirOpaqueDecl( | ... | @@ -2156,7 +2182,7 @@ fn zirOpaqueDecl( |
| 2156 | }; | 2182 | }; |
| 2157 | const opaque_ty = Type.initPayload(&opaque_ty_payload.base); | 2183 | const opaque_ty = Type.initPayload(&opaque_ty_payload.base); |
| 2158 | const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty); | 2184 | const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty); |
| 2159 | const type_name = try sema.createTypeName(block, small.name_strategy); | 2185 | const type_name = try sema.createTypeName(block, small.name_strategy, "opaque"); |
| 2160 | const new_decl = try mod.createAnonymousDeclNamed(block, .{ | 2186 | const new_decl = try mod.createAnonymousDeclNamed(block, .{ |
| 2161 | .ty = Type.type, | 2187 | .ty = Type.type, |
| 2162 | .val = opaque_val, | 2188 | .val = opaque_val, |
| ... | @@ -2204,7 +2230,7 @@ fn zirErrorSetDecl( | ... | @@ -2204,7 +2230,7 @@ fn zirErrorSetDecl( |
| 2204 | const error_set = try new_decl_arena_allocator.create(Module.ErrorSet); | 2230 | const error_set = try new_decl_arena_allocator.create(Module.ErrorSet); |
| 2205 | const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set); | 2231 | const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set); |
| 2206 | const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty); | 2232 | const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty); |
| 2207 | const type_name = try sema.createTypeName(block, name_strategy); | 2233 | const type_name = try sema.createTypeName(block, name_strategy, "error"); |
| 2208 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ | 2234 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ |
| 2209 | .ty = Type.type, | 2235 | .ty = Type.type, |
| 2210 | .val = error_set_val, | 2236 | .val = error_set_val, |
| ... | @@ -12697,7 +12723,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -12697,7 +12723,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 12697 | }; | 12723 | }; |
| 12698 | const enum_ty = Type.initPayload(&enum_ty_payload.base); | 12724 | const enum_ty = Type.initPayload(&enum_ty_payload.base); |
| 12699 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); | 12725 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); |
| 12700 | const type_name = try sema.createTypeName(block, .anon); | 12726 | const type_name = try sema.createTypeName(block, .anon, "enum"); |
| 12701 | const new_decl = try mod.createAnonymousDeclNamed(block, .{ | 12727 | const new_decl = try mod.createAnonymousDeclNamed(block, .{ |
| 12702 | .ty = Type.type, | 12728 | .ty = Type.type, |
| 12703 | .val = enum_val, | 12729 | .val = enum_val, |
| ... | @@ -12707,7 +12733,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -12707,7 +12733,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 12707 | 12733 | ||
| 12708 | enum_obj.* = .{ | 12734 | enum_obj.* = .{ |
| 12709 | .owner_decl = new_decl, | 12735 | .owner_decl = new_decl, |
| 12710 | .tag_ty = Type.initTag(.@"null"), | 12736 | .tag_ty = Type.@"null", |
| 12711 | .tag_ty_inferred = true, | 12737 | .tag_ty_inferred = true, |
| 12712 | .fields = .{}, | 12738 | .fields = .{}, |
| 12713 | .values = .{}, | 12739 | .values = .{}, |
| ... | @@ -12785,7 +12811,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -12785,7 +12811,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 12785 | }; | 12811 | }; |
| 12786 | const opaque_ty = Type.initPayload(&opaque_ty_payload.base); | 12812 | const opaque_ty = Type.initPayload(&opaque_ty_payload.base); |
| 12787 | const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty); | 12813 | const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty); |
| 12788 | const type_name = try sema.createTypeName(block, .anon); | 12814 | const type_name = try sema.createTypeName(block, .anon, "opaque"); |
| 12789 | const new_decl = try mod.createAnonymousDeclNamed(block, .{ | 12815 | const new_decl = try mod.createAnonymousDeclNamed(block, .{ |
| 12790 | .ty = Type.type, | 12816 | .ty = Type.type, |
| 12791 | .val = opaque_val, | 12817 | .val = opaque_val, |
| ... | @@ -12836,7 +12862,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -12836,7 +12862,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 12836 | }; | 12862 | }; |
| 12837 | const union_ty = Type.initPayload(&union_payload.base); | 12863 | const union_ty = Type.initPayload(&union_payload.base); |
| 12838 | const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty); | 12864 | const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty); |
| 12839 | const type_name = try sema.createTypeName(block, .anon); | 12865 | const type_name = try sema.createTypeName(block, .anon, "union"); |
| 12840 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ | 12866 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ |
| 12841 | .ty = Type.type, | 12867 | .ty = Type.type, |
| 12842 | .val = new_union_val, | 12868 | .val = new_union_val, |
| ... | @@ -13001,7 +13027,7 @@ fn reifyStruct( | ... | @@ -13001,7 +13027,7 @@ fn reifyStruct( |
| 13001 | const struct_obj = try new_decl_arena_allocator.create(Module.Struct); | 13027 | const struct_obj = try new_decl_arena_allocator.create(Module.Struct); |
| 13002 | const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); | 13028 | const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); |
| 13003 | const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); | 13029 | const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); |
| 13004 | const type_name = try sema.createTypeName(block, .anon); | 13030 | const type_name = try sema.createTypeName(block, .anon, "struct"); |
| 13005 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ | 13031 | const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{ |
| 13006 | .ty = Type.type, | 13032 | .ty = Type.type, |
| 13007 | .val = new_struct_val, | 13033 | .val = new_struct_val, |
src/type.zig+102-24| ... | @@ -1793,7 +1793,7 @@ pub const Type = extern union { | ... | @@ -1793,7 +1793,7 @@ pub const Type = extern union { |
| 1793 | }, | 1793 | }, |
| 1794 | .error_set_inferred => { | 1794 | .error_set_inferred => { |
| 1795 | const func = ty.castTag(.error_set_inferred).?.data.func; | 1795 | const func = ty.castTag(.error_set_inferred).?.data.func; |
| 1796 | return writer.print("(inferred error set of {s})", .{func.owner_decl.name}); | 1796 | return writer.print("@typeInfo(@typeInfo(@TypeOf({s})).Fn.return_type.?).ErrorUnion.error_set", .{func.owner_decl.name}); |
| 1797 | }, | 1797 | }, |
| 1798 | .error_set_merged => { | 1798 | .error_set_merged => { |
| 1799 | const names = ty.castTag(.error_set_merged).?.data.keys(); | 1799 | const names = ty.castTag(.error_set_merged).?.data.keys(); |
| ... | @@ -1836,6 +1836,21 @@ pub const Type = extern union { | ... | @@ -1836,6 +1836,21 @@ pub const Type = extern union { |
| 1836 | .inferred_alloc_const => unreachable, | 1836 | .inferred_alloc_const => unreachable, |
| 1837 | .inferred_alloc_mut => unreachable, | 1837 | .inferred_alloc_mut => unreachable, |
| 1838 | .generic_poison => unreachable, | 1838 | .generic_poison => unreachable, |
| 1839 | .var_args_param => unreachable, | ||
| 1840 | .bound_fn => unreachable, | ||
| 1841 | |||
| 1842 | // TODO get rid of these Type.Tag values. | ||
| 1843 | .atomic_order => unreachable, | ||
| 1844 | .atomic_rmw_op => unreachable, | ||
| 1845 | .calling_convention => unreachable, | ||
| 1846 | .address_space => unreachable, | ||
| 1847 | .float_mode => unreachable, | ||
| 1848 | .reduce_op => unreachable, | ||
| 1849 | .call_options => unreachable, | ||
| 1850 | .prefetch_options => unreachable, | ||
| 1851 | .export_options => unreachable, | ||
| 1852 | .extern_options => unreachable, | ||
| 1853 | .type_info => unreachable, | ||
| 1839 | 1854 | ||
| 1840 | .u1, | 1855 | .u1, |
| 1841 | .u8, | 1856 | .u8, |
| ... | @@ -1873,39 +1888,44 @@ pub const Type = extern union { | ... | @@ -1873,39 +1888,44 @@ pub const Type = extern union { |
| 1873 | .comptime_int, | 1888 | .comptime_int, |
| 1874 | .comptime_float, | 1889 | .comptime_float, |
| 1875 | .noreturn, | 1890 | .noreturn, |
| 1876 | .var_args_param, | ||
| 1877 | .bound_fn, | ||
| 1878 | => return maybeDupe(@tagName(t), ally, is_arena), | 1891 | => return maybeDupe(@tagName(t), ally, is_arena), |
| 1879 | 1892 | ||
| 1880 | .enum_literal => return maybeDupe("@Type(.EnumLiteral)", ally, is_arena), | 1893 | .enum_literal => return maybeDupe("@TypeOf(.enum_literal)", ally, is_arena), |
| 1881 | .@"null" => return maybeDupe("@Type(.Null)", ally, is_arena), | 1894 | .@"null" => return maybeDupe("@TypeOf(null)", ally, is_arena), |
| 1882 | .@"undefined" => return maybeDupe("@Type(.Undefined)", ally, is_arena), | 1895 | .@"undefined" => return maybeDupe("@TypeOf(undefined)", ally, is_arena), |
| 1896 | .empty_struct_literal => return maybeDupe("@TypeOf(.{})", ally, is_arena), | ||
| 1883 | 1897 | ||
| 1884 | .empty_struct, .empty_struct_literal => return maybeDupe("struct {}", ally, is_arena), | 1898 | .empty_struct => { |
| 1899 | const namespace = ty.castTag(.empty_struct).?.data; | ||
| 1900 | var buffer = std.ArrayList(u8).init(ally); | ||
| 1901 | defer buffer.deinit(); | ||
| 1902 | try namespace.renderFullyQualifiedName("", buffer.writer()); | ||
| 1903 | return buffer.toOwnedSliceSentinel(0); | ||
| 1904 | }, | ||
| 1885 | 1905 | ||
| 1886 | .@"struct" => { | 1906 | .@"struct" => { |
| 1887 | const struct_obj = ty.castTag(.@"struct").?.data; | 1907 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 1888 | return try ally.dupeZ(u8, std.mem.sliceTo(struct_obj.owner_decl.name, 0)); | 1908 | return try struct_obj.owner_decl.getFullyQualifiedName(ally); |
| 1889 | }, | 1909 | }, |
| 1890 | .@"union", .union_tagged => { | 1910 | .@"union", .union_tagged => { |
| 1891 | const union_obj = ty.cast(Payload.Union).?.data; | 1911 | const union_obj = ty.cast(Payload.Union).?.data; |
| 1892 | return try ally.dupeZ(u8, std.mem.sliceTo(union_obj.owner_decl.name, 0)); | 1912 | return try union_obj.owner_decl.getFullyQualifiedName(ally); |
| 1893 | }, | 1913 | }, |
| 1894 | .enum_full, .enum_nonexhaustive => { | 1914 | .enum_full, .enum_nonexhaustive => { |
| 1895 | const enum_full = ty.cast(Payload.EnumFull).?.data; | 1915 | const enum_full = ty.cast(Payload.EnumFull).?.data; |
| 1896 | return try ally.dupeZ(u8, std.mem.sliceTo(enum_full.owner_decl.name, 0)); | 1916 | return try enum_full.owner_decl.getFullyQualifiedName(ally); |
| 1897 | }, | 1917 | }, |
| 1898 | .enum_simple => { | 1918 | .enum_simple => { |
| 1899 | const enum_simple = ty.castTag(.enum_simple).?.data; | 1919 | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 1900 | return try ally.dupeZ(u8, std.mem.sliceTo(enum_simple.owner_decl.name, 0)); | 1920 | return try enum_simple.owner_decl.getFullyQualifiedName(ally); |
| 1901 | }, | 1921 | }, |
| 1902 | .enum_numbered => { | 1922 | .enum_numbered => { |
| 1903 | const enum_numbered = ty.castTag(.enum_numbered).?.data; | 1923 | const enum_numbered = ty.castTag(.enum_numbered).?.data; |
| 1904 | return try ally.dupeZ(u8, std.mem.sliceTo(enum_numbered.owner_decl.name, 0)); | 1924 | return try enum_numbered.owner_decl.getFullyQualifiedName(ally); |
| 1905 | }, | 1925 | }, |
| 1906 | .@"opaque" => { | 1926 | .@"opaque" => { |
| 1907 | const opaque_obj = ty.cast(Payload.Opaque).?.data; | 1927 | const opaque_obj = ty.cast(Payload.Opaque).?.data; |
| 1908 | return try ally.dupeZ(u8, std.mem.sliceTo(opaque_obj.owner_decl.name, 0)); | 1928 | return try opaque_obj.owner_decl.getFullyQualifiedName(ally); |
| 1909 | }, | 1929 | }, |
| 1910 | 1930 | ||
| 1911 | .anyerror_void_error_union => return maybeDupe("anyerror!void", ally, is_arena), | 1931 | .anyerror_void_error_union => return maybeDupe("anyerror!void", ally, is_arena), |
| ... | @@ -1919,21 +1939,79 @@ pub const Type = extern union { | ... | @@ -1919,21 +1939,79 @@ pub const Type = extern union { |
| 1919 | .manyptr_u8 => return maybeDupe("[*]u8", ally, is_arena), | 1939 | .manyptr_u8 => return maybeDupe("[*]u8", ally, is_arena), |
| 1920 | .manyptr_const_u8 => return maybeDupe("[*]const u8", ally, is_arena), | 1940 | .manyptr_const_u8 => return maybeDupe("[*]const u8", ally, is_arena), |
| 1921 | .manyptr_const_u8_sentinel_0 => return maybeDupe("[*:0]const u8", ally, is_arena), | 1941 | .manyptr_const_u8_sentinel_0 => return maybeDupe("[*:0]const u8", ally, is_arena), |
| 1922 | .atomic_order => return maybeDupe("AtomicOrder", ally, is_arena), | 1942 | |
| 1923 | .atomic_rmw_op => return maybeDupe("AtomicRmwOp", ally, is_arena), | 1943 | .error_set_inferred => { |
| 1924 | .calling_convention => return maybeDupe("CallingConvention", ally, is_arena), | 1944 | const func = ty.castTag(.error_set_inferred).?.data.func; |
| 1925 | .address_space => return maybeDupe("AddressSpace", ally, is_arena), | 1945 | |
| 1926 | .float_mode => return maybeDupe("FloatMode", ally, is_arena), | 1946 | var buf = std.ArrayList(u8).init(ally); |
| 1927 | .reduce_op => return maybeDupe("ReduceOp", ally, is_arena), | 1947 | defer buf.deinit(); |
| 1928 | .call_options => return maybeDupe("CallOptions", ally, is_arena), | 1948 | try buf.appendSlice("@typeInfo(@typeInfo(@TypeOf("); |
| 1929 | .prefetch_options => return maybeDupe("PrefetchOptions", ally, is_arena), | 1949 | try func.owner_decl.renderFullyQualifiedName(buf.writer()); |
| 1930 | .export_options => return maybeDupe("ExportOptions", ally, is_arena), | 1950 | try buf.appendSlice(")).Fn.return_type.?).ErrorUnion.error_set"); |
| 1931 | .extern_options => return maybeDupe("ExternOptions", ally, is_arena), | 1951 | return try buf.toOwnedSliceSentinel(0); |
| 1932 | .type_info => return maybeDupe("Type", ally, is_arena), | 1952 | }, |
| 1953 | |||
| 1954 | .function => { | ||
| 1955 | const fn_info = ty.fnInfo(); | ||
| 1956 | var buf = std.ArrayList(u8).init(ally); | ||
| 1957 | defer buf.deinit(); | ||
| 1958 | try buf.appendSlice("fn("); | ||
| 1959 | for (fn_info.param_types) |param_type, i| { | ||
| 1960 | if (i != 0) try buf.appendSlice(", "); | ||
| 1961 | const param_name = try param_type.nameAllocAdvanced(ally, is_arena); | ||
| 1962 | defer if (!is_arena) ally.free(param_name); | ||
| 1963 | try buf.appendSlice(param_name); | ||
| 1964 | } | ||
| 1965 | if (fn_info.is_var_args) { | ||
| 1966 | if (fn_info.param_types.len != 0) { | ||
| 1967 | try buf.appendSlice(", "); | ||
| 1968 | } | ||
| 1969 | try buf.appendSlice("..."); | ||
| 1970 | } | ||
| 1971 | try buf.appendSlice(") "); | ||
| 1972 | if (fn_info.cc != .Unspecified) { | ||
| 1973 | try buf.appendSlice("callconv(."); | ||
| 1974 | try buf.appendSlice(@tagName(fn_info.cc)); | ||
| 1975 | try buf.appendSlice(") "); | ||
| 1976 | } | ||
| 1977 | if (fn_info.alignment != 0) { | ||
| 1978 | try buf.writer().print("align({d}) ", .{fn_info.alignment}); | ||
| 1979 | } | ||
| 1980 | { | ||
| 1981 | const ret_ty_name = try fn_info.return_type.nameAllocAdvanced(ally, is_arena); | ||
| 1982 | defer if (!is_arena) ally.free(ret_ty_name); | ||
| 1983 | try buf.appendSlice(ret_ty_name); | ||
| 1984 | } | ||
| 1985 | return try buf.toOwnedSliceSentinel(0); | ||
| 1986 | }, | ||
| 1987 | |||
| 1988 | .error_union => { | ||
| 1989 | const error_union = ty.castTag(.error_union).?.data; | ||
| 1990 | |||
| 1991 | var buf = std.ArrayList(u8).init(ally); | ||
| 1992 | defer buf.deinit(); | ||
| 1993 | |||
| 1994 | { | ||
| 1995 | const err_set_ty_name = try error_union.error_set.nameAllocAdvanced(ally, is_arena); | ||
| 1996 | defer if (!is_arena) ally.free(err_set_ty_name); | ||
| 1997 | try buf.appendSlice(err_set_ty_name); | ||
| 1998 | } | ||
| 1999 | |||
| 2000 | try buf.appendSlice("!"); | ||
| 2001 | |||
| 2002 | { | ||
| 2003 | const payload_ty_name = try error_union.payload.nameAllocAdvanced(ally, is_arena); | ||
| 2004 | defer if (!is_arena) ally.free(payload_ty_name); | ||
| 2005 | try buf.appendSlice(payload_ty_name); | ||
| 2006 | } | ||
| 2007 | |||
| 2008 | return try buf.toOwnedSliceSentinel(0); | ||
| 2009 | }, | ||
| 1933 | 2010 | ||
| 1934 | else => { | 2011 | else => { |
| 1935 | // TODO this is wasteful and also an incorrect implementation of `@typeName` | 2012 | // TODO this is wasteful and also an incorrect implementation of `@typeName` |
| 1936 | var buf = std.ArrayList(u8).init(ally); | 2013 | var buf = std.ArrayList(u8).init(ally); |
| 2014 | defer buf.deinit(); | ||
| 1937 | try buf.writer().print("{}", .{ty}); | 2015 | try buf.writer().print("{}", .{ty}); |
| 1938 | return try buf.toOwnedSliceSentinel(0); | 2016 | return try buf.toOwnedSliceSentinel(0); |
| 1939 | }, | 2017 | }, |
test/behavior.zig+1-1| ... | @@ -120,6 +120,7 @@ test { | ... | @@ -120,6 +120,7 @@ test { |
| 120 | _ = @import("behavior/tuple.zig"); | 120 | _ = @import("behavior/tuple.zig"); |
| 121 | _ = @import("behavior/type.zig"); | 121 | _ = @import("behavior/type.zig"); |
| 122 | _ = @import("behavior/type_info.zig"); | 122 | _ = @import("behavior/type_info.zig"); |
| 123 | _ = @import("behavior/typename.zig"); | ||
| 123 | _ = @import("behavior/undefined.zig"); | 124 | _ = @import("behavior/undefined.zig"); |
| 124 | _ = @import("behavior/underscore.zig"); | 125 | _ = @import("behavior/underscore.zig"); |
| 125 | _ = @import("behavior/union.zig"); | 126 | _ = @import("behavior/union.zig"); |
| ... | @@ -179,7 +180,6 @@ test { | ... | @@ -179,7 +180,6 @@ test { |
| 179 | _ = @import("behavior/bugs/7027.zig"); | 180 | _ = @import("behavior/bugs/7027.zig"); |
| 180 | _ = @import("behavior/select.zig"); | 181 | _ = @import("behavior/select.zig"); |
| 181 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); | 182 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); |
| 182 | _ = @import("behavior/typename.zig"); | ||
| 183 | } | 183 | } |
| 184 | } | 184 | } |
| 185 | } | 185 | } |
test/behavior/basic.zig+11-4| ... | @@ -199,11 +199,18 @@ const OpaqueA = opaque {}; | ... | @@ -199,11 +199,18 @@ const OpaqueA = opaque {}; |
| 199 | const OpaqueB = opaque {}; | 199 | const OpaqueB = opaque {}; |
| 200 | 200 | ||
| 201 | test "opaque types" { | 201 | test "opaque types" { |
| 202 | try expect(*OpaqueA != *OpaqueB); | 202 | if (builtin.zig_backend == .stage1) { |
| 203 | if (builtin.zig_backend == .stage1) { // TODO make this pass for stage2 | 203 | // stage1 gets the type names wrong |
| 204 | try expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); | 204 | return error.SkipZigTest; |
| 205 | try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); | ||
| 206 | } | 205 | } |
| 206 | |||
| 207 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 208 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 209 | |||
| 210 | try expect(*OpaqueA != *OpaqueB); | ||
| 211 | |||
| 212 | try expect(mem.eql(u8, @typeName(OpaqueA), "behavior.basic.OpaqueA")); | ||
| 213 | try expect(mem.eql(u8, @typeName(OpaqueB), "behavior.basic.OpaqueB")); | ||
| 207 | } | 214 | } |
| 208 | 215 | ||
| 209 | const global_a: i32 = 1234; | 216 | const global_a: i32 = 1234; |
test/behavior/bugs/3779.zig+3-2| ... | @@ -28,9 +28,10 @@ const type_name = @typeName(TestType); | ... | @@ -28,9 +28,10 @@ const type_name = @typeName(TestType); |
| 28 | const ptr_type_name: [*:0]const u8 = type_name; | 28 | const ptr_type_name: [*:0]const u8 = type_name; |
| 29 | 29 | ||
| 30 | test "@typeName() returns a string literal" { | 30 | test "@typeName() returns a string literal" { |
| 31 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong | ||
| 31 | try std.testing.expectEqual(*const [type_name.len:0]u8, @TypeOf(type_name)); | 32 | try std.testing.expectEqual(*const [type_name.len:0]u8, @TypeOf(type_name)); |
| 32 | try std.testing.expectEqualStrings("TestType", type_name); | 33 | try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", type_name); |
| 33 | try std.testing.expectEqualStrings("TestType", ptr_type_name[0..type_name.len]); | 34 | try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", ptr_type_name[0..type_name.len]); |
| 34 | } | 35 | } |
| 35 | 36 | ||
| 36 | const actual_contents = @embedFile("3779_file_to_embed.txt"); | 37 | const actual_contents = @embedFile("3779_file_to_embed.txt"); |
test/behavior/typename.zig+172-32| ... | @@ -1,6 +1,8 @@ | ... | @@ -1,6 +1,8 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 1 | const std = @import("std"); | 2 | const std = @import("std"); |
| 2 | const expect = std.testing.expect; | 3 | const expect = std.testing.expect; |
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | 4 | const expectEqualStrings = std.testing.expectEqualStrings; |
| 5 | const expectStringStartsWith = std.testing.expectStringStartsWith; | ||
| 4 | 6 | ||
| 5 | // Most tests here can be comptime but use runtime so that a stacktrace | 7 | // Most tests here can be comptime but use runtime so that a stacktrace |
| 6 | // can show failure location. | 8 | // can show failure location. |
| ... | @@ -9,50 +11,124 @@ const expectEqualSlices = std.testing.expectEqualSlices; | ... | @@ -9,50 +11,124 @@ const expectEqualSlices = std.testing.expectEqualSlices; |
| 9 | // root file. Running a test against this file as root will result in | 11 | // root file. Running a test against this file as root will result in |
| 10 | // failures. | 12 | // failures. |
| 11 | 13 | ||
| 12 | // CAUTION: this test is source-location sensitive. | 14 | test "anon fn param" { |
| 13 | test "anon fn param - source-location sensitive" { | 15 | if (builtin.zig_backend == .stage1) { |
| 16 | // stage1 uses line/column for the names but we're moving away from that for | ||
| 17 | // incremental compilation purposes. | ||
| 18 | return error.SkipZigTest; | ||
| 19 | } | ||
| 20 | |||
| 21 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 22 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 23 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 24 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 25 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 26 | |||
| 14 | // https://github.com/ziglang/zig/issues/9339 | 27 | // https://github.com/ziglang/zig/issues/9339 |
| 15 | try expectEqualSlices(u8, @typeName(TypeFromFn(struct {})), "behavior.typename.TypeFromFn(behavior.typename.struct:15:52)"); | 28 | try expectEqualStringsIgnoreDigits( |
| 16 | try expectEqualSlices(u8, @typeName(TypeFromFn(union { unused: u8 })), "behavior.typename.TypeFromFn(behavior.typename.union:16:52)"); | 29 | "behavior.typename.TypeFromFn(behavior.typename.test.anon fn param__struct_0)", |
| 17 | try expectEqualSlices(u8, @typeName(TypeFromFn(enum { unused })), "behavior.typename.TypeFromFn(behavior.typename.enum:17:52)"); | 30 | @typeName(TypeFromFn(struct {})), |
| 31 | ); | ||
| 32 | try expectEqualStringsIgnoreDigits( | ||
| 33 | "behavior.typename.TypeFromFn(behavior.typename.test.anon fn param__union_0)", | ||
| 34 | @typeName(TypeFromFn(union { unused: u8 })), | ||
| 35 | ); | ||
| 36 | try expectEqualStringsIgnoreDigits( | ||
| 37 | "behavior.typename.TypeFromFn(behavior.typename.test.anon fn param__enum_0)", | ||
| 38 | @typeName(TypeFromFn(enum { unused })), | ||
| 39 | ); | ||
| 18 | 40 | ||
| 19 | try expectEqualSlices( | 41 | try expectEqualStringsIgnoreDigits( |
| 20 | u8, | 42 | "behavior.typename.TypeFromFnB(behavior.typename.test.anon fn param__struct_0,behavior.typename.test.anon fn param__union_0,behavior.typename.test.anon fn param__enum_0)", |
| 21 | @typeName(TypeFromFn3(struct {}, union { unused: u8 }, enum { unused })), | 43 | @typeName(TypeFromFnB(struct {}, union { unused: u8 }, enum { unused })), |
| 22 | "behavior.typename.TypeFromFn3(behavior.typename.struct:21:31,behavior.typename.union:21:42,behavior.typename.enum:21:64)", | ||
| 23 | ); | 44 | ); |
| 24 | } | 45 | } |
| 25 | 46 | ||
| 26 | // CAUTION: this test is source-location sensitive. | ||
| 27 | test "anon field init" { | 47 | test "anon field init" { |
| 48 | if (builtin.zig_backend == .stage1) { | ||
| 49 | // stage1 uses line/column for the names but we're moving away from that for | ||
| 50 | // incremental compilation purposes. | ||
| 51 | return error.SkipZigTest; | ||
| 52 | } | ||
| 53 | |||
| 54 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 55 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 56 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 57 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 58 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 59 | |||
| 28 | const Foo = .{ | 60 | const Foo = .{ |
| 29 | .T1 = struct {}, | 61 | .T1 = struct {}, |
| 30 | .T2 = union { unused: u8 }, | 62 | .T2 = union { unused: u8 }, |
| 31 | .T3 = enum { unused }, | 63 | .T3 = enum { unused }, |
| 32 | }; | 64 | }; |
| 33 | 65 | ||
| 34 | try expectEqualSlices(u8, @typeName(Foo.T1), "behavior.typename.struct:29:15"); | 66 | try expectEqualStringsIgnoreDigits( |
| 35 | try expectEqualSlices(u8, @typeName(Foo.T2), "behavior.typename.union:30:15"); | 67 | "behavior.typename.test.anon field init__struct_0", |
| 36 | try expectEqualSlices(u8, @typeName(Foo.T3), "behavior.typename.enum:31:15"); | 68 | @typeName(Foo.T1), |
| 69 | ); | ||
| 70 | try expectEqualStringsIgnoreDigits( | ||
| 71 | "behavior.typename.test.anon field init__union_0", | ||
| 72 | @typeName(Foo.T2), | ||
| 73 | ); | ||
| 74 | try expectEqualStringsIgnoreDigits( | ||
| 75 | "behavior.typename.test.anon field init__enum_0", | ||
| 76 | @typeName(Foo.T3), | ||
| 77 | ); | ||
| 37 | } | 78 | } |
| 38 | 79 | ||
| 39 | test "basic" { | 80 | test "basic" { |
| 40 | try expectEqualSlices(u8, @typeName(i64), "i64"); | 81 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 41 | try expectEqualSlices(u8, @typeName(*usize), "*usize"); | 82 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 42 | try expectEqualSlices(u8, @typeName([]u8), "[]u8"); | 83 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 84 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 85 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 86 | |||
| 87 | try expectEqualStrings(@typeName(i64), "i64"); | ||
| 88 | try expectEqualStrings(@typeName(*usize), "*usize"); | ||
| 89 | try expectEqualStrings(@typeName([]u8), "[]u8"); | ||
| 43 | } | 90 | } |
| 44 | 91 | ||
| 45 | test "top level decl" { | 92 | test "top level decl" { |
| 46 | try expectEqualSlices(u8, @typeName(A_Struct), "A_Struct"); | 93 | if (builtin.zig_backend == .stage1) { |
| 47 | try expectEqualSlices(u8, @typeName(A_Union), "A_Union"); | 94 | // stage1 fails to return fully qualified namespaces. |
| 48 | try expectEqualSlices(u8, @typeName(A_Enum), "A_Enum"); | 95 | return error.SkipZigTest; |
| 96 | } | ||
| 97 | |||
| 98 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 99 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 100 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 101 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 102 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 103 | |||
| 104 | try expectEqualStrings( | ||
| 105 | "behavior.typename.A_Struct", | ||
| 106 | @typeName(A_Struct), | ||
| 107 | ); | ||
| 108 | try expectEqualStrings( | ||
| 109 | "behavior.typename.A_Union", | ||
| 110 | @typeName(A_Union), | ||
| 111 | ); | ||
| 112 | try expectEqualStrings( | ||
| 113 | "behavior.typename.A_Enum", | ||
| 114 | @typeName(A_Enum), | ||
| 115 | ); | ||
| 49 | 116 | ||
| 50 | // regular fn, without error | 117 | // regular fn, without error |
| 51 | try expectEqualSlices(u8, @typeName(@TypeOf(regular)), "fn() void"); | 118 | try expectEqualStrings( |
| 119 | "fn() void", | ||
| 120 | @typeName(@TypeOf(regular)), | ||
| 121 | ); | ||
| 52 | // regular fn inside struct, with error | 122 | // regular fn inside struct, with error |
| 53 | try expectEqualSlices(u8, @typeName(@TypeOf(B.doTest)), "fn() @typeInfo(@typeInfo(@TypeOf(behavior.typename.B.doTest)).Fn.return_type.?).ErrorUnion.error_set!void"); | 123 | try expectEqualStrings( |
| 124 | "fn() @typeInfo(@typeInfo(@TypeOf(behavior.typename.B.doTest)).Fn.return_type.?).ErrorUnion.error_set!void", | ||
| 125 | @typeName(@TypeOf(B.doTest)), | ||
| 126 | ); | ||
| 54 | // generic fn | 127 | // generic fn |
| 55 | try expectEqualSlices(u8, @typeName(@TypeOf(TypeFromFn)), "fn(type) anytype"); | 128 | try expectEqualStrings( |
| 129 | "fn(type) type", | ||
| 130 | @typeName(@TypeOf(TypeFromFn)), | ||
| 131 | ); | ||
| 56 | } | 132 | } |
| 57 | 133 | ||
| 58 | const A_Struct = struct {}; | 134 | const A_Struct = struct {}; |
| ... | @@ -66,6 +142,17 @@ const A_Enum = enum { | ... | @@ -66,6 +142,17 @@ const A_Enum = enum { |
| 66 | fn regular() void {} | 142 | fn regular() void {} |
| 67 | 143 | ||
| 68 | test "fn body decl" { | 144 | test "fn body decl" { |
| 145 | if (builtin.zig_backend == .stage1) { | ||
| 146 | // stage1 fails to return fully qualified namespaces. | ||
| 147 | return error.SkipZigTest; | ||
| 148 | } | ||
| 149 | |||
| 150 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 151 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 152 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 153 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 154 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 155 | |||
| 69 | try B.doTest(); | 156 | try B.doTest(); |
| 70 | } | 157 | } |
| 71 | 158 | ||
| ... | @@ -79,20 +166,50 @@ const B = struct { | ... | @@ -79,20 +166,50 @@ const B = struct { |
| 79 | unused, | 166 | unused, |
| 80 | }; | 167 | }; |
| 81 | 168 | ||
| 82 | try expectEqualSlices(u8, @typeName(B_Struct), "B_Struct"); | 169 | try expectEqualStringsIgnoreDigits( |
| 83 | try expectEqualSlices(u8, @typeName(B_Union), "B_Union"); | 170 | "behavior.typename.B.doTest__struct_0", |
| 84 | try expectEqualSlices(u8, @typeName(B_Enum), "B_Enum"); | 171 | @typeName(B_Struct), |
| 172 | ); | ||
| 173 | try expectEqualStringsIgnoreDigits( | ||
| 174 | "behavior.typename.B.doTest__union_0", | ||
| 175 | @typeName(B_Union), | ||
| 176 | ); | ||
| 177 | try expectEqualStringsIgnoreDigits( | ||
| 178 | "behavior.typename.B.doTest__enum_0", | ||
| 179 | @typeName(B_Enum), | ||
| 180 | ); | ||
| 85 | } | 181 | } |
| 86 | }; | 182 | }; |
| 87 | 183 | ||
| 88 | test "fn param" { | 184 | test "fn param" { |
| 185 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | ||
| 186 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 187 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 189 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 190 | |||
| 89 | // https://github.com/ziglang/zig/issues/675 | 191 | // https://github.com/ziglang/zig/issues/675 |
| 90 | try expectEqualSlices(u8, @typeName(TypeFromFn(u8)), "behavior.typename.TypeFromFn(u8)"); | 192 | try expectEqualStrings( |
| 91 | try expectEqualSlices(u8, @typeName(TypeFromFn(A_Struct)), "behavior.typename.TypeFromFn(behavior.typename.A_Struct)"); | 193 | "behavior.typename.TypeFromFn(u8)", |
| 92 | try expectEqualSlices(u8, @typeName(TypeFromFn(A_Union)), "behavior.typename.TypeFromFn(behavior.typename.A_Union)"); | 194 | @typeName(TypeFromFn(u8)), |
| 93 | try expectEqualSlices(u8, @typeName(TypeFromFn(A_Enum)), "behavior.typename.TypeFromFn(behavior.typename.A_Enum)"); | 195 | ); |
| 196 | try expectEqualStrings( | ||
| 197 | "behavior.typename.TypeFromFn(behavior.typename.A_Struct)", | ||
| 198 | @typeName(TypeFromFn(A_Struct)), | ||
| 199 | ); | ||
| 200 | try expectEqualStrings( | ||
| 201 | "behavior.typename.TypeFromFn(behavior.typename.A_Union)", | ||
| 202 | @typeName(TypeFromFn(A_Union)), | ||
| 203 | ); | ||
| 204 | try expectEqualStrings( | ||
| 205 | "behavior.typename.TypeFromFn(behavior.typename.A_Enum)", | ||
| 206 | @typeName(TypeFromFn(A_Enum)), | ||
| 207 | ); | ||
| 94 | 208 | ||
| 95 | try expectEqualSlices(u8, @typeName(TypeFromFn2(u8, bool)), "behavior.typename.TypeFromFn2(u8,bool)"); | 209 | try expectEqualStrings( |
| 210 | "behavior.typename.TypeFromFn2(u8,bool)", | ||
| 211 | @typeName(TypeFromFn2(u8, bool)), | ||
| 212 | ); | ||
| 96 | } | 213 | } |
| 97 | 214 | ||
| 98 | fn TypeFromFn(comptime T: type) type { | 215 | fn TypeFromFn(comptime T: type) type { |
| ... | @@ -106,9 +223,32 @@ fn TypeFromFn2(comptime T1: type, comptime T2: type) type { | ... | @@ -106,9 +223,32 @@ fn TypeFromFn2(comptime T1: type, comptime T2: type) type { |
| 106 | return struct {}; | 223 | return struct {}; |
| 107 | } | 224 | } |
| 108 | 225 | ||
| 109 | fn TypeFromFn3(comptime T1: type, comptime T2: type, comptime T3: type) type { | 226 | fn TypeFromFnB(comptime T1: type, comptime T2: type, comptime T3: type) type { |
| 110 | _ = T1; | 227 | _ = T1; |
| 111 | _ = T2; | 228 | _ = T2; |
| 112 | _ = T3; | 229 | _ = T3; |
| 113 | return struct {}; | 230 | return struct {}; |
| 114 | } | 231 | } |
| 232 | |||
| 233 | /// Replaces integers in `actual` with '0' before doing the test. | ||
| 234 | pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8) !void { | ||
| 235 | var actual_buf: [1024]u8 = undefined; | ||
| 236 | var actual_i: usize = 0; | ||
| 237 | var last_digit = false; | ||
| 238 | for (actual) |byte| { | ||
| 239 | switch (byte) { | ||
| 240 | '0'...'9' => { | ||
| 241 | if (last_digit) continue; | ||
| 242 | last_digit = true; | ||
| 243 | actual_buf[actual_i] = '0'; | ||
| 244 | actual_i += 1; | ||
| 245 | }, | ||
| 246 | else => { | ||
| 247 | last_digit = false; | ||
| 248 | actual_buf[actual_i] = byte; | ||
| 249 | actual_i += 1; | ||
| 250 | }, | ||
| 251 | } | ||
| 252 | } | ||
| 253 | return expectEqualStrings(expected, actual_buf[0..actual_i]); | ||
| 254 | } |
test/behavior/undefined.zig+5-1| ... | @@ -77,8 +77,12 @@ test "assign undefined to struct with method" { | ... | @@ -77,8 +77,12 @@ test "assign undefined to struct with method" { |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | test "type name of undefined" { | 79 | test "type name of undefined" { |
| 80 | if (builtin.zig_backend == .stage1) { | ||
| 81 | // stage1 gets the type name wrong | ||
| 82 | return error.SkipZigTest; | ||
| 83 | } | ||
| 80 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 84 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 81 | 85 | ||
| 82 | const x = undefined; | 86 | const x = undefined; |
| 83 | try expect(mem.eql(u8, @typeName(@TypeOf(x)), "@Type(.Undefined)")); | 87 | try expect(mem.eql(u8, @typeName(@TypeOf(x)), "@TypeOf(undefined)")); |
| 84 | } | 88 | } |