authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-26 19:08:11-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-26 19:33:42-04:00
log738fb7835f366dab6bc15ddbaecc0b334f2bb1f9
treed374a796e3e94740ccfe313d3c11973397bef955
parent44524cbf51a14d6eed0b81f97b2b267783038e72

Runner: more error set cleanup


1 files changed, 118 insertions(+), 51 deletions(-)

test/src/Runner.zig+118-51
......@@ -1,6 +1,7 @@
11const assert = std.debug.assert;
22const std = @import("std");
33const Runner = @This();
4const zig_version_string = @import("builtin").zig_version_string;
45
56gpa: std.mem.Allocator,
67arena: *std.heap.ArenaAllocator,
......@@ -51,24 +52,33 @@ fn deinit(runner: *Runner) void {
5152 runner.* = undefined;
5253}
5354
54const Fallible = error{AlreadyReported} || std.mem.Allocator.Error || std.Io.Cancelable;
55fn fail(runner: *Runner, comptime fmt: []const u8, args: anytype) Fallible {
55const FailError = error{AlreadyReported} || std.mem.Allocator.Error || std.Io.Cancelable;
56fn fail(runner: *Runner, comptime fmt: []const u8, args: anytype) FailError {
5657 return runner.failString(try runner.eb_wip.printString(fmt, args));
5758}
58fn failString(runner: *Runner, msg: std.zig.ErrorBundle.String) Fallible {
59fn failString(runner: *Runner, msg: std.zig.ErrorBundle.String) FailError {
5960 try runner.eb_wip.addRootErrorMessage(.{
6061 .msg = msg,
6162 });
6263 return error.AlreadyReported;
6364}
6465
65pub const ProtocolError = Fallible || std.Io.Reader.Error || std.Io.Writer.Error;
66pub const ProtocolError = error{
67 ServerReadFailed,
68 ServerWriteFailed,
69 ServerEndOfStream,
70} || FailError;
6671pub fn runServer(runner: *Runner) ProtocolError {
67 try runner.server.serveStringMessage(.zig_version, @import("builtin").zig_version_string);
72 runner.server.serveStringMessage(.zig_version, zig_version_string) catch |err| switch (err) {
73 error.WriteFailed => return error.ServerWriteFailed,
74 };
6875 while (true) {
6976 _ = runner.arena.reset(.retain_capacity);
7077 const arena = runner.arena.allocator();
71 const hdr = try runner.server.receiveMessage();
78 const hdr = runner.server.receiveMessage() catch |err| switch (err) {
79 error.ReadFailed => return error.ServerReadFailed,
80 error.EndOfStream => return error.ServerEndOfStream,
81 };
7282 switch (hdr.tag) {
7383 else => |tag| return runner.fail("unsupported message: {t}", .{tag}),
7484 .exit => std.process.exit(0),
......@@ -273,16 +283,20 @@ pub fn runServer(runner: *Runner) ProtocolError {
273283 .query_test_metadata => {
274284 const expected_panic_msgs = try arena.alloc(u32, runner.args.targets.items.len);
275285 @memset(expected_panic_msgs, 0);
276 try runner.server.serveTestMetadata(.{
286 runner.server.serveTestMetadata(.{
277287 .names = runner.args.targets.items,
278288 .expected_panic_msgs = expected_panic_msgs,
279289 .string_bytes = runner.args.target_bytes.items,
280 });
290 }) catch |err| switch (err) {
291 error.WriteFailed => return error.ServerWriteFailed,
292 };
281293 },
282294 .run_test => {
283295 const test_index = runner.server.receiveBody_u32() catch unreachable;
284 try runner.server.serveBodylessMessage(.test_started);
285 try runner.server.serveTestResults(.{
296 runner.server.serveBodylessMessage(.test_started) catch |err| switch (err) {
297 error.WriteFailed => return error.ServerWriteFailed,
298 };
299 runner.server.serveTestResults(.{
286300 .index = test_index,
287301 .flags = .{
288302 .status = if (runner.testOne(test_index))
......@@ -290,14 +304,18 @@ pub fn runServer(runner: *Runner) ProtocolError {
290304 else |err| status: switch (err) {
291305 error.Canceled,
292306 error.OutOfMemory,
293 error.ReadFailed,
294 error.WriteFailed,
307 error.ServerWriteFailed,
295308 => |e| return e,
296309 error.AlreadyReported => {
297310 var eb = try runner.eb_wip.toOwnedBundle("");
298311 defer eb.deinit(runner.gpa);
299312 assert(eb.errorMessageCount() > 0); // already reported what?
300 try runner.server.serveErrorBundle(.error_bundle, eb);
313 runner.server.serveErrorBundle(
314 .error_bundle,
315 eb,
316 ) catch |server_err| switch (server_err) {
317 error.WriteFailed => return error.ServerWriteFailed,
318 };
301319 const eb_wip: std.zig.ErrorBundle.Wip = try .init(runner.gpa);
302320 runner.eb_wip.deinit();
303321 runner.eb_wip = eb_wip;
......@@ -309,7 +327,9 @@ pub fn runServer(runner: *Runner) ProtocolError {
309327 .log_err_count = 0,
310328 .leak_count = 0,
311329 },
312 });
330 }) catch |err| switch (err) {
331 error.WriteFailed => return error.ServerWriteFailed,
332 };
313333 assert(runner.eb_wip.root_list.items.len == 0); // failed to report
314334 },
315335 }
......@@ -320,6 +340,15 @@ fn discoverInput(
320340 runner: *Runner,
321341 dir: std.zig.Server.Message.InputDir,
322342 sub_path: []const u8,
343) error{ServerWriteFailed}!void {
344 return runner.discoverInputInner(dir, sub_path) catch |err| switch (err) {
345 error.WriteFailed => return error.ServerWriteFailed,
346 };
347}
348fn discoverInputInner(
349 runner: *Runner,
350 dir: std.zig.Server.Message.InputDir,
351 sub_path: []const u8,
323352) std.Io.Writer.Error!void {
324353 try runner.server.serveMessageHeader(.{
325354 .tag = .discovered_inputs,
......@@ -435,14 +464,14 @@ pub const SourceReader = struct {
435464 src_loc: []const u8,
436465 comptime fmt: []const u8,
437466 args: anytype,
438 ) Fallible {
467 ) FailError {
439468 return s.failString(src_loc, try s.eb_wip.printString(fmt, args));
440469 }
441470 fn failString(
442471 s: *SourceReader,
443472 src_loc: []const u8,
444473 msg: std.zig.ErrorBundle.String,
445 ) Fallible {
474 ) FailError {
446475 const line: u32, const column: u32, const source_line = src_loc: {
447476 const pos = src_loc.ptr - s.interface.buffer.ptr;
448477 const end = std.mem.findScalarPos(u8, s.interface.buffer, pos, '\n') orelse
......@@ -531,8 +560,8 @@ const Update = struct {
531560
532561const TestError = error{
533562 SkipTest,
534} || Fallible || std.Io.Reader.ShortError || std.Io.Writer.Error;
535fn testOne(runner: *Runner, test_index: u32) TestError!void {
563} || FailError;
564fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestError)!void {
536565 const target_query =
537566 std.mem.sliceTo(runner.args.target_bytes.items[runner.args.targets.items[test_index]..], 0);
538567 const manifest_file = runner.args.manifest_file orelse
......@@ -660,16 +689,24 @@ fn testOne(runner: *Runner, test_index: u32) TestError!void {
660689 error.OutOfMemory,
661690 error.AlreadyReported,
662691 error.SkipTest,
663 error.WriteFailed,
664692 => |e| return e,
665 error.ReadFailed => switch (contents_impl) {
693 error.ContentsReadFailed => switch (contents_impl) {
666694 .ending => unreachable,
667 .dr => return runner.fail("unable to read manifest: {t}", .{manifest_fr.err.?}),
668 .fr => |fr| return runner.fail("unable to read contents file: {t}", .{fr.err.?}),
695 .dr => switch (manifest_fr.err orelse return error.OutOfMemory) {
696 error.Canceled => |e| return e,
697 else => |e| return runner.fail("unable to read manifest: {t}", .{e}),
698 },
699 .fr => |fr| switch (fr.err.?) {
700 error.Canceled => |e| return e,
701 else => |e| return runner.fail("unable to read contents file: {t}", .{e}),
702 },
669703 },
670704 };
671705 } else |err| switch (err) {
672 error.ReadFailed => |e| return e,
706 error.ReadFailed => switch (manifest_fr.err orelse return error.OutOfMemory) {
707 error.Canceled => |e| return e,
708 else => |e| return runner.fail("unable to read manifest: {t}", .{e}),
709 },
673710 error.StreamTooLong => unreachable,
674711 error.EndOfStream => if (skip_delimiter)
675712 return runner.fail("manifest missing \"#}}\" delimiter", .{}),
......@@ -687,7 +724,7 @@ fn handleCommand(
687724 cmd: Command,
688725 arg: ?[]const u8,
689726 contents_r: *std.Io.Reader,
690) TestError!void {
727) (error{ContentsReadFailed} || TestError)!void {
691728 var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined;
692729 const cmd_prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "#{t}{s}{s}", .{
693730 cmd, if (arg) |_| " " else "", arg orelse "",
......@@ -702,9 +739,8 @@ fn handleCommand(
702739 cmd_src_loc,
703740 "\"#skip\" must appear before other commands",
704741 .{},
705 ) else if (std.mem.eql(u8, update.target_query, arg.?))
706 return error.SkipTest,
707 .exe, .lib, .obj => try runner.spawnCompiler(&update.compiler, update.src_dir, switch (cmd) {
742 ) else if (std.mem.eql(u8, update.target_query, arg.?)) return error.SkipTest,
743 .exe, .lib, .obj => runner.spawnCompiler(&update.compiler, update.src_dir, switch (cmd) {
708744 else => unreachable,
709745 .exe => .Exe,
710746 .lib => .Lib,
......@@ -746,7 +782,10 @@ fn handleCommand(
746782 .mode = mode,
747783 .backend = backend,
748784 };
749 }),
785 }) catch |err| switch (err) {
786 error.Canceled, error.OutOfMemory, error.AlreadyReported => |e| return e,
787 error.ReadFailed => return error.ContentsReadFailed,
788 },
750789 .write => {
751790 const file = update.src_dir.createFile(runner.io, arg.?, .{}) catch |err| switch (err) {
752791 error.Canceled => |e| return e,
......@@ -756,7 +795,7 @@ fn handleCommand(
756795 var fw_buffer: [512]u8 = undefined;
757796 var fw = file.writer(runner.io, &fw_buffer);
758797 _ = contents_r.streamRemaining(&fw.interface) catch |err| switch (err) {
759 error.ReadFailed => |e| return e,
798 error.ReadFailed => return error.ContentsReadFailed,
760799 error.WriteFailed => switch (fw.err.?) {
761800 error.Canceled => |e| return e,
762801 else => |e| return update.manifest_sr.fail(
......@@ -797,7 +836,9 @@ fn handleCommand(
797836 ));
798837 update.prog_node.end();
799838 update.prog_node = runner.prog_node.start(
800 switch (try contents_r.readSliceShort(&name_buffer)) {
839 switch (contents_r.readSliceShort(&name_buffer) catch |err| switch (err) {
840 error.ReadFailed => return error.ContentsReadFailed,
841 }) {
801842 0 => switch (update.num) {
802843 0 => "initial update",
803844 else => |num| std.mem.print(&name_buffer, "update {d}", .{num}) catch
......@@ -807,10 +848,17 @@ fn handleCommand(
807848 },
808849 0,
809850 );
810 _ = try contents_r.discardRemaining();
851 _ = contents_r.discardRemaining() catch |err| switch (err) {
852 error.ReadFailed => return error.ContentsReadFailed,
853 };
811854 if (comp.state != .idle)
812855 return update.manifest_sr.fail(cmd_src_loc, "missing \"#check\"", .{});
813 try comp.client.serveBodylessMessage(.update);
856 comp.client.serveBodylessMessage(.update) catch |err| switch (err) {
857 error.WriteFailed => switch (comp.fw.err.?) {
858 error.Canceled => |e| return e,
859 else => |e| return runner.fail("unable to send message to compiler: {t}", .{e}),
860 },
861 };
814862 comp.state = .update;
815863 update.mtime = update.mtime.addDuration(.fromSeconds(2));
816864 update.num += 1;
......@@ -820,7 +868,8 @@ fn handleCommand(
820868 return update.manifest_sr.fail(arg.?, "unknown check", .{});
821869 const expected =
822870 contents_r.allocRemaining(runner.gpa, .unlimited) catch |err| switch (err) {
823 error.OutOfMemory, error.ReadFailed => |e| return e,
871 error.OutOfMemory => |e| return e,
872 error.ReadFailed => return error.ContentsReadFailed,
824873 error.StreamTooLong => unreachable, // .unlimited
825874 };
826875 defer runner.gpa.free(expected);
......@@ -860,11 +909,13 @@ fn handleCommand(
860909 .errors => {
861910 var error_aw: std.Io.Writer.Allocating = .init(runner.gpa);
862911 defer error_aw.deinit();
863 try eb.renderToWriter(.{
912 eb.renderToWriter(.{
864913 .include_reference_trace = false,
865914 .include_source_line = false,
866915 .include_log_text = true,
867 }, &error_aw.writer);
916 }, &error_aw.writer) catch |err| switch (err) {
917 error.WriteFailed => return error.OutOfMemory,
918 };
868919 const actual = error_aw.written();
869920 std.mem.replaceScalar(u8, actual, '\\', '/');
870921 std.testing.expectEqualStrings(expected, actual) catch |err| switch (err) {
......@@ -900,7 +951,9 @@ fn handleCommand(
900951 return runner.fail("compiler failed to send terminating error_bundle", .{});
901952 },
902953 }
903 assert(try contents_r.discardRemaining() == 0);
954 assert(contents_r.discardRemaining() catch |err| switch (err) {
955 error.ReadFailed => return error.ContentsReadFailed,
956 } == 0);
904957 switch (cmd) {
905958 .todo, .skip => {},
906959 else => update.allow_skip = false,
......@@ -914,7 +967,7 @@ fn spawnCompiler(
914967 output_mode: std.lang.OutputMode,
915968 args_r: *std.Io.Reader,
916969 target: Compiler.Target,
917) (Fallible || std.Io.Reader.ShortError)!void {
970) (std.Io.Reader.ShortError || FailError)!void {
918971 const gpa = runner.gpa;
919972 const arena = runner.arena.allocator();
920973 if (compiler.*) |*comp| {
......@@ -1072,7 +1125,7 @@ const Compiler = struct {
10721125 };
10731126 };
10741127
1075 fn receiveMessage(comp: *Compiler) Fallible!?struct {
1128 fn receiveMessage(comp: *Compiler) FailError!?struct {
10761129 tag: std.zig.Server.Message.Tag,
10771130 body: []const u8,
10781131 } {
......@@ -1107,7 +1160,7 @@ const Compiler = struct {
11071160 expected: []const u8,
11081161 src_dir: std.Io.Dir,
11091162 digest: *const std.Build.Cache.BinDigest,
1110 ) Fallible!void {
1163 ) FailError!void {
11111164 const runner = comp.runner;
11121165 const gpa = runner.gpa;
11131166 const arena = runner.arena.allocator();
......@@ -1288,7 +1341,7 @@ const Compiler = struct {
12881341 }
12891342 }
12901343
1291 fn compileC(parent_comp: *Compiler, src_dir: std.Io.Dir, c_path: []const u8) Fallible![]const u8 {
1344 fn compileC(parent_comp: *Compiler, src_dir: std.Io.Dir, c_path: []const u8) FailError![]const u8 {
12921345 const runner = parent_comp.runner;
12931346 const arena = runner.arena.allocator();
12941347 var compiler: ?Compiler = null;
......@@ -1308,7 +1361,10 @@ const Compiler = struct {
13081361 };
13091362 const comp = &compiler.?;
13101363 comp.client.serveBodylessMessage(.update) catch |err| switch (err) {
1311 error.WriteFailed => return runner.fail("unable to send message: {t}", .{comp.fw.err.?}),
1364 error.WriteFailed => switch (comp.fw.err.?) {
1365 error.Canceled => |e| return e,
1366 else => |e| return runner.fail("unable to send message: {t}", .{e}),
1367 },
13121368 };
13131369 comp.state = .update;
13141370 var out_path: ?[]const u8 = null;
......@@ -1348,7 +1404,7 @@ const Compiler = struct {
13481404 return out_path.?;
13491405 }
13501406
1351 fn exit(comp: *Compiler) Fallible!void {
1407 fn exit(comp: *Compiler) FailError!void {
13521408 const runner = comp.runner;
13531409 comp.client.serveBodylessMessage(.exit) catch |err| switch (err) {
13541410 error.WriteFailed => switch (comp.fw.err.?) {
......@@ -1465,9 +1521,15 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl
14651521 defer runner.deinit();
14661522 switch (runner.runServer()) {
14671523 error.Canceled, error.OutOfMemory => |e| return e,
1468 error.ReadFailed => fatal("unable to receive message: {t}", .{stdin.err.?}),
1469 error.EndOfStream => fatal("no more messages", .{}),
1470 error.WriteFailed => fatal("unable to send message: {t}", .{stdout.err.?}),
1524 error.ServerReadFailed => switch (stdin.err.?) {
1525 error.Canceled => |e| return e,
1526 else => |e| fatal("unable to receive message: {t}", .{e}),
1527 },
1528 error.ServerWriteFailed => switch (stdout.err.?) {
1529 error.Canceled => |e| return e,
1530 else => |e| fatal("unable to send message: {t}", .{e}),
1531 },
1532 error.ServerEndOfStream => fatal("no more messages", .{}),
14711533 error.AlreadyReported => {
14721534 var eb = try runner.eb_wip.toOwnedBundle("");
14731535 defer eb.deinit(init.gpa);
......@@ -1590,9 +1652,15 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl
15901652 };
15911653 const success = runClient(init.gpa, arena, init.io, &client, &args) catch |err| switch (err) {
15921654 error.OutOfMemory => |e| return e,
1593 error.ReadFailed => fatal("unable to receive message: {t}", .{child_reader.err.?}),
1655 error.ReadFailed => switch (child_reader.err.?) {
1656 error.Canceled => |e| return e,
1657 else => |e| fatal("unable to receive message: {t}", .{e}),
1658 },
1659 error.WriteFailed => switch (child_writer.err.?) {
1660 error.Canceled => |e| return e,
1661 else => |e| fatal("unable to send message: {t}", .{e}),
1662 },
15941663 error.EndOfStream => fatal("no more messages", .{}),
1595 error.WriteFailed => fatal("unable to send message: {t}", .{child_writer.err.?}),
15961664 };
15971665 _ = child.wait(init.io) catch |err| switch (err) {
15981666 error.Canceled => |e| return e,
......@@ -1734,12 +1802,11 @@ fn runClient(
17341802 switch (hdr.tag) {
17351803 else => try client.in.discardAll(hdr.bytes_len),
17361804 .zig_version => {
1737 const expected = @import("builtin").zig_version_string;
1738 const actual = try client.in.take(hdr.bytes_len);
1739 if (!std.mem.eql(u8, expected, actual)) {
1805 const actual_version = try client.in.take(hdr.bytes_len);
1806 if (!std.mem.eql(u8, zig_version_string, actual_version)) {
17401807 try stderr.print(
17411808 "error: zig version mismatch compiler test runner vs compiler: {q} vs {q}\n",
1742 .{ expected, actual },
1809 .{ zig_version_string, actual_version },
17431810 );
17441811 try stderr.flush();
17451812 std.process.exit(1);