authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-18 00:12:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-18 00:12:22-07:00
logf3f5a5d05b7056aceb408b701613242d053019ab
treeacb912950d734b0c25b38c1ae82a8558d1313057
parent69d78bdae4a5d0ec5877add5936ae8e9daf09140

stage2: improve `@typeName`

* 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" {
97029702 <p>
97039703 This function returns the string representation of a type, as
97049704 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.
97059707 </p>
9706
97079708 {#header_close#}
97089709
97099710 {#header_open|@TypeOf#}
lib/std/special/test_runner.zig+3-1
......@@ -23,7 +23,9 @@ fn processArgs() void {
2323}
2424
2525pub 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 {
2729 return main2() catch @panic("test failure");
2830 }
2931 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 {
445445 }
446446}
447447
448pub 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
448468pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) !void {
449469 if (std.mem.endsWith(u8, actual, expected_ends_with))
450470 return;
src/AstGen.zig+3
......@@ -6293,7 +6293,10 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
62936293 } else .{
62946294 .ty = try gz.addNodeExtended(.ret_type, node),
62956295 };
6296 const prev_anon_name_strategy = gz.anon_name_strategy;
6297 gz.anon_name_strategy = .func;
62966298 const operand = try reachableExpr(gz, scope, rl, operand_node, node);
6299 gz.anon_name_strategy = prev_anon_name_strategy;
62976300
62986301 switch (nodeMayEvalToError(tree, operand_node)) {
62996302 .never => {
src/Sema.zig+47-21
......@@ -1767,7 +1767,7 @@ fn zirStructDecl(
17671767 const struct_obj = try new_decl_arena_allocator.create(Module.Struct);
17681768 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
17691769 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");
17711771 const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
17721772 .ty = Type.type,
17731773 .val = struct_val,
......@@ -1796,28 +1796,54 @@ fn zirStructDecl(
17961796 return sema.analyzeDeclVal(block, src, new_decl);
17971797}
17981798
1799fn createTypeName(sema: *Sema, block: *Block, name_strategy: Zir.Inst.NameStrategy) ![:0]u8 {
1799fn createTypeName(
1800 sema: *Sema,
1801 block: *Block,
1802 name_strategy: Zir.Inst.NameStrategy,
1803 anon_prefix: []const u8,
1804) ![:0]u8 {
18001805 switch (name_strategy) {
18011806 .anon => {
18021807 // It would be neat to have "struct:line:column" but this name has
18031808 // to survive incremental updates, where it may have been shifted down
18041809 // or up to a different line, but unchanged, and thus not unnecessarily
18051810 // semantically analyzed.
1811 // This name is also used as the key in the parent namespace so it cannot be
1812 // renamed.
18061813 const name_index = sema.mod.getNextAnonNameIndex();
1807 return std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{
1808 block.src_decl.name, name_index,
1814 return std.fmt.allocPrintZ(sema.gpa, "{s}__{s}_{d}", .{
1815 block.src_decl.name, anon_prefix, name_index,
18091816 });
18101817 },
18111818 .parent => return sema.gpa.dupeZ(u8, mem.sliceTo(block.src_decl.name, 0)),
18121819 .func => {
1813 const name_index = sema.mod.getNextAnonNameIndex();
1814 const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{
1815 block.src_decl.name, name_index,
1816 });
1817 log.warn("TODO: handle NameStrategy.func correctly instead of using anon name '{s}'", .{
1818 name,
1819 });
1820 return name;
1820 const fn_info = sema.code.getFnInfo(sema.func.?.zir_body_inst);
1821 const zir_tags = sema.code.instructions.items(.tag);
1822
1823 var buf = std.ArrayList(u8).init(sema.gpa);
1824 defer buf.deinit();
1825 try buf.appendSlice(mem.sliceTo(block.src_decl.name, 0));
1826 try buf.appendSlice("(");
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);
18211847 },
18221848 }
18231849}
......@@ -1877,7 +1903,7 @@ fn zirEnumDecl(
18771903 };
18781904 const enum_ty = Type.initPayload(&enum_ty_payload.base);
18791905 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");
18811907 const new_decl = try mod.createAnonymousDeclNamed(block, .{
18821908 .ty = Type.type,
18831909 .val = enum_val,
......@@ -2088,7 +2114,7 @@ fn zirUnionDecl(
20882114 };
20892115 const union_ty = Type.initPayload(&union_payload.base);
20902116 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");
20922118 const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
20932119 .ty = Type.type,
20942120 .val = union_val,
......@@ -2156,7 +2182,7 @@ fn zirOpaqueDecl(
21562182 };
21572183 const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
21582184 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");
21602186 const new_decl = try mod.createAnonymousDeclNamed(block, .{
21612187 .ty = Type.type,
21622188 .val = opaque_val,
......@@ -2204,7 +2230,7 @@ fn zirErrorSetDecl(
22042230 const error_set = try new_decl_arena_allocator.create(Module.ErrorSet);
22052231 const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set);
22062232 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");
22082234 const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
22092235 .ty = Type.type,
22102236 .val = error_set_val,
......@@ -12697,7 +12723,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1269712723 };
1269812724 const enum_ty = Type.initPayload(&enum_ty_payload.base);
1269912725 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");
1270112727 const new_decl = try mod.createAnonymousDeclNamed(block, .{
1270212728 .ty = Type.type,
1270312729 .val = enum_val,
......@@ -12707,7 +12733,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1270712733
1270812734 enum_obj.* = .{
1270912735 .owner_decl = new_decl,
12710 .tag_ty = Type.initTag(.@"null"),
12736 .tag_ty = Type.@"null",
1271112737 .tag_ty_inferred = true,
1271212738 .fields = .{},
1271312739 .values = .{},
......@@ -12785,7 +12811,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1278512811 };
1278612812 const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
1278712813 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");
1278912815 const new_decl = try mod.createAnonymousDeclNamed(block, .{
1279012816 .ty = Type.type,
1279112817 .val = opaque_val,
......@@ -12836,7 +12862,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1283612862 };
1283712863 const union_ty = Type.initPayload(&union_payload.base);
1283812864 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");
1284012866 const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
1284112867 .ty = Type.type,
1284212868 .val = new_union_val,
......@@ -13001,7 +13027,7 @@ fn reifyStruct(
1300113027 const struct_obj = try new_decl_arena_allocator.create(Module.Struct);
1300213028 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
1300313029 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");
1300513031 const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
1300613032 .ty = Type.type,
1300713033 .val = new_struct_val,
src/type.zig+102-24
......@@ -1793,7 +1793,7 @@ pub const Type = extern union {
17931793 },
17941794 .error_set_inferred => {
17951795 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});
17971797 },
17981798 .error_set_merged => {
17991799 const names = ty.castTag(.error_set_merged).?.data.keys();
......@@ -1836,6 +1836,21 @@ pub const Type = extern union {
18361836 .inferred_alloc_const => unreachable,
18371837 .inferred_alloc_mut => unreachable,
18381838 .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,
18391854
18401855 .u1,
18411856 .u8,
......@@ -1873,39 +1888,44 @@ pub const Type = extern union {
18731888 .comptime_int,
18741889 .comptime_float,
18751890 .noreturn,
1876 .var_args_param,
1877 .bound_fn,
18781891 => return maybeDupe(@tagName(t), ally, is_arena),
18791892
1880 .enum_literal => return maybeDupe("@Type(.EnumLiteral)", ally, is_arena),
1881 .@"null" => return maybeDupe("@Type(.Null)", ally, is_arena),
1882 .@"undefined" => return maybeDupe("@Type(.Undefined)", ally, is_arena),
1893 .enum_literal => return maybeDupe("@TypeOf(.enum_literal)", ally, is_arena),
1894 .@"null" => return maybeDupe("@TypeOf(null)", ally, is_arena),
1895 .@"undefined" => return maybeDupe("@TypeOf(undefined)", ally, is_arena),
1896 .empty_struct_literal => return maybeDupe("@TypeOf(.{})", ally, is_arena),
18831897
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 },
18851905
18861906 .@"struct" => {
18871907 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);
18891909 },
18901910 .@"union", .union_tagged => {
18911911 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);
18931913 },
18941914 .enum_full, .enum_nonexhaustive => {
18951915 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);
18971917 },
18981918 .enum_simple => {
18991919 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);
19011921 },
19021922 .enum_numbered => {
19031923 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);
19051925 },
19061926 .@"opaque" => {
19071927 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);
19091929 },
19101930
19111931 .anyerror_void_error_union => return maybeDupe("anyerror!void", ally, is_arena),
......@@ -1919,21 +1939,79 @@ pub const Type = extern union {
19191939 .manyptr_u8 => return maybeDupe("[*]u8", ally, is_arena),
19201940 .manyptr_const_u8 => return maybeDupe("[*]const u8", ally, is_arena),
19211941 .manyptr_const_u8_sentinel_0 => return maybeDupe("[*:0]const u8", ally, is_arena),
1922 .atomic_order => return maybeDupe("AtomicOrder", ally, is_arena),
1923 .atomic_rmw_op => return maybeDupe("AtomicRmwOp", ally, is_arena),
1924 .calling_convention => return maybeDupe("CallingConvention", ally, is_arena),
1925 .address_space => return maybeDupe("AddressSpace", ally, is_arena),
1926 .float_mode => return maybeDupe("FloatMode", ally, is_arena),
1927 .reduce_op => return maybeDupe("ReduceOp", ally, is_arena),
1928 .call_options => return maybeDupe("CallOptions", ally, is_arena),
1929 .prefetch_options => return maybeDupe("PrefetchOptions", ally, is_arena),
1930 .export_options => return maybeDupe("ExportOptions", ally, is_arena),
1931 .extern_options => return maybeDupe("ExternOptions", ally, is_arena),
1932 .type_info => return maybeDupe("Type", ally, is_arena),
1942
1943 .error_set_inferred => {
1944 const func = ty.castTag(.error_set_inferred).?.data.func;
1945
1946 var buf = std.ArrayList(u8).init(ally);
1947 defer buf.deinit();
1948 try buf.appendSlice("@typeInfo(@typeInfo(@TypeOf(");
1949 try func.owner_decl.renderFullyQualifiedName(buf.writer());
1950 try buf.appendSlice(")).Fn.return_type.?).ErrorUnion.error_set");
1951 return try buf.toOwnedSliceSentinel(0);
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 },
19332010
19342011 else => {
19352012 // TODO this is wasteful and also an incorrect implementation of `@typeName`
19362013 var buf = std.ArrayList(u8).init(ally);
2014 defer buf.deinit();
19372015 try buf.writer().print("{}", .{ty});
19382016 return try buf.toOwnedSliceSentinel(0);
19392017 },
test/behavior.zig+1-1
......@@ -120,6 +120,7 @@ test {
120120 _ = @import("behavior/tuple.zig");
121121 _ = @import("behavior/type.zig");
122122 _ = @import("behavior/type_info.zig");
123 _ = @import("behavior/typename.zig");
123124 _ = @import("behavior/undefined.zig");
124125 _ = @import("behavior/underscore.zig");
125126 _ = @import("behavior/union.zig");
......@@ -179,7 +180,6 @@ test {
179180 _ = @import("behavior/bugs/7027.zig");
180181 _ = @import("behavior/select.zig");
181182 _ = @import("behavior/struct_contains_slice_of_itself.zig");
182 _ = @import("behavior/typename.zig");
183183 }
184184 }
185185 }
test/behavior/basic.zig+11-4
......@@ -199,11 +199,18 @@ const OpaqueA = opaque {};
199199const OpaqueB = opaque {};
200200
201201test "opaque types" {
202 try expect(*OpaqueA != *OpaqueB);
203 if (builtin.zig_backend == .stage1) { // TODO make this pass for stage2
204 try expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
205 try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
202 if (builtin.zig_backend == .stage1) {
203 // stage1 gets the type names wrong
204 return error.SkipZigTest;
206205 }
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"));
207214}
208215
209216const global_a: i32 = 1234;
test/behavior/bugs/3779.zig+3-2
......@@ -28,9 +28,10 @@ const type_name = @typeName(TestType);
2828const ptr_type_name: [*:0]const u8 = type_name;
2929
3030test "@typeName() returns a string literal" {
31 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
3132 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("TestType", ptr_type_name[0..type_name.len]);
33 try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", type_name);
34 try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", ptr_type_name[0..type_name.len]);
3435}
3536
3637const actual_contents = @embedFile("3779_file_to_embed.txt");
test/behavior/typename.zig+172-32
......@@ -1,6 +1,8 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const expect = std.testing.expect;
3const expectEqualSlices = std.testing.expectEqualSlices;
4const expectEqualStrings = std.testing.expectEqualStrings;
5const expectStringStartsWith = std.testing.expectStringStartsWith;
46
57// Most tests here can be comptime but use runtime so that a stacktrace
68// can show failure location.
......@@ -9,50 +11,124 @@ const expectEqualSlices = std.testing.expectEqualSlices;
911// root file. Running a test against this file as root will result in
1012// failures.
1113
12// CAUTION: this test is source-location sensitive.
13test "anon fn param - source-location sensitive" {
14test "anon fn param" {
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
1427 // https://github.com/ziglang/zig/issues/9339
15 try expectEqualSlices(u8, @typeName(TypeFromFn(struct {})), "behavior.typename.TypeFromFn(behavior.typename.struct:15:52)");
16 try expectEqualSlices(u8, @typeName(TypeFromFn(union { unused: u8 })), "behavior.typename.TypeFromFn(behavior.typename.union:16:52)");
17 try expectEqualSlices(u8, @typeName(TypeFromFn(enum { unused })), "behavior.typename.TypeFromFn(behavior.typename.enum:17:52)");
28 try expectEqualStringsIgnoreDigits(
29 "behavior.typename.TypeFromFn(behavior.typename.test.anon fn param__struct_0)",
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 );
1840
19 try expectEqualSlices(
20 u8,
21 @typeName(TypeFromFn3(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)",
41 try expectEqualStringsIgnoreDigits(
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)",
43 @typeName(TypeFromFnB(struct {}, union { unused: u8 }, enum { unused })),
2344 );
2445}
2546
26// CAUTION: this test is source-location sensitive.
2747test "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
2860 const Foo = .{
2961 .T1 = struct {},
3062 .T2 = union { unused: u8 },
3163 .T3 = enum { unused },
3264 };
3365
34 try expectEqualSlices(u8, @typeName(Foo.T1), "behavior.typename.struct:29:15");
35 try expectEqualSlices(u8, @typeName(Foo.T2), "behavior.typename.union:30:15");
36 try expectEqualSlices(u8, @typeName(Foo.T3), "behavior.typename.enum:31:15");
66 try expectEqualStringsIgnoreDigits(
67 "behavior.typename.test.anon field init__struct_0",
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 );
3778}
3879
3980test "basic" {
40 try expectEqualSlices(u8, @typeName(i64), "i64");
41 try expectEqualSlices(u8, @typeName(*usize), "*usize");
42 try expectEqualSlices(u8, @typeName([]u8), "[]u8");
81 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
82 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
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");
4390}
4491
4592test "top level decl" {
46 try expectEqualSlices(u8, @typeName(A_Struct), "A_Struct");
47 try expectEqualSlices(u8, @typeName(A_Union), "A_Union");
48 try expectEqualSlices(u8, @typeName(A_Enum), "A_Enum");
93 if (builtin.zig_backend == .stage1) {
94 // stage1 fails to return fully qualified namespaces.
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 );
49116
50117 // regular fn, without error
51 try expectEqualSlices(u8, @typeName(@TypeOf(regular)), "fn() void");
118 try expectEqualStrings(
119 "fn() void",
120 @typeName(@TypeOf(regular)),
121 );
52122 // 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 );
54127 // generic fn
55 try expectEqualSlices(u8, @typeName(@TypeOf(TypeFromFn)), "fn(type) anytype");
128 try expectEqualStrings(
129 "fn(type) type",
130 @typeName(@TypeOf(TypeFromFn)),
131 );
56132}
57133
58134const A_Struct = struct {};
......@@ -66,6 +142,17 @@ const A_Enum = enum {
66142fn regular() void {}
67143
68144test "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
69156 try B.doTest();
70157}
71158
......@@ -79,20 +166,50 @@ const B = struct {
79166 unused,
80167 };
81168
82 try expectEqualSlices(u8, @typeName(B_Struct), "B_Struct");
83 try expectEqualSlices(u8, @typeName(B_Union), "B_Union");
84 try expectEqualSlices(u8, @typeName(B_Enum), "B_Enum");
169 try expectEqualStringsIgnoreDigits(
170 "behavior.typename.B.doTest__struct_0",
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 );
85181 }
86182};
87183
88184test "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
89191 // https://github.com/ziglang/zig/issues/675
90 try expectEqualSlices(u8, @typeName(TypeFromFn(u8)), "behavior.typename.TypeFromFn(u8)");
91 try expectEqualSlices(u8, @typeName(TypeFromFn(A_Struct)), "behavior.typename.TypeFromFn(behavior.typename.A_Struct)");
92 try expectEqualSlices(u8, @typeName(TypeFromFn(A_Union)), "behavior.typename.TypeFromFn(behavior.typename.A_Union)");
93 try expectEqualSlices(u8, @typeName(TypeFromFn(A_Enum)), "behavior.typename.TypeFromFn(behavior.typename.A_Enum)");
192 try expectEqualStrings(
193 "behavior.typename.TypeFromFn(u8)",
194 @typeName(TypeFromFn(u8)),
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 );
94208
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 );
96213}
97214
98215fn TypeFromFn(comptime T: type) type {
......@@ -106,9 +223,32 @@ fn TypeFromFn2(comptime T1: type, comptime T2: type) type {
106223 return struct {};
107224}
108225
109fn TypeFromFn3(comptime T1: type, comptime T2: type, comptime T3: type) type {
226fn TypeFromFnB(comptime T1: type, comptime T2: type, comptime T3: type) type {
110227 _ = T1;
111228 _ = T2;
112229 _ = T3;
113230 return struct {};
114231}
232
233/// Replaces integers in `actual` with '0' before doing the test.
234pub 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" {
7777}
7878
7979test "type name of undefined" {
80 if (builtin.zig_backend == .stage1) {
81 // stage1 gets the type name wrong
82 return error.SkipZigTest;
83 }
8084 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8185
8286 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)"));
8488}