aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-03-18 00:12:22 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-03-18 00:12:22 -0700
commitf3f5a5d05b7056aceb408b701613242d053019ab (patch)
treeacb912950d734b0c25b38c1ae82a8558d1313057 /src
parent69d78bdae4a5d0ec5877add5936ae8e9daf09140 (diff)
downloadzig-f3f5a5d05b7056aceb408b701613242d053019ab.tar.gz
zig-f3f5a5d05b7056aceb408b701613242d053019ab.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/AstGen.zig3
-rw-r--r--src/Sema.zig68
-rw-r--r--src/type.zig126
3 files changed, 152 insertions, 45 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index c714b69572..85f2288413 100644
--- a/src/AstGen.zig
+++ b/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 => {
diff --git a/src/Sema.zig b/src/Sema.zig
index 4c2fa33951..722c39cfcb 100644
--- a/src/Sema.zig
+++ b/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,
diff --git a/src/type.zig b/src/type.zig
index b3edc87585..139f126d3b 100644
--- a/src/type.zig
+++ b/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);
},