authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-04-18 00:15:53+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-04-17 22:47:54-07:00
log21a6a1b0f2d7241594a9aa123e48cf2e3ebaccb9
tree106fe6c9dfc11e73b3b3f04e5cc43d93b3da4685
parent187f0c1e262cbeb37d72c571381b5b94c1eb3a63

Sema: cap depth of value printing in type names

Certain types (notably, `std.ComptimeStringMap`) were resulting in excessively long type names when instantiated, which in turn resulted in excessively long symbol names. These are problematic for two reasons: * Symbol names are sometimes read by humans -- they ought to be readable. * Some other applications (looking at you, xcode) trip on very long symbol names. To work around this for now, we cap the depth of value printing at 1, as opposed to the normal 3. This doesn't guarantee anything -- there could still be, for instance, an incredibly long aggregate -- but it works around the issue in practice for the time being.

3 files changed, 35 insertions(+), 19 deletions(-)

src/Sema.zig+27-17
...@@ -2869,14 +2869,14 @@ fn createAnonymousDeclTypeNamed(...@@ -2869,14 +2869,14 @@ fn createAnonymousDeclTypeNamed(
2869 anon_prefix: []const u8,2869 anon_prefix: []const u8,
2870 inst: ?Zir.Inst.Index,2870 inst: ?Zir.Inst.Index,
2871) !InternPool.DeclIndex {2871) !InternPool.DeclIndex {
2872 const mod = sema.mod;2872 const zcu = sema.mod;
2873 const ip = &mod.intern_pool;2873 const ip = &zcu.intern_pool;
2874 const gpa = sema.gpa;2874 const gpa = sema.gpa;
2875 const namespace = block.namespace;2875 const namespace = block.namespace;
2876 const src_decl = mod.declPtr(block.src_decl);2876 const src_decl = zcu.declPtr(block.src_decl);
2877 const src_node = src_decl.relativeToNodeIndex(src.node_offset.x);2877 const src_node = src_decl.relativeToNodeIndex(src.node_offset.x);
2878 const new_decl_index = try mod.allocateNewDecl(namespace, src_node);2878 const new_decl_index = try zcu.allocateNewDecl(namespace, src_node);
2879 errdefer mod.destroyDecl(new_decl_index);2879 errdefer zcu.destroyDecl(new_decl_index);
28802880
2881 switch (name_strategy) {2881 switch (name_strategy) {
2882 .anon => {2882 .anon => {
...@@ -2887,15 +2887,15 @@ fn createAnonymousDeclTypeNamed(...@@ -2887,15 +2887,15 @@ fn createAnonymousDeclTypeNamed(
2887 // This name is also used as the key in the parent namespace so it cannot be2887 // This name is also used as the key in the parent namespace so it cannot be
2888 // renamed.2888 // renamed.
28892889
2890 const name = mod.intern_pool.getOrPutStringFmt(gpa, "{}__{s}_{d}", .{2890 const name = ip.getOrPutStringFmt(gpa, "{}__{s}_{d}", .{
2891 src_decl.name.fmt(&mod.intern_pool), anon_prefix, @intFromEnum(new_decl_index),2891 src_decl.name.fmt(ip), anon_prefix, @intFromEnum(new_decl_index),
2892 }, .no_embedded_nulls) catch unreachable;2892 }, .no_embedded_nulls) catch unreachable;
2893 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);2893 try zcu.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);
2894 return new_decl_index;2894 return new_decl_index;
2895 },2895 },
2896 .parent => {2896 .parent => {
2897 const name = mod.declPtr(block.src_decl).name;2897 const name = zcu.declPtr(block.src_decl).name;
2898 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);2898 try zcu.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);
2899 return new_decl_index;2899 return new_decl_index;
2900 },2900 },
2901 .func => {2901 .func => {
...@@ -2906,7 +2906,7 @@ fn createAnonymousDeclTypeNamed(...@@ -2906,7 +2906,7 @@ fn createAnonymousDeclTypeNamed(
2906 defer buf.deinit();2906 defer buf.deinit();
29072907
2908 const writer = buf.writer();2908 const writer = buf.writer();
2909 try writer.print("{}(", .{mod.declPtr(block.src_decl).name.fmt(&mod.intern_pool)});2909 try writer.print("{}(", .{zcu.declPtr(block.src_decl).name.fmt(ip)});
29102910
2911 var arg_i: usize = 0;2911 var arg_i: usize = 0;
2912 for (fn_info.param_body) |zir_inst| switch (zir_tags[@intFromEnum(zir_inst)]) {2912 for (fn_info.param_body) |zir_inst| switch (zir_tags[@intFromEnum(zir_inst)]) {
...@@ -2921,7 +2921,17 @@ fn createAnonymousDeclTypeNamed(...@@ -2921,7 +2921,17 @@ fn createAnonymousDeclTypeNamed(
2921 return sema.createAnonymousDeclTypeNamed(block, src, val, .anon, anon_prefix, null);2921 return sema.createAnonymousDeclTypeNamed(block, src, val, .anon, anon_prefix, null);
29222922
2923 if (arg_i != 0) try writer.writeByte(',');2923 if (arg_i != 0) try writer.writeByte(',');
2924 try writer.print("{}", .{arg_val.fmtValue(sema.mod, sema)});2924
2925 // Limiting the depth here helps avoid type names getting too long, which
2926 // in turn helps to avoid unreasonably long symbol names for namespaced
2927 // symbols. Such names should ideally be human-readable, and additionally,
2928 // some tooling may not support very long symbol names.
2929 try writer.print("{}", .{Value.fmtValueFull(.{
2930 .val = arg_val,
2931 .mod = zcu,
2932 .opt_sema = sema,
2933 .depth = 1,
2934 })});
29252935
2926 arg_i += 1;2936 arg_i += 1;
2927 continue;2937 continue;
...@@ -2930,8 +2940,8 @@ fn createAnonymousDeclTypeNamed(...@@ -2930,8 +2940,8 @@ fn createAnonymousDeclTypeNamed(
2930 };2940 };
29312941
2932 try writer.writeByte(')');2942 try writer.writeByte(')');
2933 const name = try mod.intern_pool.getOrPutString(gpa, buf.items, .no_embedded_nulls);2943 const name = try ip.getOrPutString(gpa, buf.items, .no_embedded_nulls);
2934 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);2944 try zcu.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);
2935 return new_decl_index;2945 return new_decl_index;
2936 },2946 },
2937 .dbg_var => {2947 .dbg_var => {
...@@ -2942,10 +2952,10 @@ fn createAnonymousDeclTypeNamed(...@@ -2942,10 +2952,10 @@ fn createAnonymousDeclTypeNamed(
2942 .dbg_var_ptr, .dbg_var_val => {2952 .dbg_var_ptr, .dbg_var_val => {
2943 if (zir_data[i].str_op.operand != ref) continue;2953 if (zir_data[i].str_op.operand != ref) continue;
29442954
2945 const name = try mod.intern_pool.getOrPutStringFmt(gpa, "{}.{s}", .{2955 const name = try ip.getOrPutStringFmt(gpa, "{}.{s}", .{
2946 src_decl.name.fmt(&mod.intern_pool), zir_data[i].str_op.getStr(sema.code),2956 src_decl.name.fmt(ip), zir_data[i].str_op.getStr(sema.code),
2947 }, .no_embedded_nulls);2957 }, .no_embedded_nulls);
2948 try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);2958 try zcu.initNewAnonDecl(new_decl_index, src_decl.src_line, val, name);
2949 return new_decl_index;2959 return new_decl_index;
2950 },2960 },
2951 else => {},2961 else => {},
src/Value.zig+5
...@@ -44,9 +44,14 @@ pub fn fmtValue(val: Value, mod: *Module, opt_sema: ?*Sema) std.fmt.Formatter(pr...@@ -44,9 +44,14 @@ pub fn fmtValue(val: Value, mod: *Module, opt_sema: ?*Sema) std.fmt.Formatter(pr
44 .val = val,44 .val = val,
45 .mod = mod,45 .mod = mod,
46 .opt_sema = opt_sema,46 .opt_sema = opt_sema,
47 .depth = 3,
47 } };48 } };
48}49}
4950
51pub fn fmtValueFull(ctx: print_value.FormatContext) std.fmt.Formatter(print_value.format) {
52 return .{ .data = ctx };
53}
54
50/// Converts `val` to a null-terminated string stored in the InternPool.55/// Converts `val` to a null-terminated string stored in the InternPool.
51/// Asserts `val` is an array of `u8`56/// Asserts `val` is an array of `u8`
52pub fn toIpString(val: Value, ty: Type, mod: *Module) !InternPool.NullTerminatedString {57pub fn toIpString(val: Value, ty: Type, mod: *Module) !InternPool.NullTerminatedString {
src/print_value.zig+3-2
...@@ -14,10 +14,11 @@ const Target = std.Target;...@@ -14,10 +14,11 @@ const Target = std.Target;
14const max_aggregate_items = 100;14const max_aggregate_items = 100;
15const max_string_len = 256;15const max_string_len = 256;
1616
17const FormatContext = struct {17pub const FormatContext = struct {
18 val: Value,18 val: Value,
19 mod: *Module,19 mod: *Module,
20 opt_sema: ?*Sema,20 opt_sema: ?*Sema,
21 depth: u8,
21};22};
2223
23pub fn format(24pub fn format(
...@@ -28,7 +29,7 @@ pub fn format(...@@ -28,7 +29,7 @@ pub fn format(
28) !void {29) !void {
29 _ = options;30 _ = options;
30 comptime std.debug.assert(fmt.len == 0);31 comptime std.debug.assert(fmt.len == 0);
31 return print(ctx.val, writer, 3, ctx.mod, ctx.opt_sema) catch |err| switch (err) {32 return print(ctx.val, writer, ctx.depth, ctx.mod, ctx.opt_sema) catch |err| switch (err) {
32 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function33 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
33 error.ComptimeBreak, error.ComptimeReturn => unreachable,34 error.ComptimeBreak, error.ComptimeReturn => unreachable,
34 error.AnalysisFail, error.NeededSourceLocation => unreachable, // TODO: re-evaluate when we use `opt_sema` more fully35 error.AnalysisFail, error.NeededSourceLocation => unreachable, // TODO: re-evaluate when we use `opt_sema` more fully