authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-02-08 15:39:21+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:10+00:00
logbe4c4ce2787537f860c8578eb9e497f66c2e9baf
tree32da88e56d7c5dba322bed9279b93a3d03c52b16
parente2669689c46630afd3adb99c496a6895c6c95a15
signaturelock-open Commit is signed but in an unrecognized format.

Zcu: improve dependency loop errors with only one item

In this case, we can write the error much more simply.

1 files changed, 25 insertions(+), 5 deletions(-)

src/Zcu.zig+25-5
......@@ -4739,21 +4739,32 @@ pub fn addDependencyLoopErrors(zcu: *Zcu, eb: *std.zig.ErrorBundle.Wip) Allocato
47394739 const frame_limit = zcu.comp.reference_trace orelse 0;
47404740 try zcu.populateReferenceTrace(units.items[start_index], frame_limit, eb, &ref_trace);
47414741
4742 if (units.items.len == 1) {
4743 // Don't do a complicated message with multiple notes, just do a single error message.
4744 assert(start_index == 0);
4745 const root_msg = addDependencyLoopErrorLine(zcu, eb, units.items[start_index], ref_trace.items) catch |err| switch (err) {
4746 error.AlreadyReported => return, // give up on the dep loop error
4747 error.OutOfMemory => |e| return e,
4748 };
4749 try eb.root_list.append(eb.gpa, root_msg);
4750 continue;
4751 }
4752
47424753 // Collect all notes first so we don't leave an incomplete root error message on `error.AlreadyReported`.
47434754 const note_buf = try gpa.alloc(std.zig.ErrorBundle.MessageIndex, units.items.len + 1);
47444755 defer gpa.free(note_buf);
4745 note_buf[0] = addDependencyLoopNote(zcu, eb, units.items[start_index], ref_trace.items) catch |err| switch (err) {
4756 note_buf[0] = addDependencyLoopErrorLine(zcu, eb, units.items[start_index], ref_trace.items) catch |err| switch (err) {
47464757 error.AlreadyReported => return, // give up on the dep loop error
47474758 error.OutOfMemory => |e| return e,
47484759 };
47494760 for (units.items[start_index + 1 ..], note_buf[1 .. units.items.len - start_index]) |unit, *note| {
4750 note.* = addDependencyLoopNote(zcu, eb, unit, &.{}) catch |err| switch (err) {
4761 note.* = addDependencyLoopErrorLine(zcu, eb, unit, &.{}) catch |err| switch (err) {
47514762 error.AlreadyReported => return, // give up on the dep loop error
47524763 error.OutOfMemory => |e| return e,
47534764 };
47544765 }
47554766 for (units.items[0..start_index], note_buf[units.items.len - start_index .. units.items.len]) |unit, *note| {
4756 note.* = addDependencyLoopNote(zcu, eb, unit, &.{}) catch |err| switch (err) {
4767 note.* = addDependencyLoopErrorLine(zcu, eb, unit, &.{}) catch |err| switch (err) {
47574768 error.AlreadyReported => return, // give up on the dep loop error
47584769 error.OutOfMemory => |e| return e,
47594770 };
......@@ -4773,7 +4784,7 @@ pub fn addDependencyLoopErrors(zcu: *Zcu, eb: *std.zig.ErrorBundle.Wip) Allocato
47734784 @memcpy(notes, note_buf);
47744785 }
47754786}
4776fn addDependencyLoopNote(
4787fn addDependencyLoopErrorLine(
47774788 zcu: *Zcu,
47784789 eb: *std.zig.ErrorBundle.Wip,
47794790 source_unit: AnalUnit,
......@@ -4789,7 +4800,16 @@ fn addDependencyLoopNote(
47894800
47904801 const dep_node = zcu.dependency_loop_nodes.get(source_unit).?;
47914802
4792 const msg: std.zig.ErrorBundle.String = switch (dep_node.unit.unwrap()) {
4803 const msg: std.zig.ErrorBundle.String = if (dep_node.unit == source_unit) switch (source_unit.unwrap()) {
4804 .@"comptime" => unreachable, // cannot be involved in a dependency loop
4805 .nav_ty, .nav_val => try eb.printString("{f} depends on itself here", .{fmt_source}),
4806 .memoized_state => unreachable, // memoized_state definitely does not *directly* depend on itself
4807 .func => try eb.printString("{f} uses its own inferred error set here", .{fmt_source}),
4808 .type_layout => try eb.printString("{f} depends on itself {s}", .{
4809 fmt_source,
4810 dep_node.reason.type_layout_reason.msg(),
4811 }),
4812 } else switch (dep_node.unit.unwrap()) {
47934813 .@"comptime" => unreachable, // cannot be involved in a dependency loop
47944814 .nav_val => |nav| try eb.printString("{f} uses value of declaration '{f}' here", .{
47954815 fmt_source, ip.getNav(nav).fqn.fmt(ip),