Commit f3f5a5d05b
Changed files (11)
lib
std
special
test
doc/langref.html.in
@@ -9702,8 +9702,9 @@ test "integer truncation" {
<p>
This function returns the string representation of a type, as
an array. It is equivalent to a string literal of the type name.
+ The returned type name is fully qualified with the parent namespace included
+ as part of the type name with a series of dots.
</p>
-
{#header_close#}
{#header_open|@TypeOf#}
lib/std/special/test_runner.zig
@@ -23,7 +23,9 @@ fn processArgs() void {
}
pub fn main() void {
- if (builtin.zig_backend != .stage1) {
+ if (builtin.zig_backend != .stage1 and
+ (builtin.zig_backend != .stage2_llvm or builtin.cpu.arch == .wasm32))
+ {
return main2() catch @panic("test failure");
}
if (builtin.zig_backend == .stage1) processArgs();
lib/std/testing.zig
@@ -445,6 +445,26 @@ pub fn expectEqualStrings(expected: []const u8, actual: []const u8) !void {
}
}
+pub fn expectStringStartsWith(actual: []const u8, expected_starts_with: []const u8) !void {
+ if (std.mem.startsWith(u8, actual, expected_starts_with))
+ return;
+
+ const shortened_actual = if (actual.len >= expected_starts_with.len)
+ actual[0..expected_starts_with.len]
+ else
+ actual;
+
+ print("\n====== expected to start with: =========\n", .{});
+ printWithVisibleNewlines(expected_starts_with);
+ print("\n====== instead ended with: ===========\n", .{});
+ printWithVisibleNewlines(shortened_actual);
+ print("\n========= full output: ==============\n", .{});
+ printWithVisibleNewlines(actual);
+ print("\n======================================\n", .{});
+
+ return error.TestExpectedStartsWith;
+}
+
pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) !void {
if (std.mem.endsWith(u8, actual, expected_ends_with))
return;
src/AstGen.zig
@@ -6293,7 +6293,10 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
} else .{
.ty = try gz.addNodeExtended(.ret_type, node),
};
+ const prev_anon_name_strategy = gz.anon_name_strategy;
+ gz.anon_name_strategy = .func;
const operand = try reachableExpr(gz, scope, rl, operand_node, node);
+ gz.anon_name_strategy = prev_anon_name_strategy;
switch (nodeMayEvalToError(tree, operand_node)) {
.never => {
src/Sema.zig
@@ -1767,7 +1767,7 @@ fn zirStructDecl(
const struct_obj = try new_decl_arena_allocator.create(Module.Struct);
const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);
- const type_name = try sema.createTypeName(block, small.name_strategy);
+ const type_name = try sema.createTypeName(block, small.name_strategy, "struct");
const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
.ty = Type.type,
.val = struct_val,
@@ -1796,28 +1796,54 @@ fn zirStructDecl(
return sema.analyzeDeclVal(block, src, new_decl);
}
-fn createTypeName(sema: *Sema, block: *Block, name_strategy: Zir.Inst.NameStrategy) ![:0]u8 {
+fn createTypeName(
+ sema: *Sema,
+ block: *Block,
+ name_strategy: Zir.Inst.NameStrategy,
+ anon_prefix: []const u8,
+) ![:0]u8 {
switch (name_strategy) {
.anon => {
// It would be neat to have "struct:line:column" but this name has
// to survive incremental updates, where it may have been shifted down
// or up to a different line, but unchanged, and thus not unnecessarily
// semantically analyzed.
+ // This name is also used as the key in the parent namespace so it cannot be
+ // renamed.
const name_index = sema.mod.getNextAnonNameIndex();
- return std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{
- block.src_decl.name, name_index,
+ return std.fmt.allocPrintZ(sema.gpa, "{s}__{s}_{d}", .{
+ block.src_decl.name, anon_prefix, name_index,
});
},
.parent => return sema.gpa.dupeZ(u8, mem.sliceTo(block.src_decl.name, 0)),
.func => {
- const name_index = sema.mod.getNextAnonNameIndex();
- const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{
- block.src_decl.name, name_index,
- });
- log.warn("TODO: handle NameStrategy.func correctly instead of using anon name '{s}'", .{
- name,
- });
- return name;
+ const fn_info = sema.code.getFnInfo(sema.func.?.zir_body_inst);
+ const zir_tags = sema.code.instructions.items(.tag);
+
+ var buf = std.ArrayList(u8).init(sema.gpa);
+ defer buf.deinit();
+ try buf.appendSlice(mem.sliceTo(block.src_decl.name, 0));
+ try buf.appendSlice("(");
+
+ var arg_i: usize = 0;
+ for (fn_info.param_body) |zir_inst| switch (zir_tags[zir_inst]) {
+ .param, .param_comptime, .param_anytype, .param_anytype_comptime => {
+ const arg = sema.inst_map.get(zir_inst).?;
+ // The comptime call code in analyzeCall already did this, so we're
+ // just repeating it here and it's guaranteed to work.
+ const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg) catch unreachable;
+
+ if (arg_i != 0) try buf.appendSlice(",");
+ try buf.writer().print("{}", .{arg_val});
+
+ arg_i += 1;
+ continue;
+ },
+ else => continue,
+ };
+
+ try buf.appendSlice(")");
+ return buf.toOwnedSliceSentinel(0);
},
}
}
@@ -1877,7 +1903,7 @@ fn zirEnumDecl(
};
const enum_ty = Type.initPayload(&enum_ty_payload.base);
const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
- const type_name = try sema.createTypeName(block, small.name_strategy);
+ const type_name = try sema.createTypeName(block, small.name_strategy, "enum");
const new_decl = try mod.createAnonymousDeclNamed(block, .{
.ty = Type.type,
.val = enum_val,
@@ -2088,7 +2114,7 @@ fn zirUnionDecl(
};
const union_ty = Type.initPayload(&union_payload.base);
const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
- const type_name = try sema.createTypeName(block, small.name_strategy);
+ const type_name = try sema.createTypeName(block, small.name_strategy, "union");
const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
.ty = Type.type,
.val = union_val,
@@ -2156,7 +2182,7 @@ fn zirOpaqueDecl(
};
const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty);
- const type_name = try sema.createTypeName(block, small.name_strategy);
+ const type_name = try sema.createTypeName(block, small.name_strategy, "opaque");
const new_decl = try mod.createAnonymousDeclNamed(block, .{
.ty = Type.type,
.val = opaque_val,
@@ -2204,7 +2230,7 @@ fn zirErrorSetDecl(
const error_set = try new_decl_arena_allocator.create(Module.ErrorSet);
const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set);
const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty);
- const type_name = try sema.createTypeName(block, name_strategy);
+ const type_name = try sema.createTypeName(block, name_strategy, "error");
const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
.ty = Type.type,
.val = error_set_val,
@@ -12697,7 +12723,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
};
const enum_ty = Type.initPayload(&enum_ty_payload.base);
const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
- const type_name = try sema.createTypeName(block, .anon);
+ const type_name = try sema.createTypeName(block, .anon, "enum");
const new_decl = try mod.createAnonymousDeclNamed(block, .{
.ty = Type.type,
.val = enum_val,
@@ -12707,7 +12733,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
enum_obj.* = .{
.owner_decl = new_decl,
- .tag_ty = Type.initTag(.@"null"),
+ .tag_ty = Type.@"null",
.tag_ty_inferred = true,
.fields = .{},
.values = .{},
@@ -12785,7 +12811,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
};
const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty);
- const type_name = try sema.createTypeName(block, .anon);
+ const type_name = try sema.createTypeName(block, .anon, "opaque");
const new_decl = try mod.createAnonymousDeclNamed(block, .{
.ty = Type.type,
.val = opaque_val,
@@ -12836,7 +12862,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
};
const union_ty = Type.initPayload(&union_payload.base);
const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
- const type_name = try sema.createTypeName(block, .anon);
+ const type_name = try sema.createTypeName(block, .anon, "union");
const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
.ty = Type.type,
.val = new_union_val,
@@ -13001,7 +13027,7 @@ fn reifyStruct(
const struct_obj = try new_decl_arena_allocator.create(Module.Struct);
const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);
- const type_name = try sema.createTypeName(block, .anon);
+ const type_name = try sema.createTypeName(block, .anon, "struct");
const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
.ty = Type.type,
.val = new_struct_val,
src/type.zig
@@ -1793,7 +1793,7 @@ pub const Type = extern union {
},
.error_set_inferred => {
const func = ty.castTag(.error_set_inferred).?.data.func;
- return writer.print("(inferred error set of {s})", .{func.owner_decl.name});
+ return writer.print("@typeInfo(@typeInfo(@TypeOf({s})).Fn.return_type.?).ErrorUnion.error_set", .{func.owner_decl.name});
},
.error_set_merged => {
const names = ty.castTag(.error_set_merged).?.data.keys();
@@ -1836,6 +1836,21 @@ pub const Type = extern union {
.inferred_alloc_const => unreachable,
.inferred_alloc_mut => unreachable,
.generic_poison => unreachable,
+ .var_args_param => unreachable,
+ .bound_fn => unreachable,
+
+ // TODO get rid of these Type.Tag values.
+ .atomic_order => unreachable,
+ .atomic_rmw_op => unreachable,
+ .calling_convention => unreachable,
+ .address_space => unreachable,
+ .float_mode => unreachable,
+ .reduce_op => unreachable,
+ .call_options => unreachable,
+ .prefetch_options => unreachable,
+ .export_options => unreachable,
+ .extern_options => unreachable,
+ .type_info => unreachable,
.u1,
.u8,
@@ -1873,39 +1888,44 @@ pub const Type = extern union {
.comptime_int,
.comptime_float,
.noreturn,
- .var_args_param,
- .bound_fn,
=> return maybeDupe(@tagName(t), ally, is_arena),
- .enum_literal => return maybeDupe("@Type(.EnumLiteral)", ally, is_arena),
- .@"null" => return maybeDupe("@Type(.Null)", ally, is_arena),
- .@"undefined" => return maybeDupe("@Type(.Undefined)", ally, is_arena),
+ .enum_literal => return maybeDupe("@TypeOf(.enum_literal)", ally, is_arena),
+ .@"null" => return maybeDupe("@TypeOf(null)", ally, is_arena),
+ .@"undefined" => return maybeDupe("@TypeOf(undefined)", ally, is_arena),
+ .empty_struct_literal => return maybeDupe("@TypeOf(.{})", ally, is_arena),
- .empty_struct, .empty_struct_literal => return maybeDupe("struct {}", ally, is_arena),
+ .empty_struct => {
+ const namespace = ty.castTag(.empty_struct).?.data;
+ var buffer = std.ArrayList(u8).init(ally);
+ defer buffer.deinit();
+ try namespace.renderFullyQualifiedName("", buffer.writer());
+ return buffer.toOwnedSliceSentinel(0);
+ },
.@"struct" => {
const struct_obj = ty.castTag(.@"struct").?.data;
- return try ally.dupeZ(u8, std.mem.sliceTo(struct_obj.owner_decl.name, 0));
+ return try struct_obj.owner_decl.getFullyQualifiedName(ally);
},
.@"union", .union_tagged => {
const union_obj = ty.cast(Payload.Union).?.data;
- return try ally.dupeZ(u8, std.mem.sliceTo(union_obj.owner_decl.name, 0));
+ return try union_obj.owner_decl.getFullyQualifiedName(ally);
},
.enum_full, .enum_nonexhaustive => {
const enum_full = ty.cast(Payload.EnumFull).?.data;
- return try ally.dupeZ(u8, std.mem.sliceTo(enum_full.owner_decl.name, 0));
+ return try enum_full.owner_decl.getFullyQualifiedName(ally);
},
.enum_simple => {
const enum_simple = ty.castTag(.enum_simple).?.data;
- return try ally.dupeZ(u8, std.mem.sliceTo(enum_simple.owner_decl.name, 0));
+ return try enum_simple.owner_decl.getFullyQualifiedName(ally);
},
.enum_numbered => {
const enum_numbered = ty.castTag(.enum_numbered).?.data;
- return try ally.dupeZ(u8, std.mem.sliceTo(enum_numbered.owner_decl.name, 0));
+ return try enum_numbered.owner_decl.getFullyQualifiedName(ally);
},
.@"opaque" => {
const opaque_obj = ty.cast(Payload.Opaque).?.data;
- return try ally.dupeZ(u8, std.mem.sliceTo(opaque_obj.owner_decl.name, 0));
+ return try opaque_obj.owner_decl.getFullyQualifiedName(ally);
},
.anyerror_void_error_union => return maybeDupe("anyerror!void", ally, is_arena),
@@ -1919,21 +1939,79 @@ pub const Type = extern union {
.manyptr_u8 => return maybeDupe("[*]u8", ally, is_arena),
.manyptr_const_u8 => return maybeDupe("[*]const u8", ally, is_arena),
.manyptr_const_u8_sentinel_0 => return maybeDupe("[*:0]const u8", ally, is_arena),
- .atomic_order => return maybeDupe("AtomicOrder", ally, is_arena),
- .atomic_rmw_op => return maybeDupe("AtomicRmwOp", ally, is_arena),
- .calling_convention => return maybeDupe("CallingConvention", ally, is_arena),
- .address_space => return maybeDupe("AddressSpace", ally, is_arena),
- .float_mode => return maybeDupe("FloatMode", ally, is_arena),
- .reduce_op => return maybeDupe("ReduceOp", ally, is_arena),
- .call_options => return maybeDupe("CallOptions", ally, is_arena),
- .prefetch_options => return maybeDupe("PrefetchOptions", ally, is_arena),
- .export_options => return maybeDupe("ExportOptions", ally, is_arena),
- .extern_options => return maybeDupe("ExternOptions", ally, is_arena),
- .type_info => return maybeDupe("Type", ally, is_arena),
+
+ .error_set_inferred => {
+ const func = ty.castTag(.error_set_inferred).?.data.func;
+
+ var buf = std.ArrayList(u8).init(ally);
+ defer buf.deinit();
+ try buf.appendSlice("@typeInfo(@typeInfo(@TypeOf(");
+ try func.owner_decl.renderFullyQualifiedName(buf.writer());
+ try buf.appendSlice(")).Fn.return_type.?).ErrorUnion.error_set");
+ return try buf.toOwnedSliceSentinel(0);
+ },
+
+ .function => {
+ const fn_info = ty.fnInfo();
+ var buf = std.ArrayList(u8).init(ally);
+ defer buf.deinit();
+ try buf.appendSlice("fn(");
+ for (fn_info.param_types) |param_type, i| {
+ if (i != 0) try buf.appendSlice(", ");
+ const param_name = try param_type.nameAllocAdvanced(ally, is_arena);
+ defer if (!is_arena) ally.free(param_name);
+ try buf.appendSlice(param_name);
+ }
+ if (fn_info.is_var_args) {
+ if (fn_info.param_types.len != 0) {
+ try buf.appendSlice(", ");
+ }
+ try buf.appendSlice("...");
+ }
+ try buf.appendSlice(") ");
+ if (fn_info.cc != .Unspecified) {
+ try buf.appendSlice("callconv(.");
+ try buf.appendSlice(@tagName(fn_info.cc));
+ try buf.appendSlice(") ");
+ }
+ if (fn_info.alignment != 0) {
+ try buf.writer().print("align({d}) ", .{fn_info.alignment});
+ }
+ {
+ const ret_ty_name = try fn_info.return_type.nameAllocAdvanced(ally, is_arena);
+ defer if (!is_arena) ally.free(ret_ty_name);
+ try buf.appendSlice(ret_ty_name);
+ }
+ return try buf.toOwnedSliceSentinel(0);
+ },
+
+ .error_union => {
+ const error_union = ty.castTag(.error_union).?.data;
+
+ var buf = std.ArrayList(u8).init(ally);
+ defer buf.deinit();
+
+ {
+ const err_set_ty_name = try error_union.error_set.nameAllocAdvanced(ally, is_arena);
+ defer if (!is_arena) ally.free(err_set_ty_name);
+ try buf.appendSlice(err_set_ty_name);
+ }
+
+ try buf.appendSlice("!");
+
+ {
+ const payload_ty_name = try error_union.payload.nameAllocAdvanced(ally, is_arena);
+ defer if (!is_arena) ally.free(payload_ty_name);
+ try buf.appendSlice(payload_ty_name);
+ }
+
+ return try buf.toOwnedSliceSentinel(0);
+ },
else => {
// TODO this is wasteful and also an incorrect implementation of `@typeName`
var buf = std.ArrayList(u8).init(ally);
+ defer buf.deinit();
try buf.writer().print("{}", .{ty});
return try buf.toOwnedSliceSentinel(0);
},
test/behavior/bugs/3779.zig
@@ -28,9 +28,10 @@ const type_name = @typeName(TestType);
const ptr_type_name: [*:0]const u8 = type_name;
test "@typeName() returns a string literal" {
+ if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
try std.testing.expectEqual(*const [type_name.len:0]u8, @TypeOf(type_name));
- try std.testing.expectEqualStrings("TestType", type_name);
- try std.testing.expectEqualStrings("TestType", ptr_type_name[0..type_name.len]);
+ try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", type_name);
+ try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", ptr_type_name[0..type_name.len]);
}
const actual_contents = @embedFile("3779_file_to_embed.txt");
test/behavior/basic.zig
@@ -199,11 +199,18 @@ const OpaqueA = opaque {};
const OpaqueB = opaque {};
test "opaque types" {
- try expect(*OpaqueA != *OpaqueB);
- if (builtin.zig_backend == .stage1) { // TODO make this pass for stage2
- try expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
- try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
+ if (builtin.zig_backend == .stage1) {
+ // stage1 gets the type names wrong
+ return error.SkipZigTest;
}
+
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
+ try expect(*OpaqueA != *OpaqueB);
+
+ try expect(mem.eql(u8, @typeName(OpaqueA), "behavior.basic.OpaqueA"));
+ try expect(mem.eql(u8, @typeName(OpaqueB), "behavior.basic.OpaqueB"));
}
const global_a: i32 = 1234;
test/behavior/typename.zig
@@ -1,6 +1,8 @@
+const builtin = @import("builtin");
const std = @import("std");
const expect = std.testing.expect;
-const expectEqualSlices = std.testing.expectEqualSlices;
+const expectEqualStrings = std.testing.expectEqualStrings;
+const expectStringStartsWith = std.testing.expectStringStartsWith;
// Most tests here can be comptime but use runtime so that a stacktrace
// can show failure location.
@@ -9,50 +11,124 @@ const expectEqualSlices = std.testing.expectEqualSlices;
// 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" {
+test "anon fn param" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 uses line/column for the names but we're moving away from that for
+ // incremental compilation purposes.
+ return error.SkipZigTest;
+ }
+
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
// 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 expectEqualStringsIgnoreDigits(
+ "behavior.typename.TypeFromFn(behavior.typename.test.anon fn param__struct_0)",
+ @typeName(TypeFromFn(struct {})),
+ );
+ try expectEqualStringsIgnoreDigits(
+ "behavior.typename.TypeFromFn(behavior.typename.test.anon fn param__union_0)",
+ @typeName(TypeFromFn(union { unused: u8 })),
+ );
+ try expectEqualStringsIgnoreDigits(
+ "behavior.typename.TypeFromFn(behavior.typename.test.anon fn param__enum_0)",
+ @typeName(TypeFromFn(enum { unused })),
+ );
- 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)",
+ try expectEqualStringsIgnoreDigits(
+ "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)",
+ @typeName(TypeFromFnB(struct {}, union { unused: u8 }, enum { unused })),
);
}
-// CAUTION: this test is source-location sensitive.
test "anon field init" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 uses line/column for the names but we're moving away from that for
+ // incremental compilation purposes.
+ return error.SkipZigTest;
+ }
+
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
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");
+ try expectEqualStringsIgnoreDigits(
+ "behavior.typename.test.anon field init__struct_0",
+ @typeName(Foo.T1),
+ );
+ try expectEqualStringsIgnoreDigits(
+ "behavior.typename.test.anon field init__union_0",
+ @typeName(Foo.T2),
+ );
+ try expectEqualStringsIgnoreDigits(
+ "behavior.typename.test.anon field init__enum_0",
+ @typeName(Foo.T3),
+ );
}
test "basic" {
- try expectEqualSlices(u8, @typeName(i64), "i64");
- try expectEqualSlices(u8, @typeName(*usize), "*usize");
- try expectEqualSlices(u8, @typeName([]u8), "[]u8");
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
+ try expectEqualStrings(@typeName(i64), "i64");
+ try expectEqualStrings(@typeName(*usize), "*usize");
+ try expectEqualStrings(@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");
+ if (builtin.zig_backend == .stage1) {
+ // stage1 fails to return fully qualified namespaces.
+ return error.SkipZigTest;
+ }
+
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
+ try expectEqualStrings(
+ "behavior.typename.A_Struct",
+ @typeName(A_Struct),
+ );
+ try expectEqualStrings(
+ "behavior.typename.A_Union",
+ @typeName(A_Union),
+ );
+ try expectEqualStrings(
+ "behavior.typename.A_Enum",
+ @typeName(A_Enum),
+ );
// regular fn, without error
- try expectEqualSlices(u8, @typeName(@TypeOf(regular)), "fn() void");
+ try expectEqualStrings(
+ "fn() void",
+ @typeName(@TypeOf(regular)),
+ );
// 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");
+ try expectEqualStrings(
+ "fn() @typeInfo(@typeInfo(@TypeOf(behavior.typename.B.doTest)).Fn.return_type.?).ErrorUnion.error_set!void",
+ @typeName(@TypeOf(B.doTest)),
+ );
// generic fn
- try expectEqualSlices(u8, @typeName(@TypeOf(TypeFromFn)), "fn(type) anytype");
+ try expectEqualStrings(
+ "fn(type) type",
+ @typeName(@TypeOf(TypeFromFn)),
+ );
}
const A_Struct = struct {};
@@ -66,6 +142,17 @@ const A_Enum = enum {
fn regular() void {}
test "fn body decl" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 fails to return fully qualified namespaces.
+ return error.SkipZigTest;
+ }
+
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
try B.doTest();
}
@@ -79,20 +166,50 @@ const B = struct {
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");
+ try expectEqualStringsIgnoreDigits(
+ "behavior.typename.B.doTest__struct_0",
+ @typeName(B_Struct),
+ );
+ try expectEqualStringsIgnoreDigits(
+ "behavior.typename.B.doTest__union_0",
+ @typeName(B_Union),
+ );
+ try expectEqualStringsIgnoreDigits(
+ "behavior.typename.B.doTest__enum_0",
+ @typeName(B_Enum),
+ );
}
};
test "fn param" {
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
// 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 expectEqualStrings(
+ "behavior.typename.TypeFromFn(u8)",
+ @typeName(TypeFromFn(u8)),
+ );
+ try expectEqualStrings(
+ "behavior.typename.TypeFromFn(behavior.typename.A_Struct)",
+ @typeName(TypeFromFn(A_Struct)),
+ );
+ try expectEqualStrings(
+ "behavior.typename.TypeFromFn(behavior.typename.A_Union)",
+ @typeName(TypeFromFn(A_Union)),
+ );
+ try expectEqualStrings(
+ "behavior.typename.TypeFromFn(behavior.typename.A_Enum)",
+ @typeName(TypeFromFn(A_Enum)),
+ );
- try expectEqualSlices(u8, @typeName(TypeFromFn2(u8, bool)), "behavior.typename.TypeFromFn2(u8,bool)");
+ try expectEqualStrings(
+ "behavior.typename.TypeFromFn2(u8,bool)",
+ @typeName(TypeFromFn2(u8, bool)),
+ );
}
fn TypeFromFn(comptime T: type) type {
@@ -106,9 +223,32 @@ fn TypeFromFn2(comptime T1: type, comptime T2: type) type {
return struct {};
}
-fn TypeFromFn3(comptime T1: type, comptime T2: type, comptime T3: type) type {
+fn TypeFromFnB(comptime T1: type, comptime T2: type, comptime T3: type) type {
_ = T1;
_ = T2;
_ = T3;
return struct {};
}
+
+/// Replaces integers in `actual` with '0' before doing the test.
+pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8) !void {
+ var actual_buf: [1024]u8 = undefined;
+ var actual_i: usize = 0;
+ var last_digit = false;
+ for (actual) |byte| {
+ switch (byte) {
+ '0'...'9' => {
+ if (last_digit) continue;
+ last_digit = true;
+ actual_buf[actual_i] = '0';
+ actual_i += 1;
+ },
+ else => {
+ last_digit = false;
+ actual_buf[actual_i] = byte;
+ actual_i += 1;
+ },
+ }
+ }
+ return expectEqualStrings(expected, actual_buf[0..actual_i]);
+}
test/behavior/undefined.zig
@@ -77,8 +77,12 @@ test "assign undefined to struct with method" {
}
test "type name of undefined" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 gets the type name wrong
+ return error.SkipZigTest;
+ }
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
const x = undefined;
- try expect(mem.eql(u8, @typeName(@TypeOf(x)), "@Type(.Undefined)"));
+ try expect(mem.eql(u8, @typeName(@TypeOf(x)), "@TypeOf(undefined)"));
}
test/behavior.zig
@@ -120,6 +120,7 @@ test {
_ = @import("behavior/tuple.zig");
_ = @import("behavior/type.zig");
_ = @import("behavior/type_info.zig");
+ _ = @import("behavior/typename.zig");
_ = @import("behavior/undefined.zig");
_ = @import("behavior/underscore.zig");
_ = @import("behavior/union.zig");
@@ -179,7 +180,6 @@ test {
_ = @import("behavior/bugs/7027.zig");
_ = @import("behavior/select.zig");
_ = @import("behavior/struct_contains_slice_of_itself.zig");
- _ = @import("behavior/typename.zig");
}
}
}