diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-03-18 00:12:22 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-03-18 00:12:22 -0700 |
| commit | f3f5a5d05b7056aceb408b701613242d053019ab (patch) | |
| tree | acb912950d734b0c25b38c1ae82a8558d1313057 /src | |
| parent | 69d78bdae4a5d0ec5877add5936ae8e9daf09140 (diff) | |
| download | zig-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.zig | 3 | ||||
| -rw-r--r-- | src/Sema.zig | 68 | ||||
| -rw-r--r-- | src/type.zig | 126 |
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); }, |
