From f84a4953d29ffc2bdc94fa353cac685430e6bbe4 Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 16 Jul 2024 11:37:53 +0100 Subject: Value: eliminate static recursion loop from value printing --- src/print_value.zig | 104 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 35 deletions(-) (limited to 'src/print_value.zig') diff --git a/src/print_value.zig b/src/print_value.zig index c19ba43af3..46b9203068 100644 --- a/src/print_value.zig +++ b/src/print_value.zig @@ -20,18 +20,35 @@ pub const FormatContext = struct { depth: u8, }; -pub fn format( +pub fn formatSema( ctx: FormatContext, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype, ) !void { _ = options; + const sema = ctx.opt_sema.?; comptime std.debug.assert(fmt.len == 0); - return print(ctx.val, writer, ctx.depth, ctx.pt, ctx.opt_sema) catch |err| switch (err) { + return print(ctx.val, writer, ctx.depth, ctx.pt, true, sema) catch |err| switch (err) { error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function error.ComptimeBreak, error.ComptimeReturn => unreachable, - error.AnalysisFail => unreachable, // TODO: re-evaluate when we use `opt_sema` more fully + error.AnalysisFail => unreachable, // TODO: re-evaluate when we use `sema` more fully + else => |e| return e, + }; +} + +pub fn format( + ctx: FormatContext, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, +) !void { + _ = options; + std.debug.assert(ctx.opt_sema == null); + comptime std.debug.assert(fmt.len == 0); + return print(ctx.val, writer, ctx.depth, ctx.pt, false, {}) catch |err| switch (err) { + error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function + error.ComptimeBreak, error.ComptimeReturn, error.AnalysisFail => unreachable, else => |e| return e, }; } @@ -42,7 +59,8 @@ pub fn print( level: u8, pt: Zcu.PerThread, /// If this `Sema` is provided, we will recurse through pointers where possible to provide friendly output. - opt_sema: ?*Sema, + comptime have_sema: bool, + sema: if (have_sema) *Sema else void, ) (@TypeOf(writer).Error || Zcu.CompileError)!void { const mod = pt.zcu; const ip = &mod.intern_pool; @@ -80,11 +98,11 @@ pub fn print( }), .int => |int| switch (int.storage) { inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}), - .lazy_align => |ty| if (opt_sema != null) { + .lazy_align => |ty| if (have_sema) { const a = (try Type.fromInterned(ty).abiAlignmentAdvanced(pt, .sema)).scalar; try writer.print("{}", .{a.toByteUnits() orelse 0}); } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(pt)}), - .lazy_size => |ty| if (opt_sema != null) { + .lazy_size => |ty| if (have_sema) { const s = (try Type.fromInterned(ty).abiSizeAdvanced(pt, .sema)).scalar; try writer.print("{}", .{s}); } else try writer.print("@sizeOf({})", .{Type.fromInterned(ty).fmt(pt)}), @@ -96,7 +114,7 @@ pub fn print( .err_name => |err_name| try writer.print("error.{}", .{ err_name.fmt(ip), }), - .payload => |payload| try print(Value.fromInterned(payload), writer, level, pt, opt_sema), + .payload => |payload| try print(Value.fromInterned(payload), writer, level, pt, have_sema, sema), }, .enum_literal => |enum_literal| try writer.print(".{}", .{ enum_literal.fmt(ip), @@ -110,7 +128,7 @@ pub fn print( return writer.writeAll("@enumFromInt(...)"); } try writer.writeAll("@enumFromInt("); - try print(Value.fromInterned(enum_tag.int), writer, level - 1, pt, opt_sema); + try print(Value.fromInterned(enum_tag.int), writer, level - 1, pt, have_sema, sema); try writer.writeAll(")"); }, .empty_enum_value => try writer.writeAll("(empty enum value)"), @@ -124,15 +142,15 @@ pub fn print( .decl, .int => false, }; if (print_contents) { - // TODO: eventually we want to load the slice as an array with `opt_sema`, but that's + // TODO: eventually we want to load the slice as an array with `sema`, but that's // currently not possible without e.g. triggering compile errors. } - try printPtr(Value.fromInterned(slice.ptr), writer, level, pt, opt_sema); + try printPtr(Value.fromInterned(slice.ptr), writer, level, pt, have_sema, sema); try writer.writeAll("[0.."); if (level == 0) { try writer.writeAll("(...)"); } else { - try print(Value.fromInterned(slice.len), writer, level - 1, pt, opt_sema); + try print(Value.fromInterned(slice.len), writer, level - 1, pt, have_sema, sema); } try writer.writeAll("]"); }, @@ -143,16 +161,16 @@ pub fn print( .decl, .int => false, }; if (print_contents) { - // TODO: eventually we want to load the pointer with `opt_sema`, but that's + // TODO: eventually we want to load the pointer with `sema`, but that's // currently not possible without e.g. triggering compile errors. } - try printPtr(val, writer, level, pt, opt_sema); + try printPtr(val, writer, level, pt, have_sema, sema); }, .opt => |opt| switch (opt.val) { .none => try writer.writeAll("null"), - else => |payload| try print(Value.fromInterned(payload), writer, level, pt, opt_sema), + else => |payload| try print(Value.fromInterned(payload), writer, level, pt, have_sema, sema), }, - .aggregate => |aggregate| try printAggregate(val, aggregate, false, writer, level, pt, opt_sema), + .aggregate => |aggregate| try printAggregate(val, aggregate, false, writer, level, pt, have_sema, sema), .un => |un| { if (level == 0) { try writer.writeAll(".{ ... }"); @@ -161,13 +179,13 @@ pub fn print( if (un.tag == .none) { const backing_ty = try val.typeOf(mod).unionBackingType(pt); try writer.print("@bitCast(@as({}, ", .{backing_ty.fmt(pt)}); - try print(Value.fromInterned(un.val), writer, level - 1, pt, opt_sema); + try print(Value.fromInterned(un.val), writer, level - 1, pt, have_sema, sema); try writer.writeAll("))"); } else { try writer.writeAll(".{ "); - try print(Value.fromInterned(un.tag), writer, level - 1, pt, opt_sema); + try print(Value.fromInterned(un.tag), writer, level - 1, pt, have_sema, sema); try writer.writeAll(" = "); - try print(Value.fromInterned(un.val), writer, level - 1, pt, opt_sema); + try print(Value.fromInterned(un.val), writer, level - 1, pt, have_sema, sema); try writer.writeAll(" }"); } }, @@ -182,7 +200,8 @@ fn printAggregate( writer: anytype, level: u8, pt: Zcu.PerThread, - opt_sema: ?*Sema, + comptime have_sema: bool, + sema: if (have_sema) *Sema else void, ) (@TypeOf(writer).Error || Zcu.CompileError)!void { if (level == 0) { if (is_ref) try writer.writeByte('&'); @@ -203,7 +222,7 @@ fn printAggregate( if (i != 0) try writer.writeAll(", "); const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?; try writer.print(".{i} = ", .{field_name.fmt(ip)}); - try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema); + try print(try val.fieldValue(pt, i), writer, level - 1, pt, have_sema, sema); } try writer.writeAll(" }"); return; @@ -253,7 +272,7 @@ fn printAggregate( const max_len = @min(len, max_aggregate_items); for (0..max_len) |i| { if (i != 0) try writer.writeAll(", "); - try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema); + try print(try val.fieldValue(pt, i), writer, level - 1, pt, have_sema, sema); } if (len > max_aggregate_items) { try writer.writeAll(", ..."); @@ -261,7 +280,14 @@ fn printAggregate( return writer.writeAll(" }"); } -fn printPtr(ptr_val: Value, writer: anytype, level: u8, pt: Zcu.PerThread, opt_sema: ?*Sema) (@TypeOf(writer).Error || Zcu.CompileError)!void { +fn printPtr( + ptr_val: Value, + writer: anytype, + level: u8, + pt: Zcu.PerThread, + comptime have_sema: bool, + sema: if (have_sema) *Sema else void, +) (@TypeOf(writer).Error || Zcu.CompileError)!void { const ptr = switch (pt.zcu.intern_pool.indexToKey(ptr_val.toIntern())) { .undef => return writer.writeAll("undefined"), .ptr => |ptr| ptr, @@ -278,7 +304,8 @@ fn printPtr(ptr_val: Value, writer: anytype, level: u8, pt: Zcu.PerThread, opt_s writer, level, pt, - opt_sema, + have_sema, + sema, ), else => {}, } @@ -286,12 +313,19 @@ fn printPtr(ptr_val: Value, writer: anytype, level: u8, pt: Zcu.PerThread, opt_s var arena = std.heap.ArenaAllocator.init(pt.zcu.gpa); defer arena.deinit(); - const derivation = try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, opt_sema); - try printPtrDerivation(derivation, writer, level, pt, opt_sema); + const derivation = try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, have_sema, sema); + try printPtrDerivation(derivation, writer, level, pt, have_sema, sema); } /// Print `derivation` as an lvalue, i.e. such that writing `&` before this gives the pointer value. -fn printPtrDerivation(derivation: Value.PointerDeriveStep, writer: anytype, level: u8, pt: Zcu.PerThread, opt_sema: ?*Sema) (@TypeOf(writer).Error || Zcu.CompileError)!void { +fn printPtrDerivation( + derivation: Value.PointerDeriveStep, + writer: anytype, + level: u8, + pt: Zcu.PerThread, + comptime have_sema: bool, + sema: if (have_sema) *Sema else void, +) (@TypeOf(writer).Error || Zcu.CompileError)!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; switch (derivation) { @@ -305,31 +339,31 @@ fn printPtrDerivation(derivation: Value.PointerDeriveStep, writer: anytype, leve .anon_decl_ptr => |anon| { const ty = Value.fromInterned(anon.val).typeOf(zcu); try writer.print("@as({}, ", .{ty.fmt(pt)}); - try print(Value.fromInterned(anon.val), writer, level - 1, pt, opt_sema); + try print(Value.fromInterned(anon.val), writer, level - 1, pt, have_sema, sema); try writer.writeByte(')'); }, .comptime_alloc_ptr => |info| { try writer.print("@as({}, ", .{info.val.typeOf(zcu).fmt(pt)}); - try print(info.val, writer, level - 1, pt, opt_sema); + try print(info.val, writer, level - 1, pt, have_sema, sema); try writer.writeByte(')'); }, .comptime_field_ptr => |val| { const ty = val.typeOf(zcu); try writer.print("@as({}, ", .{ty.fmt(pt)}); - try print(val, writer, level - 1, pt, opt_sema); + try print(val, writer, level - 1, pt, have_sema, sema); try writer.writeByte(')'); }, .eu_payload_ptr => |info| { try writer.writeByte('('); - try printPtrDerivation(info.parent.*, writer, level, pt, opt_sema); + try printPtrDerivation(info.parent.*, writer, level, pt, have_sema, sema); try writer.writeAll(" catch unreachable)"); }, .opt_payload_ptr => |info| { - try printPtrDerivation(info.parent.*, writer, level, pt, opt_sema); + try printPtrDerivation(info.parent.*, writer, level, pt, have_sema, sema); try writer.writeAll(".?"); }, .field_ptr => |field| { - try printPtrDerivation(field.parent.*, writer, level, pt, opt_sema); + try printPtrDerivation(field.parent.*, writer, level, pt, have_sema, sema); const agg_ty = (try field.parent.ptrType(pt)).childType(zcu); switch (agg_ty.zigTypeTag(zcu)) { .Struct => if (agg_ty.structFieldName(field.field_idx, zcu).unwrap()) |field_name| { @@ -351,16 +385,16 @@ fn printPtrDerivation(derivation: Value.PointerDeriveStep, writer: anytype, leve } }, .elem_ptr => |elem| { - try printPtrDerivation(elem.parent.*, writer, level, pt, opt_sema); + try printPtrDerivation(elem.parent.*, writer, level, pt, have_sema, sema); try writer.print("[{d}]", .{elem.elem_idx}); }, .offset_and_cast => |oac| if (oac.byte_offset == 0) { try writer.print("@as({}, @ptrCast(", .{oac.new_ptr_ty.fmt(pt)}); - try printPtrDerivation(oac.parent.*, writer, level, pt, opt_sema); + try printPtrDerivation(oac.parent.*, writer, level, pt, have_sema, sema); try writer.writeAll("))"); } else { try writer.print("@as({}, @ptrFromInt(@intFromPtr(", .{oac.new_ptr_ty.fmt(pt)}); - try printPtrDerivation(oac.parent.*, writer, level, pt, opt_sema); + try printPtrDerivation(oac.parent.*, writer, level, pt, have_sema, sema); try writer.print(") + {d}))", .{oac.byte_offset}); }, } -- cgit v1.2.3