From ec261c5e8d569a7bf90a51638d41de6053f98e1a Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 19 Sep 2026 06:52:35 -0400 Subject: [PATCH] test-incremental: convert tests to new format --- build.zig | 19 +- test/incremental/add_decl | 63 +- test/incremental/add_decl_namespaced | 65 +- ..._field_and_nested_struct_uses_changed_decl | 22 +- test/incremental/add_remove_struct_fields | 93 -- .../add_remove_struct_fields/0/main.zig | 19 + .../add_remove_struct_fields/1/main.zig | 19 + .../add_remove_struct_fields/2/main.zig | 19 + .../add_remove_struct_fields/3/main.zig | 20 + .../add_remove_struct_fields/manifest | 31 + test/incremental/add_remove_toplevel_fields | 96 -- .../add_remove_toplevel_fields/0/main.zig | 20 + .../add_remove_toplevel_fields/1/main.zig | 21 + .../add_remove_toplevel_fields/2/main.zig | 19 + .../add_remove_toplevel_fields/3/main.zig | 20 + .../add_remove_toplevel_fields/manifest | 31 + .../analysis_error_and_syntax_error | 62 +- test/incremental/bad_import | 40 +- test/incremental/change_bitpack_backing_int | 83 +- test/incremental/change_container_kind | 135 ++- test/incremental/change_embed_file | 65 +- test/incremental/change_enum_tag_type | 93 -- .../change_enum_tag_type/0/main.zig | 15 + .../change_enum_tag_type/1/main.zig | 21 + .../change_enum_tag_type/2/main.zig | 16 + .../change_enum_tag_type/3/main.zig | 12 + .../change_enum_tag_type/4/main.zig | 12 + .../incremental/change_enum_tag_type/manifest | 43 + test/incremental/change_exports | 169 --- test/incremental/change_exports/0/main.zig | 17 + test/incremental/change_exports/1/main.zig | 19 + test/incremental/change_exports/2/main.zig | 19 + test/incremental/change_exports/3/main.zig | 22 + test/incremental/change_exports/4/main.zig | 17 + test/incremental/change_exports/5/main.zig | 22 + test/incremental/change_exports/6/main.zig | 22 + test/incremental/change_exports/manifest | 54 + test/incremental/change_fn_type | 33 +- test/incremental/change_generic_line_number | 26 +- test/incremental/change_line_number | 24 +- test/incremental/change_module | 72 +- test/incremental/change_panic_handler | 33 +- .../incremental/change_panic_handler_explicit | 149 --- .../change_panic_handler_explicit/0/main.zig | 0 .../change_panic_handler_explicit/1/main.zig | 0 .../change_panic_handler_explicit/2/main.zig | 0 .../change_panic_handler_explicit/manifest | 0 .../change_reify_struct_field_type | 22 +- test/incremental/change_shift_op | 24 +- test/incremental/change_struct_same_fields | 33 +- test/incremental/change_union_tag_type | 35 +- test/incremental/change_zon_file | 69 +- .../change_zon_file_no_result_type | 26 +- test/incremental/compile_error_then_log | 32 +- test/incremental/compile_log | 38 +- test/incremental/delete_comptime_decls | 29 +- .../dependency_on_type_of_inferred_global | 23 +- test/incremental/do_nothing | 26 +- test/incremental/fix_astgen_failure | 50 +- test/incremental/function_becomes_inline | 34 +- test/incremental/hello | 24 +- test/incremental/increase_array_field_length | 23 +- test/incremental/make_decl_pub | 28 +- test/incremental/modify_inline_fn | 24 +- test/incremental/move_src | 23 +- .../pointer_to_decl_with_astgen_error | 31 +- .../recursive_function_becomes_non_recursive | 23 +- test/incremental/remove_enum_field | 30 +- .../remove_function_with_changed_callee | 22 +- .../remove_invalid_union_backing_enum | 25 +- .../struct_reification_becomes_anon_init | 23 +- test/incremental/tag_name | 32 +- ...porary_analysis_error_in_generic_signature | 35 +- test/incremental/temporary_parse_error | 31 +- test/incremental/type_becomes_comptime_only | 30 +- test/incremental/type_dependency_loop | 62 +- test/incremental/unreferenced_error | 43 +- test/incremental2/bad_import | 48 - test/incremental2/hello | 28 - test/src/runner.zig | 19 +- test/tests.zig | 99 +- tools/incr-check.zig | 1032 ----------------- 82 files changed, 1739 insertions(+), 2309 deletions(-) delete mode 100644 test/incremental/add_remove_struct_fields create mode 100644 test/incremental/add_remove_struct_fields/0/main.zig create mode 100644 test/incremental/add_remove_struct_fields/1/main.zig create mode 100644 test/incremental/add_remove_struct_fields/2/main.zig create mode 100644 test/incremental/add_remove_struct_fields/3/main.zig create mode 100644 test/incremental/add_remove_struct_fields/manifest delete mode 100644 test/incremental/add_remove_toplevel_fields create mode 100644 test/incremental/add_remove_toplevel_fields/0/main.zig create mode 100644 test/incremental/add_remove_toplevel_fields/1/main.zig create mode 100644 test/incremental/add_remove_toplevel_fields/2/main.zig create mode 100644 test/incremental/add_remove_toplevel_fields/3/main.zig create mode 100644 test/incremental/add_remove_toplevel_fields/manifest delete mode 100644 test/incremental/change_enum_tag_type create mode 100644 test/incremental/change_enum_tag_type/0/main.zig create mode 100644 test/incremental/change_enum_tag_type/1/main.zig create mode 100644 test/incremental/change_enum_tag_type/2/main.zig create mode 100644 test/incremental/change_enum_tag_type/3/main.zig create mode 100644 test/incremental/change_enum_tag_type/4/main.zig create mode 100644 test/incremental/change_enum_tag_type/manifest delete mode 100644 test/incremental/change_exports create mode 100644 test/incremental/change_exports/0/main.zig create mode 100644 test/incremental/change_exports/1/main.zig create mode 100644 test/incremental/change_exports/2/main.zig create mode 100644 test/incremental/change_exports/3/main.zig create mode 100644 test/incremental/change_exports/4/main.zig create mode 100644 test/incremental/change_exports/5/main.zig create mode 100644 test/incremental/change_exports/6/main.zig create mode 100644 test/incremental/change_exports/manifest delete mode 100644 test/incremental/change_panic_handler_explicit rename test/{incremental2 => incremental}/change_panic_handler_explicit/0/main.zig (100%) rename test/{incremental2 => incremental}/change_panic_handler_explicit/1/main.zig (100%) rename test/{incremental2 => incremental}/change_panic_handler_explicit/2/main.zig (100%) rename test/{incremental2 => incremental}/change_panic_handler_explicit/manifest (100%) delete mode 100644 test/incremental2/bad_import delete mode 100644 test/incremental2/hello delete mode 100644 tools/incr-check.zig diff --git a/build.zig b/build.zig index df065484e061352b3f5a33eebcc3c969d7d87b93..bc09ce6393c0598245d43f16e07bd5fbf72d72b7 100644 --- a/build.zig +++ b/build.zig @@ -125,7 +125,6 @@ pub fn build(b: *std.Build) !void { const skip_darwin = b.option(bool, "skip-darwin", "Main test suite skips targets with darwin OSs") orelse false; const skip_linux = b.option(bool, "skip-linux", "Main test suite skips targets with linux OS") orelse false; const skip_llvm = b.option(bool, "skip-llvm", "Main test suite skips targets that use LLVM backend") orelse false; - const skip_test_incremental = b.option(bool, "skip-test-incremental", "Main test step omits dependency on test-incremental step") orelse false; const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false; @@ -781,22 +780,6 @@ pub fn build(b: *std.Build) !void { test_step.dependOn(check_oracle_step); } - const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases"); - try tests.addIncrementalTests(b, test_incremental_step, .{ - .test_filters = test_filters, - .test_target_filters = test_target_filters, - .skip_non_native = skip_non_native, - .skip_wasm = skip_wasm, - .skip_freebsd = skip_freebsd, - .skip_netbsd = skip_netbsd, - .skip_openbsd = skip_openbsd, - .skip_windows = skip_windows, - .skip_darwin = skip_darwin, - .skip_linux = skip_linux, - .skip_llvm = skip_llvm, - }); - if (!skip_test_incremental) test_step.dependOn(test_incremental_step); - if (tests.addLibcTestNszTests(b, .{ .optimize_modes = optimize_modes, .test_filters = test_filters, @@ -812,7 +795,7 @@ pub fn build(b: *std.Build) !void { .target = b.graph.host, }), }); - test_step.dependOn(try tests.addNewIncrementalTests(b, runner, .{ + test_step.dependOn(try tests.addIncrementalTests(b, runner, .{ .test_filters = test_filters, .test_target_filters = test_target_filters, .skip_non_native = skip_non_native, diff --git a/test/incremental/add_decl b/test/incremental/add_decl index 50d961da7b88f00b78b2895ebfeae18e76219d6a..5832015217c571a79a2bc5ca0ab45abf91d7a156 100644 --- a/test/incremental/add_decl +++ b/test/incremental/add_decl @@ -1,15 +1,21 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, foo); } const foo = "good morning\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="good morning\n" +#} +#update +#check stdout { +good morning +#} -#update=add new declaration -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, foo); @@ -17,10 +23,14 @@ pub fn main() !void { const foo = "good morning\n"; const bar = "good evening\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="good morning\n" +#} +#update { +add new declaration#} +#check stdout { +good morning +#} -#update=reference new declaration -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, bar); @@ -28,10 +38,14 @@ pub fn main() !void { const foo = "good morning\n"; const bar = "good evening\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="good evening\n" +#} +#update { +reference new declaration#} +#check stdout { +good evening +#} -#update=reference missing declaration -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, qux); @@ -39,10 +53,14 @@ pub fn main() !void { const foo = "good morning\n"; const bar = "good evening\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:3:52: error: use of undeclared identifier 'qux' +#} +#update { +reference missing declaration#} +#check errors { +main.zig:3:52: error: use of undeclared identifier 'qux' +#} -#update=add missing declaration -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, qux); @@ -51,14 +69,23 @@ const foo = "good morning\n"; const bar = "good evening\n"; const qux = "good night\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="good night\n" +#} +#update { +add missing declaration#} +#check stdout { +good night +#} -#update=remove unused declarations -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, qux); } const qux = "good night\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="good night\n" +#} +#update { +remove unused declarations#} +#check stdout { +good night +#} diff --git a/test/incremental/add_decl_namespaced b/test/incremental/add_decl_namespaced index e1fa74a3ad7ecd6bb70b481f73d6db0702c27d22..30bf6a81e9abb3449ad1575a20022b7d6f0d279f 100644 --- a/test/incremental/add_decl_namespaced +++ b/test/incremental/add_decl_namespaced @@ -1,15 +1,21 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @This().foo); } const foo = "good morning\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="good morning\n" +#} +#update +#check stdout { +good morning +#} -#update=add new declaration -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @This().foo); @@ -17,10 +23,14 @@ pub fn main() !void { const foo = "good morning\n"; const bar = "good evening\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="good morning\n" +#} +#update { +add new declaration#} +#check stdout { +good morning +#} -#update=reference new declaration -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @This().bar); @@ -28,10 +38,14 @@ pub fn main() !void { const foo = "good morning\n"; const bar = "good evening\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="good evening\n" +#} +#update { +reference new declaration#} +#check stdout { +good evening +#} -#update=reference missing declaration -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @This().qux); @@ -39,11 +53,15 @@ pub fn main() !void { const foo = "good morning\n"; const bar = "good evening\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:3:59: error: root source file struct 'main' has no member named 'qux' -#expect_error=main.zig:1:1: note: struct declared here +#} +#update { +reference missing declaration#} +#check errors { +main.zig:3:59: error: root source file struct 'main' has no member named 'qux' +main.zig:1:1: note: struct declared here +#} -#update=add missing declaration -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @This().qux); @@ -52,14 +70,23 @@ const foo = "good morning\n"; const bar = "good evening\n"; const qux = "good night\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="good night\n" +#} +#update { +add missing declaration#} +#check stdout { +good night +#} -#update=remove unused declarations -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @This().qux); } const qux = "good night\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="good night\n" +#} +#update { +remove unused declarations#} +#check stdout { +good night +#} diff --git a/test/incremental/add_field_and_nested_struct_uses_changed_decl b/test/incremental/add_field_and_nested_struct_uses_changed_decl index 35882c10a3fcda7d06a2ca968226e3c545d29c12..731d34837bc82b9b3ffac774943f53ffad77d468 100644 --- a/test/incremental/add_field_and_nested_struct_uses_changed_decl +++ b/test/incremental/add_field_and_nested_struct_uses_changed_decl @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub fn main() void { _ = @as(S, undefined); } @@ -9,9 +12,12 @@ const SomeType = u8; const S = struct { foo: struct { inner: SomeType }, }; -#expect_stdout="" -#update=add field to outer struct, change decl used by inner struct -#file=main.zig +#} +#update +#check stdout { +#} + +#write main.zig { pub fn main() void { _ = @as(S, undefined); } @@ -22,4 +28,8 @@ const S = struct { foo: struct { inner: SomeType }, bar: u32, }; -#expect_stdout="" +#} +#update { +add field to outer struct, change decl used by inner struct#} +#check stdout { +#} diff --git a/test/incremental/add_remove_struct_fields b/test/incremental/add_remove_struct_fields deleted file mode 100644 index f5e62fad787f9c2e96a2cdcf476173732cfe32f6..0000000000000000000000000000000000000000 --- a/test/incremental/add_remove_struct_fields +++ /dev/null @@ -1,93 +0,0 @@ -#update=initial version -#file=main.zig -const S = struct { x: u8 }; -pub fn main(init: std.process.Init) !void { - var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); - printFieldCount(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; - printOneField(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; -} -fn printFieldCount(w: *Writer) Writer.Error!void { - try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); -} -fn printOneField(w: *Writer) Writer.Error!void { - const val: S = .{ .x = 100 }; - try w.print("{d}\n", .{val.x}); -} -const std = @import("std"); -const Writer = std.Io.Writer; -#expect_stdout="1 100\n" - -#update=add a field -#file=main.zig -const S = struct { x: u8, y: u16 = 200 }; -pub fn main(init: std.process.Init) !void { - var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); - printFieldCount(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; - printOneField(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; -} -fn printFieldCount(w: *Writer) Writer.Error!void { - try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); -} -fn printOneField(w: *Writer) Writer.Error!void { - const val: S = .{ .x = 100 }; - try w.print("{d}\n", .{val.x}); -} -const std = @import("std"); -const Writer = std.Io.Writer; -#expect_stdout="2 100\n" - -#update=remove all fields -#file=main.zig -const S = struct {}; -pub fn main(init: std.process.Init) !void { - var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); - printFieldCount(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; - printOneField(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; -} -fn printFieldCount(w: *Writer) Writer.Error!void { - try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); -} -fn printOneField(w: *Writer) Writer.Error!void { - const val: S = .{ .x = 100 }; - try w.print("{d}\n", .{val.x}); -} -const std = @import("std"); -const Writer = std.Io.Writer; -#expect_error=main.zig:15:24: error: no field named 'x' in struct 'main.S' -#expect_error=main.zig:1:11: note: struct declared here - -#update=remove reference to non-existent field -#file=main.zig -const S = struct {}; -pub fn main(init: std.process.Init) !void { - var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); - printFieldCount(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; - printOneField(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; -} -fn printFieldCount(w: *Writer) Writer.Error!void { - try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); -} -fn printOneField(w: *Writer) Writer.Error!void { - //const val: S = .{ .x = 100 }; - //try w.print("{d}\n", .{val.x}); - try w.writeAll("\n"); -} -const std = @import("std"); -const Writer = std.Io.Writer; -#expect_stdout="0 \n" diff --git a/test/incremental/add_remove_struct_fields/0/main.zig b/test/incremental/add_remove_struct_fields/0/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..0481e7418f5889de45d38cb7033e498831d8305a --- /dev/null +++ b/test/incremental/add_remove_struct_fields/0/main.zig @@ -0,0 +1,19 @@ +const S = struct { x: u8 }; +pub fn main(init: std.process.Init) !void { + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + printFieldCount(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; + printOneField(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; +} +fn printFieldCount(w: *Writer) Writer.Error!void { + try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); +} +fn printOneField(w: *Writer) Writer.Error!void { + const val: S = .{ .x = 100 }; + try w.print("{d}\n", .{val.x}); +} +const std = @import("std"); +const Writer = std.Io.Writer; diff --git a/test/incremental/add_remove_struct_fields/1/main.zig b/test/incremental/add_remove_struct_fields/1/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..82305cdf3a00d0d56681a196b94e8cfff72710bd --- /dev/null +++ b/test/incremental/add_remove_struct_fields/1/main.zig @@ -0,0 +1,19 @@ +const S = struct { x: u8, y: u16 = 200 }; +pub fn main(init: std.process.Init) !void { + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + printFieldCount(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; + printOneField(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; +} +fn printFieldCount(w: *Writer) Writer.Error!void { + try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); +} +fn printOneField(w: *Writer) Writer.Error!void { + const val: S = .{ .x = 100 }; + try w.print("{d}\n", .{val.x}); +} +const std = @import("std"); +const Writer = std.Io.Writer; diff --git a/test/incremental/add_remove_struct_fields/2/main.zig b/test/incremental/add_remove_struct_fields/2/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..b490c06b2315fce7bbbd8c9c24729adcb6e12084 --- /dev/null +++ b/test/incremental/add_remove_struct_fields/2/main.zig @@ -0,0 +1,19 @@ +const S = struct {}; +pub fn main(init: std.process.Init) !void { + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + printFieldCount(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; + printOneField(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; +} +fn printFieldCount(w: *Writer) Writer.Error!void { + try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); +} +fn printOneField(w: *Writer) Writer.Error!void { + const val: S = .{ .x = 100 }; + try w.print("{d}\n", .{val.x}); +} +const std = @import("std"); +const Writer = std.Io.Writer; diff --git a/test/incremental/add_remove_struct_fields/3/main.zig b/test/incremental/add_remove_struct_fields/3/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..62ca3461d6ee668ee6dbd046e127b8fafead8f8b --- /dev/null +++ b/test/incremental/add_remove_struct_fields/3/main.zig @@ -0,0 +1,20 @@ +const S = struct {}; +pub fn main(init: std.process.Init) !void { + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + printFieldCount(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; + printOneField(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; +} +fn printFieldCount(w: *Writer) Writer.Error!void { + try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); +} +fn printOneField(w: *Writer) Writer.Error!void { + //const val: S = .{ .x = 100 }; + //try w.print("{d}\n", .{val.x}); + try w.writeAll("\n"); +} +const std = @import("std"); +const Writer = std.Io.Writer; diff --git a/test/incremental/add_remove_struct_fields/manifest b/test/incremental/add_remove_struct_fields/manifest new file mode 100644 index 0000000000000000000000000000000000000000..2099e73cef2d89db7446cfe1c9f3a82057332248 --- /dev/null +++ b/test/incremental/add_remove_struct_fields/manifest @@ -0,0 +1,31 @@ +#exe { +-Mroot=main.zig +#} + +#write main.zig 0/main.zig +#update +#check stdout { +1 100 +#} + +#write main.zig 1/main.zig +#update { +add a field#} +#check stdout { +2 100 +#} + +#write main.zig 2/main.zig +#update { +remove all fields#} +#check errors { +main.zig:15:24: error: no field named 'x' in struct 'main.S' +main.zig:1:11: note: struct declared here +#} + +#write main.zig 3/main.zig +#update { +remove reference to non-existent field#} +#check stdout { +0 +#} diff --git a/test/incremental/add_remove_toplevel_fields b/test/incremental/add_remove_toplevel_fields deleted file mode 100644 index e7ba9a2e892d343b08f90016a545252d04b04d5c..0000000000000000000000000000000000000000 --- a/test/incremental/add_remove_toplevel_fields +++ /dev/null @@ -1,96 +0,0 @@ -#update=initial version -#file=main.zig -const S = @This(); -x: u8, -pub fn main(init: std.process.Init) !void { - var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); - printFieldCount(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; - printOneField(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; -} -fn printFieldCount(w: *Writer) Writer.Error!void { - try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); -} -fn printOneField(w: *Writer) Writer.Error!void { - const val: S = .{ .x = 100 }; - try w.print("{d}\n", .{val.x}); -} -const std = @import("std"); -const Writer = std.Io.Writer; -#expect_stdout="1 100\n" - -#update=add a field -#file=main.zig -const S = @This(); -x: u8, -y: u16 = 200, -pub fn main(init: std.process.Init) !void { - var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); - printFieldCount(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; - printOneField(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; -} -fn printFieldCount(w: *Writer) Writer.Error!void { - try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); -} -fn printOneField(w: *Writer) Writer.Error!void { - const val: S = .{ .x = 100 }; - try w.print("{d}\n", .{val.x}); -} -const std = @import("std"); -const Writer = std.Io.Writer; -#expect_stdout="2 100\n" - -#update=remove all fields -#file=main.zig -const S = @This(); -pub fn main(init: std.process.Init) !void { - var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); - printFieldCount(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; - printOneField(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; -} -fn printFieldCount(w: *Writer) Writer.Error!void { - try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); -} -fn printOneField(w: *Writer) Writer.Error!void { - const val: S = .{ .x = 100 }; - try w.print("{d}\n", .{val.x}); -} -const std = @import("std"); -const Writer = std.Io.Writer; -#expect_error=main.zig:15:24: error: no field named 'x' in struct 'main' -#expect_error=main.zig:1:1: note: struct declared here - -#update=remove reference to non-existent field -#file=main.zig -const S = @This(); -pub fn main(init: std.process.Init) !void { - var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); - printFieldCount(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; - printOneField(&stdout_writer.interface) catch |err| switch (err) { - error.WriteFailed => return stdout_writer.err.?, - }; -} -fn printFieldCount(w: *Writer) Writer.Error!void { - try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); -} -fn printOneField(w: *Writer) Writer.Error!void { - //const val: S = .{ .x = 100 }; - //try w.print("{d}\n", .{val.x}); - try w.writeAll("\n"); -} -const std = @import("std"); -const Writer = std.Io.Writer; -#expect_stdout="0 \n" diff --git a/test/incremental/add_remove_toplevel_fields/0/main.zig b/test/incremental/add_remove_toplevel_fields/0/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..72823f713cab4244b581f51ca442a7ae57ece762 --- /dev/null +++ b/test/incremental/add_remove_toplevel_fields/0/main.zig @@ -0,0 +1,20 @@ +const S = @This(); +x: u8, +pub fn main(init: std.process.Init) !void { + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + printFieldCount(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; + printOneField(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; +} +fn printFieldCount(w: *Writer) Writer.Error!void { + try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); +} +fn printOneField(w: *Writer) Writer.Error!void { + const val: S = .{ .x = 100 }; + try w.print("{d}\n", .{val.x}); +} +const std = @import("std"); +const Writer = std.Io.Writer; diff --git a/test/incremental/add_remove_toplevel_fields/1/main.zig b/test/incremental/add_remove_toplevel_fields/1/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..7fecd0bb563d9962f8cbc4830f714259e34d393b --- /dev/null +++ b/test/incremental/add_remove_toplevel_fields/1/main.zig @@ -0,0 +1,21 @@ +const S = @This(); +x: u8, +y: u16 = 200, +pub fn main(init: std.process.Init) !void { + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + printFieldCount(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; + printOneField(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; +} +fn printFieldCount(w: *Writer) Writer.Error!void { + try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); +} +fn printOneField(w: *Writer) Writer.Error!void { + const val: S = .{ .x = 100 }; + try w.print("{d}\n", .{val.x}); +} +const std = @import("std"); +const Writer = std.Io.Writer; diff --git a/test/incremental/add_remove_toplevel_fields/2/main.zig b/test/incremental/add_remove_toplevel_fields/2/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..cdba934cc767e1ab7e9ed7e5ff9a4a43db164981 --- /dev/null +++ b/test/incremental/add_remove_toplevel_fields/2/main.zig @@ -0,0 +1,19 @@ +const S = @This(); +pub fn main(init: std.process.Init) !void { + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + printFieldCount(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; + printOneField(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; +} +fn printFieldCount(w: *Writer) Writer.Error!void { + try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); +} +fn printOneField(w: *Writer) Writer.Error!void { + const val: S = .{ .x = 100 }; + try w.print("{d}\n", .{val.x}); +} +const std = @import("std"); +const Writer = std.Io.Writer; diff --git a/test/incremental/add_remove_toplevel_fields/3/main.zig b/test/incremental/add_remove_toplevel_fields/3/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..495c87c2b1aeeefe9628072bb2e2f325f8c82325 --- /dev/null +++ b/test/incremental/add_remove_toplevel_fields/3/main.zig @@ -0,0 +1,20 @@ +const S = @This(); +pub fn main(init: std.process.Init) !void { + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + printFieldCount(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; + printOneField(&stdout_writer.interface) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; +} +fn printFieldCount(w: *Writer) Writer.Error!void { + try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len}); +} +fn printOneField(w: *Writer) Writer.Error!void { + //const val: S = .{ .x = 100 }; + //try w.print("{d}\n", .{val.x}); + try w.writeAll("\n"); +} +const std = @import("std"); +const Writer = std.Io.Writer; diff --git a/test/incremental/add_remove_toplevel_fields/manifest b/test/incremental/add_remove_toplevel_fields/manifest new file mode 100644 index 0000000000000000000000000000000000000000..569ee7527b51e75d6a214d260b4206b1c5dd2974 --- /dev/null +++ b/test/incremental/add_remove_toplevel_fields/manifest @@ -0,0 +1,31 @@ +#exe { +-Mroot=main.zig +#} + +#write main.zig 0/main.zig +#update +#check stdout { +1 100 +#} + +#write main.zig 1/main.zig +#update { +add a field#} +#check stdout { +2 100 +#} + +#write main.zig 2/main.zig +#update { +remove all fields#} +#check errors { +main.zig:15:24: error: no field named 'x' in struct 'main' +main.zig:1:1: note: struct declared here +#} + +#write main.zig 3/main.zig +#update { +remove reference to non-existent field#} +#check stdout { +0 +#} diff --git a/test/incremental/analysis_error_and_syntax_error b/test/incremental/analysis_error_and_syntax_error index 6c703db7545fd51153794b18ab696e25851bf8a5..5a2246ee8a8cbc2da6512e70830d8927a676d75b 100644 --- a/test/incremental/analysis_error_and_syntax_error +++ b/test/incremental/analysis_error_and_syntax_error @@ -1,38 +1,64 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub fn main() !void { @compileError("uh oh"); } -#expect_error=main.zig:2:5: error: uh oh +#} +#update +#check errors { +main.zig:2:5: error: uh oh +#} -#update=add parse error -#file=main.zig +#write main.zig { pub fn main() !void { @compileError("uh oh"); -#expect_error=main.zig:3:1: error: expected statement, found 'EOF' +#} +#update { +add parse error#} +#check errors { +main.zig:3:1: error: expected statement, found 'EOF' +#} -#update=fix parse error -#file=main.zig +#write main.zig { pub fn main() !void { @compileError("uh oh"); } -#expect_error=main.zig:2:5: error: uh oh +#} +#update { +fix parse error#} +#check errors { +main.zig:2:5: error: uh oh +#} -#update=add parse error again -#file=main.zig +#write main.zig { pub fn main() !void { @compileError("uh oh"); -#expect_error=main.zig:3:1: error: expected statement, found 'EOF' +#} +#update { +add parse error again#} +#check errors { +main.zig:3:1: error: expected statement, found 'EOF' +#} -#update=comment @compileError call -#file=main.zig +#write main.zig { pub fn main() !void { //@compileError("uh oh"); -#expect_error=main.zig:3:1: error: expected statement, found 'EOF' +#} +#update { +comment @compileError call#} +#check errors { +main.zig:3:1: error: expected statement, found 'EOF' +#} -#update=fix parse error again -#file=main.zig +#write main.zig { pub fn main() !void { //@compileError("uh oh"); } -#expect_stdout="" +#} +#update { +fix parse error again#} +#check stdout { +#} diff --git a/test/incremental/bad_import b/test/incremental/bad_import index fd91fa66050e2ae3cb1407382d5f173bdb2fe884..d93a9ed6309f963c310a82f0813d0905a564cc10 100644 --- a/test/incremental/bad_import +++ b/test/incremental/bad_import @@ -1,32 +1,48 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub fn main() !void { _ = @import("foo.zig"); try std.Io.File.stdout().writeStreamingAll(io, "success\n"); } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#file=foo.zig +#} +#write foo.zig { comptime { _ = @import("bad.zig"); } -#expect_error=bad.zig:1:1: error: unable to load "bad.zig": FileNotFound -#expect_error=foo.zig:2:17: note: file imported here +#} +#update +#check errors { +bad.zig:1:1: error: unable to load "bad.zig": FileNotFound +foo.zig:2:17: note: file imported here +#} -#update=change bad import -#file=foo.zig +#write foo.zig { comptime { _ = @import("this_is/not_real.zig"); } -#expect_error=this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound -#expect_error=foo.zig:2:17: note: file imported here +#} +#update { +change bad import#} +#check errors { +this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound +foo.zig:2:17: note: file imported here +#} -#update=remove import of 'foo.zig' -#file=main.zig +#write main.zig { pub fn main() !void { //_ = @import("foo.zig"); try std.Io.File.stdout().writeStreamingAll(io, "success\n"); } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="success\n" +#} +#update { +remove import of 'foo.zig'#} +#check stdout { +success +#} diff --git a/test/incremental/change_bitpack_backing_int b/test/incremental/change_bitpack_backing_int index 0af16aa43e092554bc22c09053b22b54e87a32e4..a5a2b81ce3c3df699043da2fdbd06e7718627ec8 100644 --- a/test/incremental/change_bitpack_backing_int +++ b/test/incremental/change_bitpack_backing_int @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const Foo = packed struct(u8) { a: u4, b: i4 }; const Bar = packed union(u10) { a: u10, b: i10 }; pub fn main() void {} @@ -11,13 +14,18 @@ comptime { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:5:5: error: found compile log statement -#expect_error=main.zig:8:5: note: also here -#expect_compile_log=@as(type, u8) -#expect_compile_log=@as(comptime_int, 10) +#} +#update +#check errors { +main.zig:5:5: error: found compile log statement +main.zig:8:5: note: also here -#update=make backing types signed -#file=main.zig +Compile Log Output: +@as(type, u8) +@as(comptime_int, 10) +#} + +#write main.zig { const Foo = packed struct(i8) { a: u4, b: i4 }; const Bar = packed union(i10) { a: u10, b: i10 }; pub fn main() void {} @@ -29,13 +37,19 @@ comptime { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:5:5: error: found compile log statement -#expect_error=main.zig:8:5: note: also here -#expect_compile_log=@as(type, i8) -#expect_compile_log=@as(comptime_int, 10) +#} +#update { +make backing types signed#} +#check errors { +main.zig:5:5: error: found compile log statement +main.zig:8:5: note: also here -#update=make backing types too small -#file=main.zig +Compile Log Output: +@as(type, i8) +@as(comptime_int, 10) +#} + +#write main.zig { const Foo = packed struct(i5) { a: u4, b: i4 }; const Bar = packed union(i8) { a: u10, b: i10 }; pub fn main() void {} @@ -47,16 +61,20 @@ comptime { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:1:20: error: backing integer bit width does not match total bit width of fields -#expect_error=main.zig:1:27: note: backing integer 'i5' has bit width '5' -#expect_error=main.zig:1:20: note: struct fields have total bit width '8' -#expect_error=main.zig:2:35: error: field bit width does not match backing integer -#expect_error=main.zig:2:35: note: field type 'u10' has bit width '10' -#expect_error=main.zig:2:26: note: backing integer 'i8' has bit width '8' -#expect_error=main.zig:2:35: note: all fields in a packed union must have the same bit width +#} +#update { +make backing types too small#} +#check errors { +main.zig:1:20: error: backing integer bit width does not match total bit width of fields +main.zig:1:27: note: backing integer 'i5' has bit width '5' +main.zig:1:20: note: struct fields have total bit width '8' +main.zig:2:35: error: field bit width does not match backing integer +main.zig:2:35: note: field type 'u10' has bit width '10' +main.zig:2:26: note: backing integer 'i8' has bit width '8' +main.zig:2:35: note: all fields in a packed union must have the same bit width +#} -#update=make backing types too big -#file=main.zig +#write main.zig { const Foo = packed struct(u10) { a: u4, b: i4 }; const Bar = packed union(u32) { a: u10, b: i10 }; pub fn main() void {} @@ -68,10 +86,15 @@ comptime { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:1:20: error: backing integer bit width does not match total bit width of fields -#expect_error=main.zig:1:27: note: backing integer 'u10' has bit width '10' -#expect_error=main.zig:1:20: note: struct fields have total bit width '8' -#expect_error=main.zig:2:36: error: field bit width does not match backing integer -#expect_error=main.zig:2:36: note: field type 'u10' has bit width '10' -#expect_error=main.zig:2:26: note: backing integer 'u32' has bit width '32' -#expect_error=main.zig:2:36: note: all fields in a packed union must have the same bit width +#} +#update { +make backing types too big#} +#check errors { +main.zig:1:20: error: backing integer bit width does not match total bit width of fields +main.zig:1:27: note: backing integer 'u10' has bit width '10' +main.zig:1:20: note: struct fields have total bit width '8' +main.zig:2:36: error: field bit width does not match backing integer +main.zig:2:36: note: field type 'u10' has bit width '10' +main.zig:2:26: note: backing integer 'u32' has bit width '32' +main.zig:2:36: note: all fields in a packed union must have the same bit width +#} diff --git a/test/incremental/change_container_kind b/test/incremental/change_container_kind index cf6b5a3689cdb51f037db505ad5fdd9ebebdb48b..b83abc6ed79414180e28bf393af94cb708bb377e 100644 --- a/test/incremental/change_container_kind +++ b/test/incremental/change_container_kind @@ -1,61 +1,114 @@ -#update=initial version, T is struct -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const T = @import("foo.zig").T; pub fn main() void { @compileLog(T); @compileLog(@tagName(@typeInfo(T))); } -#file=foo.zig +#} +#write foo.zig { pub const T = struct { x: u8 }; -#expect_error=main.zig:3:5: error: found compile log statement -#expect_compile_log=@as(type, foo.T) -#expect_compile_log=@as(*const [6:0]u8, "struct") +#} +#update { +T is struct#} +#check errors { +main.zig:3:5: error: found compile log statement -#update=T is union -#file=foo.zig +Compile Log Output: +@as(type, foo.T) +@as(*const [6:0]u8, "struct") +#} + +#write foo.zig { pub const T = union {}; -#expect_error=main.zig:3:5: error: found compile log statement -#expect_compile_log=@as(type, foo.T) -#expect_compile_log=@as(*const [5:0]u8, "union") +#} +#update { +T is union#} +#check errors { +main.zig:3:5: error: found compile log statement -#update=T is enum -#file=foo.zig +Compile Log Output: +@as(type, foo.T) +@as(*const [5:0]u8, "union") +#} + +#write foo.zig { pub const T = enum {}; -#expect_error=main.zig:3:5: error: found compile log statement -#expect_compile_log=@as(type, foo.T) -#expect_compile_log=@as(*const [4:0]u8, "enum") +#} +#update { +T is enum#} +#check errors { +main.zig:3:5: error: found compile log statement -#update=T is opaque -#file=foo.zig +Compile Log Output: +@as(type, foo.T) +@as(*const [4:0]u8, "enum") +#} + +#write foo.zig { pub const T = opaque {}; -#expect_error=main.zig:3:5: error: found compile log statement -#expect_compile_log=@as(type, foo.T) -#expect_compile_log=@as(*const [6:0]u8, "opaque") +#} +#update { +T is opaque#} +#check errors { +main.zig:3:5: error: found compile log statement -#update=T is packed struct -#file=foo.zig +Compile Log Output: +@as(type, foo.T) +@as(*const [6:0]u8, "opaque") +#} + +#write foo.zig { pub const T = packed struct {}; -#expect_error=main.zig:3:5: error: found compile log statement -#expect_compile_log=@as(type, foo.T) -#expect_compile_log=@as(*const [6:0]u8, "struct") +#} +#update { +T is packed struct#} +#check errors { +main.zig:3:5: error: found compile log statement -#update=T is packed union -#file=foo.zig +Compile Log Output: +@as(type, foo.T) +@as(*const [6:0]u8, "struct") +#} + +#write foo.zig { pub const T = packed union { x: void }; // packed unions need at least 1 field -#expect_error=main.zig:3:5: error: found compile log statement -#expect_compile_log=@as(type, foo.T) -#expect_compile_log=@as(*const [5:0]u8, "union") +#} +#update { +T is packed union#} +#check errors { +main.zig:3:5: error: found compile log statement -#update=T is extern struct -#file=foo.zig +Compile Log Output: +@as(type, foo.T) +@as(*const [5:0]u8, "union") +#} + +#write foo.zig { pub const T = extern struct {}; -#expect_error=main.zig:3:5: error: found compile log statement -#expect_compile_log=@as(type, foo.T) -#expect_compile_log=@as(*const [6:0]u8, "struct") +#} +#update { +T is extern struct#} +#check errors { +main.zig:3:5: error: found compile log statement -#update=T is extern union -#file=foo.zig +Compile Log Output: +@as(type, foo.T) +@as(*const [6:0]u8, "struct") +#} + +#write foo.zig { pub const T = extern union { x: void }; // extern unions need at least 1 field -#expect_error=main.zig:3:5: error: found compile log statement -#expect_compile_log=@as(type, foo.T) -#expect_compile_log=@as(*const [5:0]u8, "union") +#} +#update { +T is extern union#} +#check errors { +main.zig:3:5: error: found compile log statement + +Compile Log Output: +@as(type, foo.T) +@as(*const [5:0]u8, "union") +#} diff --git a/test/incremental/change_embed_file b/test/incremental/change_embed_file index 8b515d2d980c9ee68da186c8fa149b5b19c2ed20..d50101dc476973ab1974d4ae82fca3cebffed359 100644 --- a/test/incremental/change_embed_file +++ b/test/incremental/change_embed_file @@ -1,45 +1,72 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); const string = @embedFile("string.txt"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, string); } const io = std.Io.Threaded.global_single_threaded.io(); -#file=string.txt +#} +#write string.txt { Hello, World! -#expect_stdout="Hello, World!\n" +#} +#update +#check stdout { +Hello, World! +#} -#update=change file contents -#file=string.txt +#write string.txt { +Hello again, World! +#} +#update { +change file contents#} +#check stdout { Hello again, World! -#expect_stdout="Hello again, World!\n" +#} -#update=delete file -#rm_file=string.txt -#expect_error=main.zig:2:27: error: failed opening "string.txt": FileNotFound +#delete string.txt +#update { +delete file#} +#check errors { +main.zig:2:27: error: failed opening "string.txt": FileNotFound +#} -#update=remove reference to file -#file=main.zig +#write main.zig { const std = @import("std"); const string = @embedFile("string.txt"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n"); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="a hardcoded string\n" +#} +#update { +remove reference to file#} +#check stdout { +a hardcoded string +#} -#update=re-introduce reference to file -#file=main.zig +#write main.zig { const std = @import("std"); const string = @embedFile("string.txt"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, string); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:2:27: error: failed opening "string.txt": FileNotFound +#} +#update { +re-introduce reference to file#} +#check errors { +main.zig:2:27: error: failed opening "string.txt": FileNotFound +#} -#update=recreate file -#file=string.txt +#write string.txt { We're back, World! -#expect_stdout="We're back, World!\n" +#} +#update { +recreate file#} +#check stdout { +We're back, World! +#} diff --git a/test/incremental/change_enum_tag_type b/test/incremental/change_enum_tag_type deleted file mode 100644 index 6ff8a1424d0c695145e7e136b9989c7413fda5a2..0000000000000000000000000000000000000000 --- a/test/incremental/change_enum_tag_type +++ /dev/null @@ -1,93 +0,0 @@ -#update=initial version -#file=main.zig -const Tag = u2; -const Foo = enum(Tag) { - a, - b, - c, - d, -}; -pub fn main() !void { - var val: Foo = undefined; - val = .a; - var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - try stdout_writer.interface.print("{s}\n", .{@tagName(val)}); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="a\n" -#update=too many enum fields -#file=main.zig -const Tag = u2; -const Foo = enum(Tag) { - a, - b, - c, - d, - e, -}; -pub fn main() !void { - var val: Foo = undefined; - val = .a; - var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - try stdout_writer.interface.print("{s}\n", .{@tagName(val)}); -} -comptime { - // These can't be true at the same time; analysis should stop as soon as it sees `Foo` - std.debug.assert(@intFromEnum(Foo.e) == 4); - std.debug.assert(@TypeOf(@intFromEnum(Foo.e)) == Tag); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:7:5: error: enum tag value '4' too large for type 'u2' -#update=increase tag size -#file=main.zig -const Tag = u3; -const Foo = enum(Tag) { - a, - b, - c, - d, - e, -}; -pub fn main() !void { - var val: Foo = undefined; - val = .a; - var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - try stdout_writer.interface.print("{s}\n", .{@tagName(val)}); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="a\n" -#update=specify tag directly -#file=main.zig -const Foo = enum(u3) { - a, - b, - c, - d, - e, -}; -pub fn main() !void { - @compileLog(@typeInfo(Foo).@"enum".tag_type); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:9:5: error: found compile log statement -#expect_compile_log=@as(type, u3) -#update=change directly-specified tag type -#file=main.zig -const Foo = enum(u8) { - a, - b, - c, - d, - e, -}; -pub fn main() !void { - @compileLog(@typeInfo(Foo).@"enum".tag_type); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:9:5: error: found compile log statement -#expect_compile_log=@as(type, u8) diff --git a/test/incremental/change_enum_tag_type/0/main.zig b/test/incremental/change_enum_tag_type/0/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..391e354224b13f84fd0e172d9a2c5a07074cdcd8 --- /dev/null +++ b/test/incremental/change_enum_tag_type/0/main.zig @@ -0,0 +1,15 @@ +const Tag = u2; +const Foo = enum(Tag) { + a, + b, + c, + d, +}; +pub fn main() !void { + var val: Foo = undefined; + val = .a; + var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); + try stdout_writer.interface.print("{s}\n", .{@tagName(val)}); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); diff --git a/test/incremental/change_enum_tag_type/1/main.zig b/test/incremental/change_enum_tag_type/1/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..ea4ff6f7a9097e4f4982ae4598a40b0e1f023e80 --- /dev/null +++ b/test/incremental/change_enum_tag_type/1/main.zig @@ -0,0 +1,21 @@ +const Tag = u2; +const Foo = enum(Tag) { + a, + b, + c, + d, + e, +}; +pub fn main() !void { + var val: Foo = undefined; + val = .a; + var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); + try stdout_writer.interface.print("{s}\n", .{@tagName(val)}); +} +comptime { + // These can't be true at the same time; analysis should stop as soon as it sees `Foo` + std.debug.assert(@backingInt(Foo.e) == 4); + std.debug.assert(@TypeOf(@backingInt(Foo.e)) == Tag); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); diff --git a/test/incremental/change_enum_tag_type/2/main.zig b/test/incremental/change_enum_tag_type/2/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..2a1eee0ba91d59ed1d5df6adfc5ae2de2d29a5d6 --- /dev/null +++ b/test/incremental/change_enum_tag_type/2/main.zig @@ -0,0 +1,16 @@ +const Tag = u3; +const Foo = enum(Tag) { + a, + b, + c, + d, + e, +}; +pub fn main() !void { + var val: Foo = undefined; + val = .a; + var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); + try stdout_writer.interface.print("{s}\n", .{@tagName(val)}); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); diff --git a/test/incremental/change_enum_tag_type/3/main.zig b/test/incremental/change_enum_tag_type/3/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..c4e213660e09f90523a3c8914d0f09dd5266cdf4 --- /dev/null +++ b/test/incremental/change_enum_tag_type/3/main.zig @@ -0,0 +1,12 @@ +const Foo = enum(u3) { + a, + b, + c, + d, + e, +}; +pub fn main() !void { + @compileLog(@typeInfo(Foo).@"enum".tag_type); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); diff --git a/test/incremental/change_enum_tag_type/4/main.zig b/test/incremental/change_enum_tag_type/4/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..729f2501dd4e1ff7260c7234a1b204052fe5f92c --- /dev/null +++ b/test/incremental/change_enum_tag_type/4/main.zig @@ -0,0 +1,12 @@ +const Foo = enum(u8) { + a, + b, + c, + d, + e, +}; +pub fn main() !void { + @compileLog(@typeInfo(Foo).@"enum".tag_type); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); diff --git a/test/incremental/change_enum_tag_type/manifest b/test/incremental/change_enum_tag_type/manifest new file mode 100644 index 0000000000000000000000000000000000000000..682c83a67ed4a3d9ced7ba413b3c8e2ddfab4559 --- /dev/null +++ b/test/incremental/change_enum_tag_type/manifest @@ -0,0 +1,43 @@ +#exe { +-Mroot=main.zig +#} + +#write main.zig 0/main.zig +#update +#check stdout { +a +#} + +#write main.zig 1/main.zig +#update { +too many enum fields#} +#check errors { +main.zig:7:5: error: enum tag value '4' too large for type 'u2' +#} + +#write main.zig 2/main.zig +#update { +increase tag size#} +#check stdout { +a +#} + +#write main.zig 3/main.zig +#update { +specify tag directly#} +#check errors { +main.zig:9:5: error: found compile log statement + +Compile Log Output: +@as(type, u3) +#} + +#write main.zig 4/main.zig +#update { +change directly-specified tag type#} +#check errors { +main.zig:9:5: error: found compile log statement + +Compile Log Output: +@as(type, u8) +#} diff --git a/test/incremental/change_exports b/test/incremental/change_exports deleted file mode 100644 index 64aec0288cbbf82420b8eaf5345245bea34d72b0..0000000000000000000000000000000000000000 --- a/test/incremental/change_exports +++ /dev/null @@ -1,169 +0,0 @@ -#update=initial version -#file=main.zig -export fn foo() void {} -const bar: u32 = 123; -const other: u32 = 456; -comptime { - @export(&bar, .{ .name = "bar" }); -} -pub fn main() !void { - const S = struct { - extern fn foo() void; - extern const bar: u32; - }; - S.foo(); - var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - try stdout_writer.interface.print("{}\n", .{S.bar}); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="123\n" - -#update=add conflict -#file=main.zig -export fn foo() void {} -const bar: u32 = 123; -const other: u32 = 456; -comptime { - @export(&bar, .{ .name = "bar" }); - @export(&other, .{ .name = "foo" }); -} -pub fn main() !void { - const S = struct { - extern fn foo() void; - extern const bar: u32; - extern const other: u32; - }; - S.foo(); - var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other }); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:6:5: error: exported symbol collision: foo -#expect_error=main.zig:1:1: note: other symbol here - -#update=resolve conflict -#file=main.zig -export fn foo() void {} -const bar: u32 = 123; -const other: u32 = 456; -comptime { - @export(&bar, .{ .name = "bar" }); - @export(&other, .{ .name = "other" }); -} -pub fn main() !void { - const S = struct { - extern fn foo() void; - extern const bar: u32; - extern const other: u32; - }; - S.foo(); - var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other }); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="123 456\n" - -#update=put exports in decl -#file=main.zig -export fn foo() void {} -const bar: u32 = 123; -const other: u32 = 456; -const does_exports = { - @export(&bar, .{ .name = "bar" }); - @export(&other, .{ .name = "other" }); -}; -comptime { - _ = does_exports; -} -pub fn main() !void { - const S = struct { - extern fn foo() void; - extern const bar: u32; - extern const other: u32; - }; - S.foo(); - var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other }); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="123 456\n" - -#update=remove reference to exporting decl -#file=main.zig -export fn foo() void {} -const bar: u32 = 123; -const other: u32 = 456; -const does_exports = { - @export(&bar, .{ .name = "bar" }); - @export(&other, .{ .name = "other" }); -}; -comptime { - //_ = does_exports; -} -pub fn main() !void { - const S = struct { - extern fn foo() void; - }; - S.foo(); -} -const std = @import("std"); -#expect_stdout="" - -#update=mark consts as export -#file=main.zig -export fn foo() void {} -export const bar: u32 = 123; -export const other: u32 = 456; -const does_exports = { - @export(&bar, .{ .name = "bar" }); - @export(&other, .{ .name = "other" }); -}; -comptime { - //_ = does_exports; -} -pub fn main() !void { - const S = struct { - extern fn foo() void; - extern const bar: u32; - extern const other: u32; - }; - S.foo(); - var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other }); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="123 456\n" - -#update=reintroduce reference to exporting decl, introducing conflict -#file=main.zig -export fn foo() void {} -export const bar: u32 = 123; -export const other: u32 = 456; -const does_exports = { - @export(&bar, .{ .name = "bar" }); - @export(&other, .{ .name = "other" }); -}; -comptime { - _ = does_exports; -} -pub fn main() !void { - const S = struct { - extern fn foo() void; - extern const bar: u32; - extern const other: u32; - }; - S.foo(); - var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other }); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:5:5: error: exported symbol collision: bar -#expect_error=main.zig:2:1: note: other symbol here -#expect_error=main.zig:6:5: error: exported symbol collision: other -#expect_error=main.zig:3:1: note: other symbol here diff --git a/test/incremental/change_exports/0/main.zig b/test/incremental/change_exports/0/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..79f3265c558830ea94304c71feb5eeb39b96de33 --- /dev/null +++ b/test/incremental/change_exports/0/main.zig @@ -0,0 +1,17 @@ +export fn foo() void {} +const bar: u32 = 123; +const other: u32 = 456; +comptime { + @export(&bar, .{ .name = "bar" }); +} +pub fn main() !void { + const S = struct { + extern fn foo() void; + extern const bar: u32; + }; + S.foo(); + var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); + try stdout_writer.interface.print("{}\n", .{S.bar}); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); diff --git a/test/incremental/change_exports/1/main.zig b/test/incremental/change_exports/1/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..af1dd07028368824ec0bc5a81d0c7b43e99ad521 --- /dev/null +++ b/test/incremental/change_exports/1/main.zig @@ -0,0 +1,19 @@ +export fn foo() void {} +const bar: u32 = 123; +const other: u32 = 456; +comptime { + @export(&bar, .{ .name = "bar" }); + @export(&other, .{ .name = "foo" }); +} +pub fn main() !void { + const S = struct { + extern fn foo() void; + extern const bar: u32; + extern const other: u32; + }; + S.foo(); + var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); + try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other }); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); diff --git a/test/incremental/change_exports/2/main.zig b/test/incremental/change_exports/2/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..e2737aea7e73d589b7525d06085a79f0b8a11f0f --- /dev/null +++ b/test/incremental/change_exports/2/main.zig @@ -0,0 +1,19 @@ +export fn foo() void {} +const bar: u32 = 123; +const other: u32 = 456; +comptime { + @export(&bar, .{ .name = "bar" }); + @export(&other, .{ .name = "other" }); +} +pub fn main() !void { + const S = struct { + extern fn foo() void; + extern const bar: u32; + extern const other: u32; + }; + S.foo(); + var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); + try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other }); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); diff --git a/test/incremental/change_exports/3/main.zig b/test/incremental/change_exports/3/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..20662c64435cc85c232ec1a18ffec0982b31fc58 --- /dev/null +++ b/test/incremental/change_exports/3/main.zig @@ -0,0 +1,22 @@ +export fn foo() void {} +const bar: u32 = 123; +const other: u32 = 456; +const does_exports = { + @export(&bar, .{ .name = "bar" }); + @export(&other, .{ .name = "other" }); +}; +comptime { + _ = does_exports; +} +pub fn main() !void { + const S = struct { + extern fn foo() void; + extern const bar: u32; + extern const other: u32; + }; + S.foo(); + var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); + try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other }); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); diff --git a/test/incremental/change_exports/4/main.zig b/test/incremental/change_exports/4/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..f53a371119987978b64e3cac638dc3630b179a0a --- /dev/null +++ b/test/incremental/change_exports/4/main.zig @@ -0,0 +1,17 @@ +export fn foo() void {} +const bar: u32 = 123; +const other: u32 = 456; +const does_exports = { + @export(&bar, .{ .name = "bar" }); + @export(&other, .{ .name = "other" }); +}; +comptime { + //_ = does_exports; +} +pub fn main() !void { + const S = struct { + extern fn foo() void; + }; + S.foo(); +} +const std = @import("std"); diff --git a/test/incremental/change_exports/5/main.zig b/test/incremental/change_exports/5/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..ad9ccddf989a962083c351a2badc6fd7a5777b92 --- /dev/null +++ b/test/incremental/change_exports/5/main.zig @@ -0,0 +1,22 @@ +export fn foo() void {} +export const bar: u32 = 123; +export const other: u32 = 456; +const does_exports = { + @export(&bar, .{ .name = "bar" }); + @export(&other, .{ .name = "other" }); +}; +comptime { + //_ = does_exports; +} +pub fn main() !void { + const S = struct { + extern fn foo() void; + extern const bar: u32; + extern const other: u32; + }; + S.foo(); + var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); + try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other }); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); diff --git a/test/incremental/change_exports/6/main.zig b/test/incremental/change_exports/6/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..2019185e6046252901faf087291720f93895d514 --- /dev/null +++ b/test/incremental/change_exports/6/main.zig @@ -0,0 +1,22 @@ +export fn foo() void {} +export const bar: u32 = 123; +export const other: u32 = 456; +const does_exports = { + @export(&bar, .{ .name = "bar" }); + @export(&other, .{ .name = "other" }); +}; +comptime { + _ = does_exports; +} +pub fn main() !void { + const S = struct { + extern fn foo() void; + extern const bar: u32; + extern const other: u32; + }; + S.foo(); + var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); + try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other }); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); diff --git a/test/incremental/change_exports/manifest b/test/incremental/change_exports/manifest new file mode 100644 index 0000000000000000000000000000000000000000..41716cd32cadf13dca51971fbab9703bc1530ade --- /dev/null +++ b/test/incremental/change_exports/manifest @@ -0,0 +1,54 @@ +#exe { +-Mroot=main.zig +#} + +#write main.zig 0/main.zig +#update +#check stdout { +123 +#} + +#write main.zig 1/main.zig +#update { +add conflict#} +#check errors { +main.zig:6:5: error: exported symbol collision: foo +main.zig:1:1: note: other symbol here +#} + +#write main.zig 2/main.zig +#update { +resolve conflict#} +#check stdout { +123 456 +#} + +#write main.zig 3/main.zig +#update { +put exports in decl#} +#check stdout { +123 456 +#} + +#write main.zig 4/main.zig +#update { +remove reference to exporting decl#} +#check stdout { +#} + +#write main.zig 5/main.zig +#update { +mark consts as export#} +#check stdout { +123 456 +#} + +#write main.zig 6/main.zig +#update { +reintroduce reference to exporting decl, introducing conflict#} +#check errors { +main.zig:5:5: error: exported symbol collision: bar +main.zig:2:1: note: other symbol here +main.zig:6:5: error: exported symbol collision: other +main.zig:3:1: note: other symbol here +#} diff --git a/test/incremental/change_fn_type b/test/incremental/change_fn_type index ca0667d8041e05c363a9c975b865c6e1a7640904..b16811fbc937aa183fd80bfe7b0eb59690e089b7 100644 --- a/test/incremental/change_fn_type +++ b/test/incremental/change_fn_type @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub fn main() !void { try foo(123); } @@ -9,10 +12,13 @@ fn foo(x: u8) !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="123\n" +#} +#update +#check stdout { +123 +#} -#update=change function type -#file=main.zig +#write main.zig { pub fn main() !void { try foo(123); } @@ -22,10 +28,14 @@ fn foo(x: i64) !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="123\n" +#} +#update { +change function type#} +#check stdout { +123 +#} -#update=change function argument -#file=main.zig +#write main.zig { pub fn main() !void { try foo(-42); } @@ -35,4 +45,9 @@ fn foo(x: i64) !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="-42\n" +#} +#update { +change function argument#} +#check stdout { +-42 +#} diff --git a/test/incremental/change_generic_line_number b/test/incremental/change_generic_line_number index 23b3f2c0190a47c9c5e8a124af324b308fc100a3..cda09859f9c849649b5b40c66d9d16e94101cf34 100644 --- a/test/incremental/change_generic_line_number +++ b/test/incremental/change_generic_line_number @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); fn Printer(message: []const u8) type { @@ -13,9 +16,14 @@ pub fn main() !void { try Printer("foo\n").print(); try Printer("bar\n").print(); } -#expect_stdout="foo\nbar\n" -#update=change line number -#file=main.zig +#} +#update +#check stdout { +foo +bar +#} + +#write main.zig { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); @@ -30,4 +38,10 @@ pub fn main() !void { try Printer("foo\n").print(); try Printer("bar\n").print(); } -#expect_stdout="foo\nbar\n" +#} +#update { +change line number#} +#check stdout { +foo +bar +#} diff --git a/test/incremental/change_line_number b/test/incremental/change_line_number index 90a1edb95c924143792363c8b14c6414f0fbac13..ed8e24b009356b452dd71d17d7ca510e0df285d2 100644 --- a/test/incremental/change_line_number +++ b/test/incremental/change_line_number @@ -1,17 +1,29 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, "foo\n"); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="foo\n" -#update=change line number -#file=main.zig +#} +#update +#check stdout { +foo +#} + +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, "foo\n"); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="foo\n" +#} +#update { +change line number#} +#check stdout { +foo +#} diff --git a/test/incremental/change_module b/test/incremental/change_module index 73129f9eec6db02e446ff663c5600ffac2345994..4c24df6e4dd2c3f410d2d0a555e5a05a2d94d592 100644 --- a/test/incremental/change_module +++ b/test/incremental/change_module @@ -1,61 +1,87 @@ -#module=foo=foo.zig +#exe { +--dep foo -Mroot=main.zig +-Mfoo=foo.zig +#} -#update=initial version -#file=main.zig +#write main.zig { pub fn main() void { _ = @import("foo"); //_ = @import("other.zig"); } -#file=foo.zig +#} +#write foo.zig { comptime { _ = @import("other.zig"); } -#file=other.zig +#} +#write other.zig { fn f() void { @compileLog(@src().module); } comptime { f(); } -#expect_error=other.zig:2:5: error: found compile log statement -#expect_compile_log=@as([:0]const u8, "foo"[0..3]) +#} +#update +#check errors { +other.zig:2:5: error: found compile log statement -#update=change module of other.zig -#file=main.zig +Compile Log Output: +@as([:0]const u8, "foo"[0..3]) +#} + +#write main.zig { pub fn main() void { _ = @import("foo"); _ = @import("other.zig"); } -#file=foo.zig +#} +#write foo.zig { comptime { //_ = @import("other.zig"); } -#expect_error=other.zig:2:5: error: found compile log statement -#expect_compile_log=@as([:0]const u8, "root"[0..4]) +#} +#update { +change module of other.zig#} +#check errors { +other.zig:2:5: error: found compile log statement + +Compile Log Output: +@as([:0]const u8, "root"[0..4]) +#} -#update=put other.zig in both modules -#file=main.zig +#write main.zig { pub fn main() void { _ = @import("foo"); _ = @import("other.zig"); } -#file=foo.zig +#} +#write foo.zig { comptime { _ = @import("other.zig"); } -#expect_error=other.zig:1:1: error: file exists in modules 'root' and 'foo' -#expect_error=other.zig:1:1: note: files must belong to only one module -#expect_error=main.zig:3:17: note: file is imported here by the root of module 'root' -#expect_error=foo.zig:2:17: note: file is imported here by the root of module 'foo' +#} +#update { +put other.zig in both modules#} +#check errors { +other.zig:1:1: error: file exists in modules 'root' and 'foo' +other.zig:1:1: note: files must belong to only one module +main.zig:3:17: note: file is imported here by the root of module 'root' +foo.zig:2:17: note: file is imported here by the root of module 'foo' +#} -#update=put other.zig in no modules -#file=main.zig +#write main.zig { pub fn main() void { _ = @import("foo"); //_ = @import("other.zig"); } -#file=foo.zig +#} +#write foo.zig { comptime { //_ = @import("other.zig"); } -#expect_stdout="" +#} +#update { +put other.zig in no modules#} +#check stdout { +#} diff --git a/test/incremental/change_panic_handler b/test/incremental/change_panic_handler index b250c9867985a683a209279835f366703f2f5161..3407de9bade926e20542b9342c91e2d223a019da 100644 --- a/test/incremental/change_panic_handler +++ b/test/incremental/change_panic_handler @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub fn main() !u8 { var a: u8 = undefined; a = 255; @@ -14,10 +17,13 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="panic message: integer overflow\n" +#} +#update +#check stdout { +panic message: integer overflow +#} -#update=change the panic handler body -#file=main.zig +#write main.zig { pub fn main() !u8 { var a: u8 = undefined; a = 255; @@ -32,10 +38,14 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="new panic message: integer overflow\n" +#} +#update { +change the panic handler body#} +#check stdout { +new panic message: integer overflow +#} -#update=change the panic handler function value -#file=main.zig +#write main.zig { pub fn main() !u8 { var a: u8 = undefined; a = 255; @@ -50,4 +60,9 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="third panic message: integer overflow\n" +#} +#update { +change the panic handler function value#} +#check stdout { +third panic message: integer overflow +#} diff --git a/test/incremental/change_panic_handler_explicit b/test/incremental/change_panic_handler_explicit deleted file mode 100644 index 3735cfd86c0116ce130481c56f60d6816174d00f..0000000000000000000000000000000000000000 --- a/test/incremental/change_panic_handler_explicit +++ /dev/null @@ -1,149 +0,0 @@ -#update=initial version -#file=main.zig -pub fn main() !u8 { - var a: u8 = undefined; - a = 255; - _ = a + 1; - return 1; -} -const no_panic = std.debug.no_panic; -pub const panic = struct { - pub const call = myPanic; - pub fn integerOverflow() noreturn { - @panic("integer overflow"); - } - pub const sentinelMismatch = no_panic.sentinelMismatch; - pub const unwrapError = no_panic.unwrapError; - pub const outOfBounds = no_panic.outOfBounds; - pub const startGreaterThanEnd = no_panic.startGreaterThanEnd; - pub const inactiveUnionField = no_panic.inactiveUnionField; - pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder; - pub const reachedUnreachable = no_panic.reachedUnreachable; - pub const unwrapNull = no_panic.unwrapNull; - pub const castToNull = no_panic.castToNull; - pub const incorrectAlignment = no_panic.incorrectAlignment; - pub const invalidErrorCode = no_panic.invalidErrorCode; - pub const unexpectedErrorCode = no_panic.unexpectedErrorCode; - pub const integerOutOfBounds = no_panic.integerOutOfBounds; - pub const shlOverflow = no_panic.shlOverflow; - pub const shrOverflow = no_panic.shrOverflow; - pub const divideByZero = no_panic.divideByZero; - pub const exactDivisionRemainder = no_panic.exactDivisionRemainder; - pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds; - pub const corruptSwitch = no_panic.corruptSwitch; - pub const shiftRhsTooBig = no_panic.shiftRhsTooBig; - pub const invalidEnumValue = no_panic.invalidEnumValue; - pub const forLenMismatch = no_panic.forLenMismatch; - pub const copyLenMismatch = no_panic.copyLenMismatch; - pub const memcpyAlias = no_panic.memcpyAlias; - pub const noreturnReturned = no_panic.noreturnReturned; - pub const loadUninstantiableType = no_panic.loadUninstantiableType; -}; -fn myPanic(msg: []const u8, _: ?usize) noreturn { - var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - stdout_writer.interface.print("panic message: {s}\n", .{msg}) catch {}; - std.process.exit(0); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="panic message: integer overflow\n" - -#update=change the panic handler body -#file=main.zig -pub fn main() !u8 { - var a: u8 = undefined; - a = 255; - _ = a + 1; - return 1; -} -const no_panic = std.debug.no_panic; -pub const panic = struct { - pub const call = myPanic; - pub fn integerOverflow() noreturn { - @panic("integer overflow"); - } - pub const sentinelMismatch = no_panic.sentinelMismatch; - pub const unwrapError = no_panic.unwrapError; - pub const outOfBounds = no_panic.outOfBounds; - pub const startGreaterThanEnd = no_panic.startGreaterThanEnd; - pub const inactiveUnionField = no_panic.inactiveUnionField; - pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder; - pub const reachedUnreachable = no_panic.reachedUnreachable; - pub const unwrapNull = no_panic.unwrapNull; - pub const castToNull = no_panic.castToNull; - pub const incorrectAlignment = no_panic.incorrectAlignment; - pub const invalidErrorCode = no_panic.invalidErrorCode; - pub const unexpectedErrorCode = no_panic.unexpectedErrorCode; - pub const integerOutOfBounds = no_panic.integerOutOfBounds; - pub const shlOverflow = no_panic.shlOverflow; - pub const shrOverflow = no_panic.shrOverflow; - pub const divideByZero = no_panic.divideByZero; - pub const exactDivisionRemainder = no_panic.exactDivisionRemainder; - pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds; - pub const corruptSwitch = no_panic.corruptSwitch; - pub const shiftRhsTooBig = no_panic.shiftRhsTooBig; - pub const invalidEnumValue = no_panic.invalidEnumValue; - pub const forLenMismatch = no_panic.forLenMismatch; - pub const copyLenMismatch = no_panic.copyLenMismatch; - pub const memcpyAlias = no_panic.memcpyAlias; - pub const noreturnReturned = no_panic.noreturnReturned; - pub const loadUninstantiableType = no_panic.loadUninstantiableType; -}; -fn myPanic(msg: []const u8, _: ?usize) noreturn { - var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - stdout_writer.interface.print("new panic message: {s}\n", .{msg}) catch {}; - std.process.exit(0); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="new panic message: integer overflow\n" - -#update=change the panic handler function value -#file=main.zig -pub fn main() !u8 { - var a: u8 = undefined; - a = 255; - _ = a + 1; - return 1; -} -const no_panic = std.debug.no_panic; -pub const panic = struct { - pub const call = myPanicNew; - pub fn integerOverflow() noreturn { - @panic("integer overflow"); - } - pub const sentinelMismatch = std.debug.no_panic.sentinelMismatch; - pub const unwrapError = std.debug.no_panic.unwrapError; - pub const outOfBounds = std.debug.no_panic.outOfBounds; - pub const startGreaterThanEnd = std.debug.no_panic.startGreaterThanEnd; - pub const inactiveUnionField = std.debug.no_panic.inactiveUnionField; - pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder; - pub const reachedUnreachable = no_panic.reachedUnreachable; - pub const unwrapNull = no_panic.unwrapNull; - pub const castToNull = no_panic.castToNull; - pub const incorrectAlignment = no_panic.incorrectAlignment; - pub const invalidErrorCode = no_panic.invalidErrorCode; - pub const unexpectedErrorCode = no_panic.unexpectedErrorCode; - pub const integerOutOfBounds = no_panic.integerOutOfBounds; - pub const shlOverflow = no_panic.shlOverflow; - pub const shrOverflow = no_panic.shrOverflow; - pub const divideByZero = no_panic.divideByZero; - pub const exactDivisionRemainder = no_panic.exactDivisionRemainder; - pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds; - pub const corruptSwitch = no_panic.corruptSwitch; - pub const shiftRhsTooBig = no_panic.shiftRhsTooBig; - pub const invalidEnumValue = no_panic.invalidEnumValue; - pub const forLenMismatch = no_panic.forLenMismatch; - pub const copyLenMismatch = no_panic.copyLenMismatch; - pub const memcpyAlias = no_panic.memcpyAlias; - pub const noreturnReturned = no_panic.noreturnReturned; - pub const loadUninstantiableType = no_panic.loadUninstantiableType; -}; -fn myPanicNew(msg: []const u8, _: ?usize) noreturn { - var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - stdout_writer.interface.print("third panic message: {s}\n", .{msg}) catch {}; - std.process.exit(0); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="third panic message: integer overflow\n" diff --git a/test/incremental2/change_panic_handler_explicit/0/main.zig b/test/incremental/change_panic_handler_explicit/0/main.zig similarity index 100% rename from test/incremental2/change_panic_handler_explicit/0/main.zig rename to test/incremental/change_panic_handler_explicit/0/main.zig diff --git a/test/incremental2/change_panic_handler_explicit/1/main.zig b/test/incremental/change_panic_handler_explicit/1/main.zig similarity index 100% rename from test/incremental2/change_panic_handler_explicit/1/main.zig rename to test/incremental/change_panic_handler_explicit/1/main.zig diff --git a/test/incremental2/change_panic_handler_explicit/2/main.zig b/test/incremental/change_panic_handler_explicit/2/main.zig similarity index 100% rename from test/incremental2/change_panic_handler_explicit/2/main.zig rename to test/incremental/change_panic_handler_explicit/2/main.zig diff --git a/test/incremental2/change_panic_handler_explicit/manifest b/test/incremental/change_panic_handler_explicit/manifest similarity index 100% rename from test/incremental2/change_panic_handler_explicit/manifest rename to test/incremental/change_panic_handler_explicit/manifest diff --git a/test/incremental/change_reify_struct_field_type b/test/incremental/change_reify_struct_field_type index bc157bd68364af5eda2d806a2d83b24479bdb843..92a41faee42808ef4b2338a1bdac241507e659fe 100644 --- a/test/incremental/change_reify_struct_field_type +++ b/test/incremental/change_reify_struct_field_type @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{struct { tag: Enum }}, &.{.{}})) Enum { return s.field.tag; } @@ -8,9 +11,12 @@ pub fn main(init: std.process.Init) !void { } const Enum = enum { foo, bar }; const std = @import("std"); -#expect_stdout="foo" -#update=change field type -#file=main.zig +#} +#update +#check stdout { +foo#} + +#write main.zig { fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{Enum}, &.{.{}})) Enum { return s.field; } @@ -19,4 +25,8 @@ pub fn main(init: std.process.Init) !void { } const Enum = enum { foo, bar }; const std = @import("std"); -#expect_stdout="bar" +#} +#update { +change field type#} +#check stdout { +bar#} diff --git a/test/incremental/change_shift_op b/test/incremental/change_shift_op index d1fa6e747e125af9506bdff9766bbb5fa0dcd368..bcd0ff1d2f61b4aeb305a350bc64a8b64b76fbed 100644 --- a/test/incremental/change_shift_op +++ b/test/incremental/change_shift_op @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub fn main() !void { try foo(0x1300); } @@ -9,9 +12,13 @@ fn foo(x: u16) !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="0x3000\n" -#update=change to right shift -#file=main.zig +#} +#update +#check stdout { +0x3000 +#} + +#write main.zig { pub fn main() !void { try foo(0x1300); } @@ -21,4 +28,9 @@ fn foo(x: u16) !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="0x130\n" +#} +#update { +change to right shift#} +#check stdout { +0x130 +#} diff --git a/test/incremental/change_struct_same_fields b/test/incremental/change_struct_same_fields index b94f03778b21467cf255a13c48c95cce59f99329..348a443dd555223482c96f6ae0ccd7ed5a48c459 100644 --- a/test/incremental/change_struct_same_fields +++ b/test/incremental/change_struct_same_fields @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const S = extern struct { x: u8, y: u8 }; pub fn main() !void { const val: S = .{ .x = 100, .y = 200 }; @@ -14,10 +17,13 @@ fn foo(val: *const S) !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="100 200\n" +#} +#update +#check stdout { +100 200 +#} -#update=change struct layout -#file=main.zig +#write main.zig { const S = extern struct { x: u32, y: u32 }; pub fn main() !void { const val: S = .{ .x = 100, .y = 200 }; @@ -32,10 +38,14 @@ fn foo(val: *const S) !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="100 200\n" +#} +#update { +change struct layout#} +#check stdout { +100 200 +#} -#update=change values -#file=main.zig +#write main.zig { const S = extern struct { x: u32, y: u32 }; pub fn main() !void { const val: S = .{ .x = 1234, .y = 5678 }; @@ -50,4 +60,9 @@ fn foo(val: *const S) !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="1234 5678\n" +#} +#update { +change values#} +#check stdout { +1234 5678 +#} diff --git a/test/incremental/change_union_tag_type b/test/incremental/change_union_tag_type index 5f754de42ab27224a99c30cff9c645c60fbbf1cb..dbbbc94c1e9bebbfdd1b98743de8a85763e725a5 100644 --- a/test/incremental/change_union_tag_type +++ b/test/incremental/change_union_tag_type @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const A = enum(u8) { a }; const B = enum(u8) { b }; const Foo = union(A) { a: u8 }; @@ -9,10 +12,13 @@ pub fn main(init: std.process.Init) !void { try stdout_writer.interface.print("{s}\n", .{field_name}); } const std = @import("std"); -#expect_stdout="a\n" +#} +#update +#check stdout { +a +#} -#update=change tag type -#file=main.zig +#write main.zig { const A = enum(u8) { a }; const B = enum(u8) { b }; const Foo = union(B) { a: u8 }; @@ -22,11 +28,15 @@ pub fn main(init: std.process.Init) !void { try stdout_writer.interface.print("{s}\n", .{field_name}); } const std = @import("std"); -#expect_error=main.zig:3:24: error: no field named 'a' in enum 'main.B' -#expect_error=main.zig:2:11: note: enum declared here +#} +#update { +change tag type#} +#check errors { +main.zig:3:24: error: no field named 'a' in enum 'main.B' +main.zig:2:11: note: enum declared here +#} -#update=change field name to match new tag type -#file=main.zig +#write main.zig { const A = enum(u8) { a }; const B = enum(u8) { b }; const Foo = union(B) { b: u8 }; @@ -36,4 +46,9 @@ pub fn main(init: std.process.Init) !void { try stdout_writer.interface.print("{s}\n", .{field_name}); } const std = @import("std"); -#expect_stdout="b\n" +#} +#update { +change field name to match new tag type#} +#check stdout { +b +#} diff --git a/test/incremental/change_zon_file b/test/incremental/change_zon_file index 7616c53ea80094d746102df13d51e387a3d1bc40..53b7c82c84703475b71d4495a716041858d27cee 100644 --- a/test/incremental/change_zon_file +++ b/test/incremental/change_zon_file @@ -1,47 +1,74 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); const message: []const u8 = @import("message.zon"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, message); } const io = std.Io.Threaded.global_single_threaded.io(); -#file=message.zon +#} +#write message.zon { "Hello, World!\n" -#expect_stdout="Hello, World!\n" +#} +#update +#check stdout { +Hello, World! +#} -#update=change ZON file contents -#file=message.zon +#write message.zon { "Hello again, World!\n" -#expect_stdout="Hello again, World!\n" +#} +#update { +change ZON file contents#} +#check stdout { +Hello again, World! +#} -#update=delete file -#rm_file=message.zon -#expect_error=message.zon:1:1: error: unable to load "message.zon": FileNotFound -#expect_error=main.zig:2:37: note: file imported here +#delete message.zon +#update { +delete file#} +#check errors { +message.zon:1:1: error: unable to load "message.zon": FileNotFound +main.zig:2:37: note: file imported here +#} -#update=remove reference to ZON file -#file=main.zig +#write main.zig { const std = @import("std"); const message: []const u8 = @import("message.zon"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n"); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=message.zon:1:1: error: unable to load "message.zon": FileNotFound -#expect_error=main.zig:2:37: note: file imported here +#} +#update { +remove reference to ZON file#} +#check errors { +message.zon:1:1: error: unable to load "message.zon": FileNotFound +main.zig:2:37: note: file imported here +#} -#update=recreate ZON file -#file=message.zon +#write message.zon { "We're back, World!\n" -#expect_stdout="a hardcoded string\n" +#} +#update { +recreate ZON file#} +#check stdout { +a hardcoded string +#} -#update=re-introduce reference to ZON file -#file=main.zig +#write main.zig { const std = @import("std"); const message: []const u8 = @import("message.zon"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, message); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="We're back, World!\n" +#} +#update { +re-introduce reference to ZON file#} +#check stdout { +We're back, World! +#} diff --git a/test/incremental/change_zon_file_no_result_type b/test/incremental/change_zon_file_no_result_type index 5deca8c7fda5e77995ec385bea0ed4e58839dd2e..dd63226cbaa21d113d2ff5f7f43484d616a5d956 100644 --- a/test/incremental/change_zon_file_no_result_type +++ b/test/incremental/change_zon_file_no_result_type @@ -1,21 +1,33 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @import("foo.zon").message); } -#file=foo.zon +#} +#write foo.zon { .{ .message = "Hello, World!\n", .a_number = 0, } -#expect_stdout="Hello, World!\n" +#} +#update +#check stdout { +Hello, World! +#} -#update=change ZON file -#file=foo.zon +#write foo.zon { .{ .message = "Hello again, World!\n", .b_number = 0, } -#expect_stdout="Hello again, World!\n" +#} +#update { +change ZON file#} +#check stdout { +Hello again, World! +#} diff --git a/test/incremental/compile_error_then_log b/test/incremental/compile_error_then_log index a19430f7cd2a2e45a7fadb4c6b8b57a3a9927608..44dd98a1734dc9fdc2c5618fa58d8fdcceea8ce9 100644 --- a/test/incremental/compile_error_then_log +++ b/test/incremental/compile_error_then_log @@ -1,5 +1,8 @@ -#update=initial version with compile error -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub fn main() void {} comptime { @compileError("this is an error"); @@ -7,11 +10,17 @@ comptime { comptime { @compileLog("this is a log"); } -#expect_error=main.zig:3:5: error: this is an error -#expect_compile_log=@as(*const [13:0]u8, "this is a log") +#} +#update { +compile error#} +#check errors { +main.zig:3:5: error: this is an error -#update=remove the compile error -#file=main.zig +Compile Log Output: +@as(*const [13:0]u8, "this is a log") +#} + +#write main.zig { pub fn main() void {} comptime { //@compileError("this is an error"); @@ -19,5 +28,12 @@ comptime { comptime { @compileLog("this is a log"); } -#expect_error=main.zig:6:5: error: found compile log statement -#expect_compile_log=@as(*const [13:0]u8, "this is a log") +#} +#update { +remove the compile error#} +#check errors { +main.zig:6:5: error: found compile log statement + +Compile Log Output: +@as(*const [13:0]u8, "this is a log") +#} diff --git a/test/incremental/compile_log b/test/incremental/compile_log index cc4c6368391979358ac215f6b9c73a080cd39ff0..d4445f3ca80aaac2262e70b94ec2f8acaf751603 100644 --- a/test/incremental/compile_log +++ b/test/incremental/compile_log @@ -1,28 +1,46 @@ -#update=initial version with no compile log -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n"); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="Hello, World!\n" +#} +#update { +no compile log#} +#check stdout { +Hello, World! +#} -#update=add compile log -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n"); @compileLog("this is a log"); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:4:5: error: found compile log statement -#expect_compile_log=@as(*const [13:0]u8, "this is a log") +#} +#update { +add compile log#} +#check errors { +main.zig:4:5: error: found compile log statement -#update=remove compile log -#file=main.zig +Compile Log Output: +@as(*const [13:0]u8, "this is a log") +#} + +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n"); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="Hello, World!\n" +#} +#update { +remove compile log#} +#check stdout { +Hello, World! +#} diff --git a/test/incremental/delete_comptime_decls b/test/incremental/delete_comptime_decls index 3d653d6d7dea5296437618569edb701d43bbf3ba..ffae08f3d8d7a26173aefdb4c398895eb26d420a 100644 --- a/test/incremental/delete_comptime_decls +++ b/test/incremental/delete_comptime_decls @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub fn main() void {} comptime { var array = [_:0]u8{ 1, 2, 3, 4 }; @@ -22,13 +25,16 @@ comptime { const slice = array[3..2]; _ = slice; } -#expect_error=main.zig:5:32: error: end index 6 out of bounds for slice of length 4 +1 (sentinel) -#expect_error=main.zig:10:28: error: end index 6 out of bounds for array of length 4 +1 (sentinel) -#expect_error=main.zig:15:28: error: end index 5 out of bounds for array of length 4 -#expect_error=main.zig:20:25: error: start index 3 is larger than end index 2 +#} +#update +#check errors { +main.zig:5:32: error: end index 6 out of bounds for slice of length 4 +1 (sentinel) +main.zig:10:28: error: end index 6 out of bounds for array of length 4 +1 (sentinel) +main.zig:15:28: error: end index 5 out of bounds for array of length 4 +main.zig:20:25: error: start index 3 is larger than end index 2 +#} -#update=delete and modify comptime decls -#file=main.zig +#write main.zig { pub fn main() void {} comptime { const x: [*c]u8 = null; @@ -37,4 +43,9 @@ comptime { const y = x[0..runtime_len]; _ = y; } -#expect_error=main.zig:6:16: error: slice of null pointer +#} +#update { +delete and modify comptime decls#} +#check errors { +main.zig:6:16: error: slice of null pointer +#} diff --git a/test/incremental/dependency_on_type_of_inferred_global b/test/incremental/dependency_on_type_of_inferred_global index 66e52d58394bec7274dec9b0e1767a72338109ac..73d36a7254759c0f98720617aaf3848cc8703070 100644 --- a/test/incremental/dependency_on_type_of_inferred_global +++ b/test/incremental/dependency_on_type_of_inferred_global @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const foo = @as(u8, 123); comptime { // depends on value of `foo` @@ -10,9 +13,12 @@ comptime { if (@TypeOf(&foo) != *const u8) unreachable; } pub fn main() void {} -#expect_stdout="" -#update=change the type -#file=main.zig +#} +#update +#check stdout { +#} + +#write main.zig { const foo = @as(u16, 123); comptime { // depends on value of `foo` @@ -23,4 +29,9 @@ comptime { if (@TypeOf(&foo) != *const u8) unreachable; } pub fn main() void {} -#expect_error=main.zig:8:37: error: reached unreachable code +#} +#update { +change the type#} +#check errors { +main.zig:8:37: error: reached unreachable code +#} diff --git a/test/incremental/do_nothing b/test/incremental/do_nothing index bc50b4bc03836fe9fd93317c60c3b703c7368c0b..213f7f1892d8fa96dbb9313054d862513956ce66 100644 --- a/test/incremental/do_nothing +++ b/test/incremental/do_nothing @@ -1,6 +1,11 @@ -// TODO: it'd be great if we could actually check that no analysis happened! -#update=initial version -#file=main.zig +#todo { +it'd be great if we could actually check that no analysis happened! +#} +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub fn main() void { const ptr: *const O = @ptrFromInt(0x1000); _ = ptr; @@ -18,9 +23,12 @@ const O = opaque { _ = wrapper; } }; -#expect_stdout="" -#update=do literally nothing -#file=main.zig +#} +#update +#check stdout { +#} + +#write main.zig { pub fn main() void { const ptr: *const O = @ptrFromInt(0x1000); _ = ptr; @@ -38,4 +46,8 @@ const O = opaque { _ = wrapper; } }; -#expect_stdout="" +#} +#update { +do literally nothing#} +#check stdout { +#} diff --git a/test/incremental/fix_astgen_failure b/test/incremental/fix_astgen_failure index adddc9ac054c2d95709467018ef70af6a71d2a8a..feb078359a513becff249d9e5e89a88a2e243352 100644 --- a/test/incremental/fix_astgen_failure +++ b/test/incremental/fix_astgen_failure @@ -1,35 +1,59 @@ -#update=initial version with error -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub fn main() !void { try @import("foo.zig").hello(); } -#file=foo.zig +#} +#write foo.zig { pub fn hello() !void { try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n"); } -#expect_error=foo.zig:2:9: error: use of undeclared identifier 'std' -#update=fix the error -#file=foo.zig +#} +#update { +error#} +#check errors { +foo.zig:2:9: error: use of undeclared identifier 'std' +#} + +#write foo.zig { const std = @import("std"); pub fn hello() !void { try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n"); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="Hello, World!\n" -#update=add new error -#file=foo.zig +#} +#update { +fix the error#} +#check stdout { +Hello, World! +#} + +#write foo.zig { const std = @import("std"); pub fn hello() !void { try std.Io.File.stdout().writeStreamingAll(io, hello_str); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=foo.zig:3:52: error: use of undeclared identifier 'hello_str' -#update=fix the new error -#file=foo.zig +#} +#update { +add new error#} +#check errors { +foo.zig:3:52: error: use of undeclared identifier 'hello_str' +#} + +#write foo.zig { const std = @import("std"); const hello_str = "Hello, World! Again!\n"; pub fn hello() !void { try std.Io.File.stdout().writeStreamingAll(io, hello_str); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="Hello, World! Again!\n" +#} +#update { +fix the new error#} +#check stdout { +Hello, World! Again! +#} diff --git a/test/incremental/function_becomes_inline b/test/incremental/function_becomes_inline index 91afe196ab4d1c28fb041a5f9dd8f0b6956ea463..7d64be329579442c284c149e6342bcc0d3105c36 100644 --- a/test/incremental/function_becomes_inline +++ b/test/incremental/function_becomes_inline @@ -1,5 +1,8 @@ -#update=non-inline version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub fn main() !void { try foo(); } @@ -8,10 +11,14 @@ fn foo() !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="Hello, World!\n" +#} +#update { +non-inline version#} +#check stdout { +Hello, World! +#} -#update=make function inline -#file=main.zig +#write main.zig { pub fn main() !void { try foo(); } @@ -20,10 +27,14 @@ inline fn foo() !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="Hello, World!\n" +#} +#update { +make function inline#} +#check stdout { +Hello, World! +#} -#update=change string -#file=main.zig +#write main.zig { pub fn main() !void { try foo(); } @@ -32,4 +43,9 @@ inline fn foo() !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="Hello, `inline` World!\n" +#} +#update { +change string#} +#check stdout { +Hello, `inline` World! +#} diff --git a/test/incremental/hello b/test/incremental/hello index 6988323d3dbb504cad158ad134fccc4ed4023087..74a45d2a8b81afebe334968569949b6c82d4c397 100644 --- a/test/incremental/hello +++ b/test/incremental/hello @@ -1,16 +1,28 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, "good morning\n"); } -#expect_stdout="good morning\n" -#update=change the string -#file=main.zig +#} +#update +#check stdout { +good morning +#} + +#write main.zig { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n"); } -#expect_stdout="おはようございます\n" +#} +#update { +change the string#} +#check stdout { +おはようございます +#} diff --git a/test/incremental/increase_array_field_length b/test/incremental/increase_array_field_length index 714473dd8302d57b0b2644a90f73442d47e9db2d..7b0eb9c165ff1a1b43206624569303b820d658ac 100644 --- a/test/incremental/increase_array_field_length +++ b/test/incremental/increase_array_field_length @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const Big = struct { arr: [10]u8 }; pub fn main(init: std.process.Init) !void { var big: Big = undefined; @@ -12,10 +15,13 @@ pub fn main(init: std.process.Init) !void { }; } const std = @import("std"); -#expect_stdout="arr[9] = 234\n" +#} +#update +#check stdout { +arr[9] = 234 +#} -#update=increase array length -#file=main.zig +#write main.zig { const Big = struct { arr: [1000]u8 }; pub fn main(init: std.process.Init) !void { var big: Big = undefined; @@ -28,4 +34,9 @@ pub fn main(init: std.process.Init) !void { }; } const std = @import("std"); -#expect_stdout="arr[999] = 234\n" +#} +#update { +increase array length#} +#check stdout { +arr[999] = 234 +#} diff --git a/test/incremental/make_decl_pub b/test/incremental/make_decl_pub index cdb057a7dc1fbc0f72d5ed935d47f47c91855f9e..59a54ece02b3850083fdd6c86c63d901cd346157 100644 --- a/test/incremental/make_decl_pub +++ b/test/incremental/make_decl_pub @@ -1,23 +1,35 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const foo = @import("foo.zig"); pub fn main() !void { try foo.hello(); } -#file=foo.zig +#} +#write foo.zig { const std = @import("std"); fn hello() !void { try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n"); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:3:12: error: 'hello' is not marked 'pub' -#expect_error=foo.zig:2:1: note: declared here +#} +#update +#check errors { +main.zig:3:12: error: 'hello' is not marked 'pub' +foo.zig:2:1: note: declared here +#} -#update=make hello pub -#file=foo.zig +#write foo.zig { const std = @import("std"); pub fn hello() !void { try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n"); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="Hello, World!\n" +#} +#update { +make hello pub#} +#check stdout { +Hello, World! +#} diff --git a/test/incremental/modify_inline_fn b/test/incremental/modify_inline_fn index aa7223f6ace49b27eaadfbc92bebffbe6affcc44..956a47a6da82a984edfb3cc9ebf788759c0c61a5 100644 --- a/test/incremental/modify_inline_fn +++ b/test/incremental/modify_inline_fn @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); pub fn main() !void { const str = getStr(); @@ -9,9 +12,13 @@ inline fn getStr() []const u8 { return "foo\n"; } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="foo\n" -#update=change the string -#file=main.zig +#} +#update +#check stdout { +foo +#} + +#write main.zig { const std = @import("std"); pub fn main() !void { const str = getStr(); @@ -21,4 +28,9 @@ inline fn getStr() []const u8 { return "bar\n"; } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="bar\n" +#} +#update { +change the string#} +#check stdout { +bar +#} diff --git a/test/incremental/move_src b/test/incremental/move_src index 20134267d1244fefb659ffc3d204f55c5db347d3..b385a312dbb5d55b6f7605aee556abbda5f9ade4 100644 --- a/test/incremental/move_src +++ b/test/incremental/move_src @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); pub fn main() !void { var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); @@ -12,10 +15,13 @@ fn bar() u32 { return 123; } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="7 123\n" +#} +#update +#check stdout { +7 123 +#} -#update=add newline -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); @@ -29,4 +35,9 @@ fn bar() u32 { return 123; } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="8 123\n" +#} +#update { +add newline#} +#check stdout { +8 123 +#} diff --git a/test/incremental/pointer_to_decl_with_astgen_error b/test/incremental/pointer_to_decl_with_astgen_error index 6c9359209b7fa7e83de855a3e4680f31c566fa5c..87d07ca1abe476a8bc0be5a2abfa2b127736127f 100644 --- a/test/incremental/pointer_to_decl_with_astgen_error +++ b/test/incremental/pointer_to_decl_with_astgen_error @@ -1,23 +1,36 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const foo = {}; pub fn main() void { _ = &foo; } -#expect_stdout="" +#} +#update +#check stdout { +#} -#update=introduce use of undeclared identifier -#file=main.zig +#write main.zig { const foo = something; pub fn main() void { _ = &foo; } -#expect_error=main.zig:1:13: error: use of undeclared identifier 'something' +#} +#update { +introduce use of undeclared identifier#} +#check errors { +main.zig:1:13: error: use of undeclared identifier 'something' +#} -#update=revert use of undeclared identifier -#file=main.zig +#write main.zig { const foo = {}; pub fn main() void { _ = &foo; } -#expect_stdout="" +#} +#update { +revert use of undeclared identifier#} +#check stdout { +#} diff --git a/test/incremental/recursive_function_becomes_non_recursive b/test/incremental/recursive_function_becomes_non_recursive index e789f3860de557247e84240918773ada0362feaa..442748a079c7bc0ca8a97fc726a661e86546acd1 100644 --- a/test/incremental/recursive_function_becomes_non_recursive +++ b/test/incremental/recursive_function_becomes_non_recursive @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub fn main() !void { try foo(false); } @@ -10,10 +13,13 @@ fn foo(recurse: bool) !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="non-recursive path\n" +#} +#update +#check stdout { +non-recursive path +#} -#update=eliminate recursion and change argument -#file=main.zig +#write main.zig { pub fn main() !void { try foo(true); } @@ -24,4 +30,9 @@ fn foo(recurse: bool) !void { } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="x==1\n" +#} +#update { +eliminate recursion and change argument#} +#check stdout { +x==1 +#} diff --git a/test/incremental/remove_enum_field b/test/incremental/remove_enum_field index f478ea7f5528410cb20c367cb01aa0157a34fc12..67b0db55b9d597270216eee728189fbd0a638833 100644 --- a/test/incremental/remove_enum_field +++ b/test/incremental/remove_enum_field @@ -1,27 +1,39 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const MyEnum = enum(u8) { foo = 1, bar = 2, }; pub fn main() !void { var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - try stdout_writer.interface.print("{}\n", .{@intFromEnum(MyEnum.foo)}); + try stdout_writer.interface.print("{}\n", .{@backingInt(MyEnum.foo)}); } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="1\n" -#update=remove enum field -#file=main.zig +#} +#update +#check stdout { +1 +#} + +#write main.zig { const MyEnum = enum(u8) { //foo = 1, bar = 2, }; pub fn main() !void { var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); - try stdout_writer.interface.print("{}\n", .{@intFromEnum(MyEnum.foo)}); + try stdout_writer.interface.print("{}\n", .{@backingInt(MyEnum.foo)}); } const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:7:69: error: enum 'main.MyEnum' has no member named 'foo' -#expect_error=main.zig:1:16: note: enum declared here +#} +#update { +remove enum field#} +#check errors { +main.zig:7:68: error: enum 'main.MyEnum' has no member named 'foo' +main.zig:1:16: note: enum declared here +#} diff --git a/test/incremental/remove_function_with_changed_callee b/test/incremental/remove_function_with_changed_callee index 31e962124dfb10374fd9b0dd70bc743edde143bd..d0a04678922d9ef841393ad2903469baf6ed7ca6 100644 --- a/test/incremental/remove_function_with_changed_callee +++ b/test/incremental/remove_function_with_changed_callee @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); @@ -23,9 +26,12 @@ fn bar(a: A) !void { pub fn main() !void { try foo(); } -#expect_stdout="0" -#update=remove foo and change bar wasm function type -#file=main.zig +#} +#update +#check stdout { +0#} + +#write main.zig { //! This update must preserve `bar` `InternPool.Index` value, while changing its wasm function type. //! If `foo` code is preserved in the binary without any changes, wasm type checking will fail. const std = @import("std"); @@ -47,4 +53,8 @@ fn bar(a: A) !void { pub fn main() !void { try bar(.one); } -#expect_stdout="1" +#} +#update { +remove foo and change bar wasm function type#} +#check stdout { +1#} diff --git a/test/incremental/remove_invalid_union_backing_enum b/test/incremental/remove_invalid_union_backing_enum index 04970380fb621c4e2e9cb2d3c5069d6448c5b989..8a2099afb4ebe92697ff76f773b53abb4eb8b871 100644 --- a/test/incremental/remove_invalid_union_backing_enum +++ b/test/incremental/remove_invalid_union_backing_enum @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const E = enum { a, b, c }; const U = union(E) { a: i32, @@ -11,10 +14,14 @@ pub fn main() void { const u: U = .{ .a = 123 }; _ = u; } -#expect_error=main.zig:6:5: error: no field named 'd' in enum 'main.E' -#expect_error=main.zig:1:11: note: enum declared here -#update=remove invalid backing enum -#file=main.zig +#} +#update +#check errors { +main.zig:6:5: error: no field named 'd' in enum 'main.E' +main.zig:1:11: note: enum declared here +#} + +#write main.zig { const U = union { a: i32, b: f64, @@ -25,4 +32,8 @@ pub fn main() void { const u: U = .{ .a = 123 }; _ = u; } -#expect_stdout="" +#} +#update { +remove invalid backing enum#} +#check stdout { +#} diff --git a/test/incremental/struct_reification_becomes_anon_init b/test/incremental/struct_reification_becomes_anon_init index 7099685ba2c2e464607039c5eb461fa500422d69..bd790cdeb9445aab9834c64f0a5fa683974b6d95 100644 --- a/test/incremental/struct_reification_becomes_anon_init +++ b/test/incremental/struct_reification_becomes_anon_init @@ -1,19 +1,30 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const Foo = @Struct(.auto, null, &.{"reified_field"}, &.{void}, &.{.{}}); pub fn main(init: std.process.Init) !void { const field_name = @typeInfo(Foo).@"struct".field_names[0]; try std.Io.File.stdout().writeStreamingAll(init.io, field_name ++ "\n"); } const std = @import("std"); -#expect_stdout="reified_field\n" +#} +#update +#check stdout { +reified_field +#} -#update=change to `@TypeOf` anonymous init -#file=main.zig +#write main.zig { const Foo = @TypeOf(.{ .anon_field = 123 }); pub fn main(init: std.process.Init) !void { const field_name = @typeInfo(Foo).@"struct".field_names[0]; try std.Io.File.stdout().writeStreamingAll(init.io, field_name ++ "\n"); } const std = @import("std"); -#expect_stdout="anon_field\n" +#} +#update { +change to `@TypeOf` anonymous init#} +#check stdout { +anon_field +#} diff --git a/test/incremental/tag_name b/test/incremental/tag_name index 17954435c15786ddf98bbd576c1a2ae346ab14aa..05991657cdbfd920ee24d094bb8db93ada706d17 100644 --- a/test/incremental/tag_name +++ b/test/incremental/tag_name @@ -1,27 +1,41 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); var some_enum: enum { first, second } = .first; const io = std.Io.Threaded.global_single_threaded.io(); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum)); } -#expect_stdout="first" -#update=no change -#file=main.zig +#} +#update +#check stdout { +first#} + +#write main.zig { const std = @import("std"); var some_enum: enum { first, second } = .first; const io = std.Io.Threaded.global_single_threaded.io(); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum)); } -#expect_stdout="first" -#update=swap fields -#file=main.zig +#} +#update { +no change#} +#check stdout { +first#} + +#write main.zig { const std = @import("std"); var some_enum: enum { second, first } = .first; const io = std.Io.Threaded.global_single_threaded.io(); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum)); } -#expect_stdout="first" +#} +#update { +swap fields#} +#check stdout { +first#} diff --git a/test/incremental/temporary_analysis_error_in_generic_signature b/test/incremental/temporary_analysis_error_in_generic_signature index d8db72050b3af1164a312e1e7a1ed1f89bfc3dae..dbb3b6407eba276b9654775979353b53d9cea452 100644 --- a/test/incremental/temporary_analysis_error_in_generic_signature +++ b/test/incremental/temporary_analysis_error_in_generic_signature @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { //! The original repro here depends on re-analysis order, which depends on //! declaration order, so this exact declaration order must be used. const Foo = struct { x: u8 }; @@ -11,10 +14,13 @@ fn bar(comptime x: u8) @This().Foo { return .{ .x = x }; } const std = @import("std"); -#expect_stdout="Z\n" +#} +#update +#check stdout { +Z +#} -#update=change generic signature to use non-existent member -#file=main.zig +#write main.zig { //! The original repro here depends on re-analysis order, which depends on //! declaration order, so this exact declaration order must be used. const Foo = struct { x: u8 }; @@ -26,11 +32,15 @@ fn bar(comptime x: u8) @This().FooAlias { return .{ .x = x }; } const std = @import("std"); -#expect_error=main.zig:8:31: error: root source file struct 'main' has no member named 'FooAlias' -#expect_error=main.zig:1:1: note: struct declared here +#} +#update { +change generic signature to use non-existent member#} +#check errors { +main.zig:8:31: error: root source file struct 'main' has no member named 'FooAlias' +main.zig:1:1: note: struct declared here +#} -#update=add that member, fixing the error -#file=main.zig +#write main.zig { //! The original repro here depends on re-analysis order, which depends on //! declaration order, so this exact declaration order must be used. const Foo = struct { x: u8 }; @@ -43,4 +53,9 @@ fn bar(comptime x: u8) @This().FooAlias { return .{ .x = x }; } const std = @import("std"); -#expect_stdout="Z\n" +#} +#update { +add that member, fixing the error#} +#check stdout { +Z +#} diff --git a/test/incremental/temporary_parse_error b/test/incremental/temporary_parse_error index b19636e4455a8c19a028372276b96560c5c523da..9687ac4844b79133391f85addd09e71a44c8f6cd 100644 --- a/test/incremental/temporary_parse_error +++ b/test/incremental/temporary_parse_error @@ -1,15 +1,28 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); pub fn main() !void {} -#expect_stdout="" +#} +#update +#check stdout { +#} -#update=introduce parse error -#file=main.zig +#write main.zig { pub fn main() !void { -#expect_error=main.zig:2:1: error: expected statement, found 'EOF' +#} +#update { +introduce parse error#} +#check errors { +main.zig:2:1: error: expected statement, found 'EOF' +#} -#update=fix parse error -#file=main.zig +#write main.zig { pub fn main() !void {} -#expect_stdout="" +#} +#update { +fix parse error#} +#check stdout { +#} diff --git a/test/incremental/type_becomes_comptime_only b/test/incremental/type_becomes_comptime_only index f5b0f9b5786a684d7e2dc72f78438d18ffad84e5..f174faacd788e3e5d4720c9badb1cb2e5f91c9ea 100644 --- a/test/incremental/type_becomes_comptime_only +++ b/test/incremental/type_becomes_comptime_only @@ -1,5 +1,8 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const SomeType = u32; const S = struct { x: SomeType, @@ -9,10 +12,12 @@ pub fn main() void { const s: S = .{ .x = 456 }; s.foo(); } -#expect_stdout="" +#} +#update +#check stdout { +#} -#update=make S comptime-only -#file=main.zig +#write main.zig { const SomeType = comptime_int; const S = struct { x: SomeType, @@ -22,10 +27,13 @@ pub fn main() void { const s: S = .{ .x = 456 }; s.foo(); } -#expect_stdout="" +#} +#update { +make S comptime-only#} +#check stdout { +#} -#update=make S runtime again -#file=main.zig +#write main.zig { const SomeType = u16; const S = struct { x: SomeType, @@ -35,4 +43,8 @@ pub fn main() void { const s: S = .{ .x = 456 }; s.foo(); } -#expect_stdout="" +#} +#update { +make S runtime again#} +#check stdout { +#} diff --git a/test/incremental/type_dependency_loop b/test/incremental/type_dependency_loop index b645d4266215f712826dee9291dc3150c397108f..85de8ae8391015b85194357423522046466cc042 100644 --- a/test/incremental/type_dependency_loop +++ b/test/incremental/type_dependency_loop @@ -1,50 +1,70 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { pub const A = struct { b: B }; pub const B = struct { a: A }; pub fn main() void { _ = @as(B, undefined); } -#expect_error=:error: dependency loop with length 2 -#expect_error=main.zig:2:27: note: type 'main.B' depends on type 'main.A' for field declared here -#expect_error=main.zig:1:27: note: type 'main.A' depends on type 'main.B' for field declared here -#expect_error=:note: eliminate any one of these dependencies to break the loop +#} +#update +#check errors { +error: dependency loop with length 2 + main.zig:2:27: note: type 'main.B' depends on type 'main.A' for field declared here + main.zig:1:27: note: type 'main.A' depends on type 'main.B' for field declared here + note: eliminate any one of these dependencies to break the loop +#} -#update=remove reference to dependency loop -#file=main.zig +#write main.zig { pub const A = struct { b: B }; pub const B = struct { a: A }; pub fn main() void { _ = B; } -#expect_stdout="" +#} +#update { +remove reference to dependency loop#} +#check stdout { +#} -#update=change dependency loop without fixing it -#file=main.zig +#write main.zig { pub const A = struct { b: B }; pub const B = struct { a: *align(@alignOf(A)) A }; pub fn main() void { _ = B; } -#expect_stdout="" +#} +#update { +change dependency loop without fixing it#} +#check stdout { +#} -#update=reference dependency loop again -#file=main.zig +#write main.zig { pub const A = struct { b: B }; pub const B = struct { a: *align(@alignOf(A)) A }; pub fn main() void { _ = @as(B, undefined); } -#expect_error=:error: dependency loop with length 2 -#expect_error=main.zig:2:43: note: type 'main.B' depends on type 'main.A' for alignment query here -#expect_error=main.zig:1:27: note: type 'main.A' depends on type 'main.B' for field declared here -#expect_error=:note: eliminate any one of these dependencies to break the loop +#} +#update { +reference dependency loop again#} +#check errors { +error: dependency loop with length 2 + main.zig:2:43: note: type 'main.B' depends on type 'main.A' for alignment query here + main.zig:1:27: note: type 'main.A' depends on type 'main.B' for field declared here + note: eliminate any one of these dependencies to break the loop +#} -#update=fix dependency loop -#file=main.zig +#write main.zig { pub const A = struct { b: B }; pub const B = struct { a: *A }; pub fn main() void { _ = @as(B, undefined); } -#expect_stdout="" +#} +#update { +fix dependency loop#} +#check stdout { +#} diff --git a/test/incremental/unreferenced_error b/test/incremental/unreferenced_error index f0ab8062594912c7b990472104877bd61a3d6680..0f5f65feab5c98985d105d06db1e2086cd6f0470 100644 --- a/test/incremental/unreferenced_error +++ b/test/incremental/unreferenced_error @@ -1,25 +1,35 @@ -#update=initial version -#file=main.zig +#exe { +-Mroot=main.zig +#} + +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, a); } const a = "Hello, World!\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="Hello, World!\n" +#} +#update +#check stdout { +Hello, World! +#} -#update=introduce compile error -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, a); } const a = @compileError("bad a"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:5:11: error: bad a +#} +#update { +introduce compile error#} +#check errors { +main.zig:5:11: error: bad a +#} -#update=remove error reference -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, b); @@ -27,10 +37,14 @@ pub fn main() !void { const a = @compileError("bad a"); const b = "Hi there!\n"; const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="Hi there!\n" +#} +#update { +remove error reference#} +#check stdout { +Hi there! +#} -#update=introduce and remove reference to error -#file=main.zig +#write main.zig { const std = @import("std"); pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, a); @@ -38,4 +52,9 @@ pub fn main() !void { const a = "Back to a\n"; const b = @compileError("bad b"); const io = std.Io.Threaded.global_single_threaded.io(); -#expect_stdout="Back to a\n" +#} +#update { +introduce and remove reference to error#} +#check stdout { +Back to a +#} diff --git a/test/incremental2/bad_import b/test/incremental2/bad_import deleted file mode 100644 index d93a9ed6309f963c310a82f0813d0905a564cc10..0000000000000000000000000000000000000000 --- a/test/incremental2/bad_import +++ /dev/null @@ -1,48 +0,0 @@ -#exe { --Mroot=main.zig -#} - -#write main.zig { -pub fn main() !void { - _ = @import("foo.zig"); - try std.Io.File.stdout().writeStreamingAll(io, "success\n"); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#} -#write foo.zig { -comptime { - _ = @import("bad.zig"); -} -#} -#update -#check errors { -bad.zig:1:1: error: unable to load "bad.zig": FileNotFound -foo.zig:2:17: note: file imported here -#} - -#write foo.zig { -comptime { - _ = @import("this_is/not_real.zig"); -} -#} -#update { -change bad import#} -#check errors { -this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound -foo.zig:2:17: note: file imported here -#} - -#write main.zig { -pub fn main() !void { - //_ = @import("foo.zig"); - try std.Io.File.stdout().writeStreamingAll(io, "success\n"); -} -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -#} -#update { -remove import of 'foo.zig'#} -#check stdout { -success -#} diff --git a/test/incremental2/hello b/test/incremental2/hello deleted file mode 100644 index 74a45d2a8b81afebe334968569949b6c82d4c397..0000000000000000000000000000000000000000 --- a/test/incremental2/hello +++ /dev/null @@ -1,28 +0,0 @@ -#exe { --Mroot=main.zig -#} - -#write main.zig { -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -pub fn main() !void { - try std.Io.File.stdout().writeStreamingAll(io, "good morning\n"); -} -#} -#update -#check stdout { -good morning -#} - -#write main.zig { -const std = @import("std"); -const io = std.Io.Threaded.global_single_threaded.io(); -pub fn main() !void { - try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n"); -} -#} -#update { -change the string#} -#check stdout { -おはようございます -#} diff --git a/test/src/runner.zig b/test/src/runner.zig index e4d7e9971fc965bb4724bcdec971a5c1ed754156..9e37cec171b5d5134486a21c9459e508b31e3025 100644 --- a/test/src/runner.zig +++ b/test/src/runner.zig @@ -471,7 +471,7 @@ fn runTest( continue; } const cmd = std.meta.stringToEnum( - enum { skip, exe, lib, obj, write, delete, update, check }, + enum { todo, skip, exe, lib, obj, write, delete, update, check }, cmd_str, ) orelse return error.UnknownCommand; var maybe_arg = line_it.next(); @@ -525,6 +525,7 @@ fn runTest( }; defer cmd_prog_node.end(); cmd: switch (cmd) { + .todo => _ = try contents_r.discardRemaining(), .skip => if (!allow_skip) return error.NonInitialSkipCommand // #skip must appear first else if (std.mem.eql(u8, target_string, maybe_arg orelse return error.MissingArg)) @@ -646,12 +647,12 @@ fn runTest( update_num += 1; }, .check => { - const expected = try contents_r.allocRemaining(gpa, .unlimited); - defer gpa.free(expected); const check = std.meta.stringToEnum( enum { errors, stdout, exit, lldb }, maybe_arg orelse return error.MissingCheckArg, ) orelse return error.UnknownCheck; + const expected = try contents_r.allocRemaining(gpa, .unlimited); + defer gpa.free(expected); const comp = &(compiler orelse return error.MissingCompiler); if (comp.state != .update) return error.MissingUpdate; @@ -753,7 +754,9 @@ fn runTest( var error_aw: std.Io.Writer.Allocating = .init(gpa); defer error_aw.deinit(); try error_bundle.renderToWriter(.{ + .include_reference_trace = false, .include_source_line = false, + .include_log_text = true, }, &error_aw.writer); try std.testing.expectEqualStrings(expected, error_aw.written()); }, @@ -783,12 +786,18 @@ fn runTest( }, } std.debug.assert(try contents_r.discardRemaining() == 0); - if (cmd != .skip) allow_skip = false; + switch (cmd) { + .todo, .skip => {}, + else => allow_skip = false, + } } else |err| switch (err) { else => |e| return e, error.EndOfStream => if (skip_delimiter) return error.MissingDelimiter, } - if (compiler) |*comp| try comp.exit(io); + if (compiler) |*comp| { + if (comp.state != .idle) return error.MissingCheck; + try comp.exit(io); + } } const DelimitedReader = struct { const Io = std.Io; diff --git a/test/tests.zig b/test/tests.zig index b782307a3644d54a11ec3da00d150d9650ae4d11..d92863cc88bded40c15102941b11d3ec5f748178 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -3343,109 +3343,16 @@ const IncrementalTestOptions = struct { }; pub fn addIncrementalTests( - b: *std.Build, - test_step: *Step, - options: IncrementalTestOptions, -) !void { - const io = b.graph.io; - - const incr_check = b.addExecutable(.{ - .name = "incr-check", - .root_module = b.createModule(.{ - .root_source_file = b.path("tools/incr-check.zig"), - .target = b.graph.host, - .optimize = .debug, - }), - }); - - b.dependOnDirectoryContents(b.path("test/incremental")); - - var dir = try b.root.openDir(io, "test/incremental", .{ .iterate = true }); - defer dir.close(io); - - var it = try dir.walk(b.graph.arena); - while (try it.next(io)) |entry| { - if (isEditorFileName(entry.basename)) continue; - - for (options.test_filters) |test_filter| { - if (std.mem.find(u8, entry.path, test_filter)) |_| break; - } else if (options.test_filters.len > 0) continue; - - switch (entry.kind) { - .file => {}, - .directory => { - b.dependOnDirectoryContents(b.path(b.pathJoin(&.{ "test", "incremental", entry.path }))); - }, - else => continue, - } - b.dependOnFileContents(b.path(b.pathJoin(&.{ "test", "incremental", entry.path }))); - - for (incremental_targets) |test_target| { - const resolved_target = b.resolveTargetQuery(test_target.target); - - if (options.skip_non_native and !isNative(&resolved_target, &b.graph.host.result)) - continue; - - const target = &resolved_target.result; - - if (options.skip_wasm and target.cpu.arch.isWasm()) continue; - - if (options.skip_freebsd and target.os.tag == .freebsd) continue; - if (options.skip_netbsd and target.os.tag == .netbsd) continue; - if (options.skip_openbsd and target.os.tag == .openbsd) continue; - if (options.skip_windows and target.os.tag == .windows) continue; - if (options.skip_darwin and target.os.tag.isDarwin()) continue; - if (options.skip_linux and target.os.tag == .linux) continue; - - if (options.skip_llvm and test_target.backend == .llvm) continue; - - const target_str = b.fmt("{s}-{t}", .{ - resolved_target.query.zigTriple(b.allocator) catch @panic("OOM"), - test_target.backend, - }); - - if (options.test_target_filters.len > 0) { - for (options.test_target_filters) |filter| { - if (std.mem.find(u8, target_str, filter) != null) break; - } else continue; - } - - const run = b.addRunArtifact(incr_check); - run.setName(b.fmt("incr-check {s} '{s}'", .{ target_str, entry.basename })); - - run.addArg(b.graph.zig_exe); - run.addFileArg(b.path("test/incremental/").path(b, entry.path)); - - run.addArg("--zig-lib-dir"); - run.addDirectoryArg(.zig_lib); - - run.addArgs(&.{ "--target", target_str }); - - run.addArg("--quiet"); // don't fill stderr telling us about skipped tests etc - - run.addThirdPartyEnabledArgDarling(.{ .enabled = "-fdarling" }); - run.addThirdPartyEnabledArgQemu(.{ .enabled = "-fqemu" }); - run.addThirdPartyEnabledArgRosetta(.{ .enabled = "-frosetta" }); - run.addThirdPartyEnabledArgWasmtime(.{ .enabled = "-fwasmtime" }); - run.addThirdPartyEnabledArgWine(.{ .enabled = "-fwine" }); - - run.addCheck(.{ .expect_term = .{ .exited = 0 } }); - test_step.dependOn(&run.step); - } - } -} - -pub fn addNewIncrementalTests( b: *std.Build, runner: *std.Build.Step.Compile, options: IncrementalTestOptions, ) !*Step { - const tests_step = b.step("test-new-incremental", "Run the new incremental compilation test cases"); + const tests_step = b.step("test-incremental", "Run the new incremental compilation test cases"); - const tests_path = b.path("test/incremental2"); + const tests_path = b.path("test/incremental"); b.dependOnDirectoryContents(tests_path); - var tests_dir = try b.root.openDir(b.graph.io, "test/incremental2", .{ .iterate = true }); + var tests_dir = try b.root.openDir(b.graph.io, "test/incremental", .{ .iterate = true }); defer tests_dir.close(b.graph.io); var test_it = tests_dir.iterate(); while (try test_it.next(b.graph.io)) |@"test"| { diff --git a/tools/incr-check.zig b/tools/incr-check.zig deleted file mode 100644 index c8034260dbc2af7a256151c7c43f4429531e390b..0000000000000000000000000000000000000000 --- a/tools/incr-check.zig +++ /dev/null @@ -1,1032 +0,0 @@ -const std = @import("std"); -const Io = std.Io; -const Dir = std.Io.Dir; -const Allocator = std.mem.Allocator; -const Cache = std.Build.Cache; - -const usage = - \\Usage: incr-check [options] - \\Options: - \\ --target triple-backend - \\ --quiet - \\ --zig-lib-dir /path/to/zig/lib - \\ --zig-cc-binary /path/to/zig - \\ -fqemu - \\ -fwine - \\ -fwasmtime - \\Debug Options: - \\ --preserve-tmp - \\ --debug-log foo - \\ --debug-link-snapshot -; - -pub const std_options: std.Options = .{ - .logFn = logImpl, -}; -var log_cur_update: ?*const Case.Update = null; -fn logImpl( - comptime level: std.log.Level, - comptime scope: @EnumLiteral(), - comptime format: []const u8, - args: anytype, -) void { - const update = log_cur_update orelse { - return std.log.defaultLog(level, scope, format, args); - }; - std.log.defaultLog( - level, - scope, - "['{s}'] " ++ format, - .{update.name} ++ args, - ); -} - -pub fn main(init: std.process.Init) !void { - const gpa = init.gpa; - const arena = init.arena.allocator(); - const io = init.io; - const environ_map = init.environ_map; - const cwd_path = try std.process.currentPathAlloc(io, arena); - - var opt_zig_exe: ?[]const u8 = null; - var opt_input_file_name: ?[]const u8 = null; - var opt_lib_dir: ?[]const u8 = null; - var opt_cc_zig: ?[]const u8 = null; - var opt_target: ?struct { std.Target.Query, Backend } = null; - var preserve_tmp = false; - var enable_qemu: bool = false; - var enable_wine: bool = false; - var enable_wasmtime: bool = false; - var enable_darling: bool = false; - var quiet: bool = false; - - var debug_log_args: std.ArrayList([]const u8) = .empty; - var debug_link_snapshot = false; - - var arg_it = try init.minimal.args.iterateAllocator(arena); - _ = arg_it.skip(); - while (arg_it.next()) |arg| { - if (arg.len > 0 and arg[0] == '-') { - if (std.mem.eql(u8, arg, "--zig-lib-dir")) { - opt_lib_dir = arg_it.next() orelse badUsage("expected arg after --zig-lib-dir", .{}); - } else if (std.mem.eql(u8, arg, "--target")) { - const str = arg_it.next() orelse badUsage("expected arg after --zig-cc-binary", .{}); - opt_target = parseTargetQueryAndBackend(str, ""); - } else if (std.mem.eql(u8, arg, "--quiet")) { - quiet = true; - } else if (std.mem.eql(u8, arg, "--debug-log")) { - try debug_log_args.append( - arena, - arg_it.next() orelse badUsage("expected arg after --debug-log", .{}), - ); - } else if (std.mem.eql(u8, arg, "--debug-link-snapshot")) { - debug_link_snapshot = true; - } else if (std.mem.eql(u8, arg, "--preserve-tmp")) { - preserve_tmp = true; - } else if (std.mem.eql(u8, arg, "-fqemu")) { - enable_qemu = true; - } else if (std.mem.eql(u8, arg, "-fwine")) { - enable_wine = true; - } else if (std.mem.eql(u8, arg, "-fwasmtime")) { - enable_wasmtime = true; - } else if (std.mem.eql(u8, arg, "-fdarling")) { - enable_darling = true; - } else if (std.mem.eql(u8, arg, "--zig-cc-binary")) { - opt_cc_zig = arg_it.next() orelse badUsage("expected arg after --zig-cc-binary", .{}); - } else { - badUsage("unknown option '{s}'", .{arg}); - } - continue; - } - if (opt_zig_exe == null) { - opt_zig_exe = arg; - } else if (opt_input_file_name == null) { - opt_input_file_name = arg; - } else { - badUsage("unknown argument '{s}'\n{s}", .{ arg, usage }); - } - } - const zig_exe = opt_zig_exe orelse badUsage("missing path to zig", .{}); - const input_file_name = opt_input_file_name orelse badUsage("missing input file", .{}); - const target_query, const backend = opt_target orelse badUsage("missing required option '--target'", .{}); - - if (backend == .cbe and opt_lib_dir == null) { - std.process.fatal("'--zig-lib-dir' required when using backend 'cbe'", .{}); - } - - const input_file_bytes = try Dir.cwd().readFileAlloc(io, input_file_name, arena, .limited(std.math.maxInt(u32))); - const case: Case = try .parse(arena, input_file_bytes); - - for (case.skip_targets) |skip| { - if (target_query.eql(skip.query) and backend == skip.backend) { - if (!quiet) std.log.warn("skipping test because of a 'skip_target' match", .{}); - return; - } - } - - const target = try std.zig.system.resolveTargetQuery(io, target_query); - - const prog_node = std.Progress.start(io, .{}); - defer prog_node.end(); - - const rand_int = rand64(io); - const tmp_dir_path = "tmp_" ++ std.fmt.hex(rand_int); - var tmp_dir = try Dir.cwd().createDirPathOpen(io, tmp_dir_path, .{}); - defer { - tmp_dir.close(io); - if (!preserve_tmp) { - Dir.cwd().deleteTree(io, tmp_dir_path) catch |err| { - std.log.warn("failed to delete tree '{s}': {t}", .{ tmp_dir_path, err }); - }; - } - } - - // Convert paths to be relative to the cwd of the subprocess. - const resolved_zig_exe = try Dir.path.relative(arena, cwd_path, environ_map, tmp_dir_path, zig_exe); - const opt_resolved_lib_dir = if (opt_lib_dir) |lib_dir| - try Dir.path.relative(arena, cwd_path, environ_map, tmp_dir_path, lib_dir) - else - null; - - const host = try std.zig.system.resolveTargetQuery(io, .{}); - - var child_args: std.ArrayList([]const u8) = .empty; - try child_args.appendSlice(arena, &.{ - resolved_zig_exe, "build-exe", - "-fincremental", "-fno-ubsan-rt", - "-target", try target_query.zigTriple(arena), - "--cache-dir", ".local-cache", - "--global-cache-dir", ".global-cache", - }); - - if (opt_resolved_lib_dir) |resolved_lib_dir| { - try child_args.appendSlice(arena, &.{ "--zig-lib-dir", resolved_lib_dir }); - } - switch (backend) { - .sema => try child_args.append(arena, "-fno-emit-bin"), - .selfhosted => try child_args.appendSlice(arena, &.{ "-fno-llvm", "-fno-lld" }), - .llvm => try child_args.appendSlice(arena, &.{ "-fllvm", "-flld" }), - .cbe => try child_args.appendSlice(arena, &.{ "-ofmt=c", "-lc" }), - } - for (debug_log_args.items) |arg| { - try child_args.appendSlice(arena, &.{ "--debug-log", arg }); - } - if (debug_link_snapshot) { - try child_args.append(arena, "--debug-link-snapshot"); - } - for (case.modules) |mod| { - try child_args.appendSlice(arena, &.{ "--dep", mod.name }); - } - try child_args.append(arena, try std.fmt.allocPrint(arena, "-Mroot={s}", .{case.root_source_file})); - for (case.modules) |mod| { - try child_args.append(arena, try std.fmt.allocPrint(arena, "-M{s}={s}", .{ mod.name, mod.file })); - } - try child_args.append(arena, "--listen=-"); - - const zig_prog_node = prog_node.start("zig", 0); - defer zig_prog_node.end(); - - var cc_child_args: std.ArrayList([]const u8) = .empty; - if (backend == .cbe) { - const resolved_cc_zig_exe = if (opt_cc_zig) |cc_zig_exe| - try Dir.path.relative(arena, cwd_path, environ_map, tmp_dir_path, cc_zig_exe) - else - resolved_zig_exe; - - try cc_child_args.appendSlice(arena, &.{ - resolved_cc_zig_exe, "build-exe", - "-target", try target_query.zigTriple(arena), - "--cache-dir", ".local-cache", - "--global-cache-dir", ".global-cache", - "-I", opt_resolved_lib_dir.?, // verified earlier - "-lc", - }); - } - - const allow_compiler_stderr = debug_log_args.items.len != 0; - - if (allow_compiler_stderr) { - const cmd: std.zig.SubprocessCommand = .{ - .argv = child_args.items, - .cwd = tmp_dir_path, - }; - std.log.scoped(.spawn).info("{f}", .{cmd}); - } - - var child = try std.process.spawn(io, .{ - .argv = child_args.items, - .stdin = .pipe, - .stdout = .pipe, - .stderr = .pipe, - .progress_node = zig_prog_node, - .cwd = .{ .path = tmp_dir_path }, - }); - defer child.kill(io); - - const updates_prog_node = prog_node.start("updates", case.updates.len); - defer updates_prog_node.end(); - - var eval: Eval = .{ - .arena = arena, - .io = io, - .case = case, - .host = host, - .target = target, - .backend = backend, - .tmp_dir = tmp_dir, - .tmp_dir_path = tmp_dir_path, - .child = &child, - .allow_compiler_stderr = allow_compiler_stderr, - .quiet = quiet, - .preserve_tmp_on_fatal = preserve_tmp, - .cc_child_args = &cc_child_args, - .enable_qemu = enable_qemu, - .enable_wine = enable_wine, - .enable_wasmtime = enable_wasmtime, - .enable_darling = enable_darling, - }; - - var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined; - var multi_reader: Io.File.MultiReader = undefined; - multi_reader.init(gpa, io, multi_reader_buffer.toStreams(), &.{ child.stdout.?, child.stderr.? }); - defer multi_reader.deinit(); - - var update_mtime = Io.Clock.real.now(io); - for (case.updates) |update| { - var update_prog_node = updates_prog_node.start(update.name, 0); - defer update_prog_node.end(); - - if (debug_log_args.items.len != 0) { - // Print a line separating the debug logs from the compiler in the stderr output. - std.log.scoped(.status).info("update: '{s}'", .{update.name}); - } - - log_cur_update = &update; - defer log_cur_update = null; - - eval.write(update, update_mtime); - update_mtime = update_mtime.addDuration(.fromSeconds(5)); - try eval.requestUpdate(); - try eval.check(&multi_reader, update, update_prog_node); - } - - try eval.end(&multi_reader); - - waitChild(&child, &eval); -} - -const Eval = struct { - arena: Allocator, - io: Io, - case: Case, - host: std.Target, - target: std.Target, - backend: Backend, - tmp_dir: Dir, - tmp_dir_path: []const u8, - child: *std.process.Child, - allow_compiler_stderr: bool, - quiet: bool, - preserve_tmp_on_fatal: bool, - /// When `backend == .cbe`, this contains the first few arguments to `zig cc` to build the generated binary. - /// The arguments `out.c in.c` must be appended before spawning the subprocess. - cc_child_args: *std.ArrayList([]const u8), - - enable_qemu: bool, - enable_wine: bool, - enable_wasmtime: bool, - enable_darling: bool, - - /// Currently this function assumes the previous updates have already been written. - fn write(eval: *Eval, update: Case.Update, mtime: Io.Timestamp) void { - const io = eval.io; - for (update.changes) |full_contents| { - var update_file = eval.tmp_dir.createFile(io, full_contents.name, .{}) catch |err| { - eval.fatal("failed to create update '{s}': {t}", .{ full_contents.name, err }); - }; - defer update_file.close(io); - update_file.writeStreamingAll(io, full_contents.bytes) catch |err| { - eval.fatal("failed to write update '{s}': {t}", .{ full_contents.name, err }); - }; - update_file.setTimestamps(io, .{ .modify_timestamp = .{ .new = mtime } }) catch |err| { - eval.fatal("failed to set mtime for '{s}': {t}", .{ full_contents.name, err }); - }; - } - for (update.deletes) |doomed_name| { - eval.tmp_dir.deleteFile(io, doomed_name) catch |err| { - eval.fatal("failed to delete '{s}': {t}", .{ doomed_name, err }); - }; - } - } - - fn check(eval: *Eval, mr: *Io.File.MultiReader, update: Case.Update, prog_node: std.Progress.Node) !void { - const arena = eval.arena; - const stdout = mr.reader(0); - const stderr = mr.reader(1); - - var client: std.zig.Client = .{ - .in = stdout, - .out = undefined, - }; - - while (true) { - const header = client.receiveMessageWithMultiReader(mr, .none) catch |err| switch (err) { - error.Timeout => unreachable, - error.EndOfStream => break, - else => |e| return e, - }; - const body = client.in.take(header.bytes_len) catch unreachable; - - switch (header.tag) { - .error_bundle => { - const result_error_bundle = try std.zig.Server.allocErrorBundle(arena, body); - if (stderr.bufferedLen() > 0) { - if (eval.allow_compiler_stderr) { - std.log.info("error_bundle stderr:\n{s}", .{stderr.buffered()}); - } else { - eval.fatal("error_bundle unexpected stderr:\n{s}", .{stderr.buffered()}); - } - stderr.tossBuffered(); - } - if (result_error_bundle.errorMessageCount() != 0) { - try eval.checkErrorOutcome(update, result_error_bundle); - } - // This message indicates the end of the update. - return; - }, - .emit_digest => { - var r: std.Io.Reader = .fixed(body); - _ = r.takeStruct(std.zig.Server.Message.EmitDigest, .little) catch unreachable; - - if (stderr.bufferedLen() > 0) { - if (eval.allow_compiler_stderr) { - std.log.info("emit_digest stderr:\n{s}", .{stderr.buffered()}); - } else { - eval.fatal("emit_digest unexpected stderr:\n{s}", .{stderr.buffered()}); - } - stderr.tossBuffered(); - } - if (eval.backend == .sema) { - try eval.checkSuccessOutcome(update, null, prog_node); - continue; - } - - const digest = r.takeArray(Cache.bin_digest_len) catch unreachable; - const result_dir = ".local-cache" ++ Dir.path.sep_str ++ "o" ++ Dir.path.sep_str ++ Cache.binToHex(digest.*); - - const bin_name = try std.zig.EmitArtifact.bin.cacheName(arena, .{ - .root_name = "root", // corresponds to the module name "root" - .cpu_arch = eval.target.cpu.arch, - .os_tag = eval.target.os.tag, - .ofmt = eval.target.ofmt, - .abi = eval.target.abi, - .output_mode = .Exe, - }); - const bin_path = try Dir.path.join(arena, &.{ result_dir, bin_name }); - - try eval.checkSuccessOutcome(update, bin_path, prog_node); - }, - else => { - // Ignore other messages. - }, - } - } - - const buffered_stderr = stderr.buffered(); - if (buffered_stderr.len > 0) { - if (eval.allow_compiler_stderr) { - std.log.info("stderr:\n{s}", .{buffered_stderr}); - } else { - eval.fatal("unexpected stderr:\n{s}", .{buffered_stderr}); - } - } - - waitChild(eval.child, eval); - eval.fatal("compiler failed to send terminating error_bundle", .{}); - } - - fn checkErrorOutcome(eval: *Eval, update: Case.Update, error_bundle: std.zig.ErrorBundle) !void { - const io = eval.io; - const expected = switch (update.outcome) { - .unknown => return, - .compile_errors => |ce| ce, - .stdout, .exit_code => { - try error_bundle.renderToStderr(io, .{}, .auto); - eval.fatal("unexpected compile errors", .{}); - }, - }; - - var expected_idx: usize = 0; - - for (error_bundle.getMessages()) |err_idx| { - if (expected_idx == expected.errors.len) { - try error_bundle.renderToStderr(io, .{}, .auto); - eval.fatal("more errors than expected", .{}); - } - try eval.checkOneError(error_bundle, expected.errors[expected_idx], false, err_idx); - expected_idx += 1; - - for (error_bundle.getNotes(err_idx)) |note_idx| { - if (expected_idx == expected.errors.len) { - try error_bundle.renderToStderr(io, .{}, .auto); - eval.fatal("more error notes than expected", .{}); - } - try eval.checkOneError(error_bundle, expected.errors[expected_idx], true, note_idx); - expected_idx += 1; - } - } - - if (!std.mem.eql(u8, error_bundle.getCompileLogOutput(), expected.compile_log_output)) { - try error_bundle.renderToStderr(io, .{}, .auto); - eval.fatal("unexpected compile log output", .{}); - } - } - - fn checkOneError( - eval: *Eval, - eb: std.zig.ErrorBundle, - expected: Case.ExpectedError, - is_note: bool, - err_idx: std.zig.ErrorBundle.MessageIndex, - ) Allocator.Error!void { - const io = eval.io; - const err = eb.getErrorMessage(err_idx); - if (err.count != 1) @panic("TODO error message with count>1"); - const msg = eb.nullTerminatedString(err.msg); - const matches = matches: { - if (expected.is_note != is_note) break :matches false; - if (!std.mem.eql(u8, expected.msg, msg)) break :matches false; - if (err.src_loc == .none) { - break :matches expected.src == null; - } - const expected_src = expected.src orelse break :matches false; - const src = eb.getSourceLocation(err.src_loc); - const raw_filename = eb.nullTerminatedString(src.src_path); - // We need to replace backslashes for consistency between platforms. - const filename = name: { - if (std.mem.findScalar(u8, raw_filename, '\\') == null) break :name raw_filename; - const copied = try eval.arena.dupe(u8, raw_filename); - std.mem.replaceScalar(u8, copied, '\\', '/'); - break :name copied; - }; - if (!std.mem.eql(u8, expected_src.filename, filename)) break :matches false; - if (expected_src.line != src.line + 1) break :matches false; - if (expected_src.column != src.column + 1) break :matches false; - break :matches true; - }; - if (!matches) { - eb.renderToStderr(io, .{}, .auto) catch {}; - eval.fatal("compile error did not match expected error", .{}); - } - } - - fn checkSuccessOutcome(eval: *Eval, update: Case.Update, opt_emitted_path: ?[]const u8, prog_node: std.Progress.Node) !void { - switch (update.outcome) { - .unknown => return, - .compile_errors => eval.fatal("expected compile errors but compilation incorrectly succeeded", .{}), - .stdout, .exit_code => {}, - } - const emitted_path = opt_emitted_path orelse { - std.debug.assert(eval.backend == .sema); - return; - }; - const io = eval.io; - - const binary_path = switch (eval.backend) { - .sema => unreachable, - .selfhosted, .llvm => emitted_path, - .cbe => bin: { - const rand_int = rand64(io); - const out_bin_name = "./out_" ++ std.fmt.hex(rand_int); - try eval.buildCOutput(emitted_path, out_bin_name, prog_node); - break :bin out_bin_name; - }, - }; - - var argv_buf: [2][]const u8 = undefined; - const argv: []const []const u8, const is_foreign: bool = sw: switch (std.zig.system.getExternalExecutor( - io, - &eval.target, - .{ - .link_libc = eval.backend == .cbe, - .host_cpu_arch = eval.host.cpu.arch, - .host_os_tag = eval.host.os.tag, - }, - )) { - .bad_dl, .bad_os_or_cpu => { - // This binary cannot be executed on this host. - if (!eval.quiet) { - std.log.warn("skipping execution because host '{s}' cannot execute binaries for foreign target '{s}'", .{ - try eval.host.zigTriple(eval.arena), - try eval.target.zigTriple(eval.arena), - }); - } - return; - }, - .native, .rosetta => argv: { - argv_buf[0] = binary_path; - break :argv .{ argv_buf[0..1], false }; - }, - .qemu => |executor_cmd| argv: { - if (eval.enable_qemu) { - argv_buf[0] = executor_cmd; - argv_buf[1] = binary_path; - break :argv .{ argv_buf[0..2], true }; - } else { - continue :sw .bad_os_or_cpu; - } - }, - .wine => |executor_cmd| argv: { - if (eval.enable_wine) { - argv_buf[0] = executor_cmd; - argv_buf[1] = binary_path; - break :argv .{ argv_buf[0..2], true }; - } else { - continue :sw .bad_os_or_cpu; - } - }, - .wasmtime => |executor_cmd| argv: { - if (eval.enable_wasmtime) { - argv_buf[0] = executor_cmd; - argv_buf[1] = binary_path; - break :argv .{ argv_buf[0..2], true }; - } else { - continue :sw .bad_os_or_cpu; - } - }, - .darling => |executor_cmd| argv: { - if (eval.enable_darling) { - argv_buf[0] = executor_cmd; - argv_buf[1] = binary_path; - break :argv .{ argv_buf[0..2], true }; - } else { - continue :sw .bad_os_or_cpu; - } - }, - }; - - const run_prog_node = prog_node.start("run generated executable", 0); - defer run_prog_node.end(); - - const result = std.process.run(eval.arena, io, .{ - .argv = argv, - .cwd = .{ .path = eval.tmp_dir_path }, - }) catch |err| { - if (is_foreign) { - // Chances are the foreign executor isn't available. Skip this evaluation. - if (!eval.quiet) { - std.log.warn("skipping execution of '{s}' via executor for foreign target '{s}': {t}", .{ - binary_path, - try eval.target.zigTriple(eval.arena), - err, - }); - } - return; - } - eval.fatal("failed to run the generated executable '{s}': {t}", .{ binary_path, err }); - }; - - // Some executors (looking at you, Wine) like throwing some stderr in, just for fun. - // Therefore, we'll ignore stderr when using a foreign executor. - if (!is_foreign and result.stderr.len != 0) { - std.log.err("generated executable '{s}' had unexpected stderr:\n{s}", .{ - binary_path, result.stderr, - }); - } - - switch (result.term) { - .exited => |code| switch (update.outcome) { - .unknown, .compile_errors => unreachable, - .stdout => |expected_stdout| { - if (code != 0) { - eval.fatal("generated executable '{s}' failed with code {d}", .{ binary_path, code }); - } - try std.testing.expectEqualStrings(expected_stdout, result.stdout); - }, - .exit_code => |expected_code| try std.testing.expectEqual(expected_code, code), - }, - .signal => |sig| { - eval.fatal("generated executable '{s}' terminated with signal {t}", .{ binary_path, sig }); - }, - .stopped => |sig| { - eval.fatal("generated executable '{s}' stopped with signal {t}", .{ binary_path, sig }); - }, - .unknown => { - eval.fatal("generated executable '{s}' terminated unexpectedly", .{binary_path}); - }, - } - - if (!is_foreign and result.stderr.len != 0) std.process.exit(1); - } - - fn requestUpdate(eval: *Eval) !void { - const io = eval.io; - - var w = eval.child.stdin.?.writerStreaming(io, &.{}); - var client: std.zig.Client = .{ - .in = undefined, - .out = &w.interface, - }; - client.serveBodylessMessage(.update) catch |err| switch (err) { - error.WriteFailed => return w.err.?, - }; - } - - fn end(eval: *Eval, mr: *Io.File.MultiReader) !void { - requestExit(eval.child, eval); - - var client: std.zig.Client = .{ - .in = mr.reader(0), - .out = undefined, - }; - - while (true) { - const header = client.receiveMessageWithMultiReader(mr, .none) catch |err| switch (err) { - error.Timeout => unreachable, - error.EndOfStream => |e| { - if (client.in.bufferedLen() == 0) break; - return e; - }, - else => |e| return e, - }; - try client.in.discardAll(header.bytes_len); - } - - const stderr = mr.reader(1).buffered(); - if (stderr.len > 0) eval.fatal("unexpected stderr:\n{s}", .{stderr}); - } - - fn buildCOutput(eval: *Eval, c_path: []const u8, out_path: []const u8, prog_node: std.Progress.Node) !void { - std.debug.assert(eval.cc_child_args.items.len > 0); - - const child_prog_node = prog_node.start("build cbe output", 0); - defer child_prog_node.end(); - - try eval.cc_child_args.append(eval.arena, try std.fmt.allocPrint(eval.arena, "-femit-bin={s}", .{out_path})); - try eval.cc_child_args.append(eval.arena, c_path); - defer eval.cc_child_args.items.len -= 2; - - if (eval.allow_compiler_stderr) { - const cmd: std.zig.SubprocessCommand = .{ - .argv = eval.cc_child_args.items, - .cwd = eval.tmp_dir_path, - }; - std.log.scoped(.spawn).info("{f}", .{cmd}); - } - - const result = std.process.run(eval.arena, eval.io, .{ - .argv = eval.cc_child_args.items, - .cwd = .{ .path = eval.tmp_dir_path }, - .progress_node = child_prog_node, - }) catch |err| { - eval.fatal("failed to spawn zig cc for '{s}': {t}", .{ c_path, err }); - }; - - if (result.term == .exited and result.term.exited == 0) return; - - if (result.stderr.len != 0) { - std.log.err("zig cc stderr:\n{s}", .{result.stderr}); - } - switch (result.term) { - .exited => |code| eval.fatal("zig cc for '{s}' failed with code {d}", .{ c_path, code }), - .signal => |sig| eval.fatal("zig cc for '{s}' terminated unexpectedly with signal {t}", .{ c_path, sig }), - .stopped => |sig| eval.fatal("zig cc for '{s}' stopped unexpectedly with signal {t}", .{ c_path, sig }), - .unknown => eval.fatal("zig cc for '{s}' terminated unexpectedly", .{c_path}), - } - } - - fn fatal(eval: *Eval, comptime fmt: []const u8, args: anytype) noreturn { - const io = eval.io; - eval.tmp_dir.close(io); - if (!eval.preserve_tmp_on_fatal) { - // Kill the child since it holds an open handle to its CWD which is the tmp dir path - eval.child.kill(io); - Dir.cwd().deleteTree(io, eval.tmp_dir_path) catch |err| { - std.log.warn("failed to delete tree '{s}': {t}", .{ eval.tmp_dir_path, err }); - }; - } - std.process.fatal(fmt, args); - } -}; - -const Backend = enum { - /// Run semantic analysis only. Runtime output will not be tested, but we still verify - /// that compilation succeeds. Corresponds to `-fno-emit-bin`. - sema, - /// Use the self-hosted code generation backend for this target. - /// Corresponds to `-fno-llvm -fno-lld`. - selfhosted, - /// Use the LLVM backend. - /// Corresponds to `-fllvm -flld`. - llvm, - /// Use the C backend. The output is compiled with `zig cc`. - /// Corresponds to `-ofmt=c`. - cbe, -}; - -const Case = struct { - updates: []Update, - root_source_file: []const u8, - skip_targets: []const SkipTarget, - modules: []const Module, - - const SkipTarget = struct { - query: std.Target.Query, - backend: Backend, - }; - - const Module = struct { - name: []const u8, - file: []const u8, - }; - - const Update = struct { - name: []const u8, - outcome: Outcome, - changes: []const FullContents = &.{}, - deletes: []const []const u8 = &.{}, - }; - - const FullContents = struct { - name: []const u8, - bytes: []const u8, - }; - - const Outcome = union(enum) { - unknown, - compile_errors: struct { - errors: []const ExpectedError, - compile_log_output: []const u8, - }, - stdout: []const u8, - exit_code: u8, - }; - - const ExpectedError = struct { - is_note: bool, - msg: []const u8, - src: ?struct { - filename: []const u8, - line: u32, - column: u32, - }, - }; - - fn parse(arena: Allocator, bytes: []const u8) !Case { - const fatal = std.process.fatal; - - var skip_targets: std.ArrayList(SkipTarget) = .empty; - var modules: std.ArrayList(Module) = .empty; - var updates: std.ArrayList(Update) = .empty; - var changes: std.ArrayList(FullContents) = .empty; - var deletes: std.ArrayList([]const u8) = .empty; - var it = std.mem.splitScalar(u8, bytes, '\n'); - var line_n: usize = 1; - var root_source_file: ?[]const u8 = null; - while (it.next()) |line| : (line_n += 1) { - if (std.mem.startsWith(u8, line, "#")) { - var line_it = std.mem.splitScalar(u8, line, '='); - const key = line_it.first()[1..]; - const val = std.mem.trimEnd(u8, line_it.rest(), "\r"); // windows moment - if (val.len == 0) { - fatal("line {d}: missing value", .{line_n}); - } else if (std.mem.eql(u8, key, "skip_target")) { - const query, const backend = parseTargetQueryAndBackend( - val, - try std.fmt.allocPrint(arena, "line {d}: ", .{line_n}), - ); - try skip_targets.append(arena, .{ - .query = query, - .backend = backend, - }); - } else if (std.mem.eql(u8, key, "module")) { - const split_idx = std.mem.findScalar(u8, val, '=') orelse - fatal("line {d}: module does not include file", .{line_n}); - const name = val[0..split_idx]; - const file = val[split_idx + 1 ..]; - try modules.append(arena, .{ - .name = name, - .file = file, - }); - } else if (std.mem.eql(u8, key, "update")) { - if (updates.items.len > 0) { - const last_update = &updates.items[updates.items.len - 1]; - last_update.changes = try changes.toOwnedSlice(arena); - last_update.deletes = try deletes.toOwnedSlice(arena); - } - try updates.append(arena, .{ - .name = val, - .outcome = .unknown, - }); - } else if (std.mem.eql(u8, key, "file")) { - if (updates.items.len == 0) fatal("line {d}: file directive before update", .{line_n}); - - if (root_source_file == null) - root_source_file = val; - - // Because Windows is so excellent, we need to convert CRLF to LF, so - // can't just slice into the input here. How delightful! - var src: std.ArrayList(u8) = .empty; - - while (true) { - const next_line_raw = it.peek() orelse fatal("line {d}: unexpected EOF", .{line_n}); - const next_line = std.mem.trimEnd(u8, next_line_raw, "\r"); - if (std.mem.startsWith(u8, next_line, "#")) break; - - _ = it.next(); - line_n += 1; - - try src.ensureUnusedCapacity(arena, next_line.len + 1); - src.appendSliceAssumeCapacity(next_line); - src.appendAssumeCapacity('\n'); - } - - try changes.append(arena, .{ - .name = val, - .bytes = src.items, - }); - } else if (std.mem.eql(u8, key, "rm_file")) { - if (updates.items.len == 0) fatal("line {d}: rm_file directive before update", .{line_n}); - try deletes.append(arena, val); - } else if (std.mem.eql(u8, key, "expect_stdout")) { - if (updates.items.len == 0) fatal("line {d}: expect directive before update", .{line_n}); - const last_update = &updates.items[updates.items.len - 1]; - if (last_update.outcome != .unknown) fatal("line {d}: conflicting expect directive", .{line_n}); - last_update.outcome = .{ - .stdout = std.zig.string_literal.parseAlloc(arena, val) catch |err| { - fatal("line {d}: bad string literal: {t}", .{ line_n, err }); - }, - }; - } else if (std.mem.eql(u8, key, "expect_error")) { - if (updates.items.len == 0) fatal("line {d}: expect directive before update", .{line_n}); - const last_update = &updates.items[updates.items.len - 1]; - if (last_update.outcome != .unknown) fatal("line {d}: conflicting expect directive", .{line_n}); - - var errors: std.ArrayList(ExpectedError) = .empty; - try errors.append(arena, parseExpectedError(val, line_n)); - while (true) { - const next_line = it.peek() orelse break; - if (!std.mem.startsWith(u8, next_line, "#")) break; - var new_line_it = std.mem.splitScalar(u8, next_line, '='); - const new_key = new_line_it.first()[1..]; - const new_val = std.mem.trimEnd(u8, new_line_it.rest(), "\r"); - if (new_val.len == 0) break; - if (!std.mem.eql(u8, new_key, "expect_error")) break; - - _ = it.next(); - line_n += 1; - try errors.append(arena, parseExpectedError(new_val, line_n)); - } - - var compile_log_output: std.ArrayList(u8) = .empty; - while (true) { - const next_line = it.peek() orelse break; - if (!std.mem.startsWith(u8, next_line, "#")) break; - var new_line_it = std.mem.splitScalar(u8, next_line, '='); - const new_key = new_line_it.first()[1..]; - const new_val = std.mem.trimEnd(u8, new_line_it.rest(), "\r"); - if (new_val.len == 0) break; - if (!std.mem.eql(u8, new_key, "expect_compile_log")) break; - - _ = it.next(); - line_n += 1; - try compile_log_output.ensureUnusedCapacity(arena, new_val.len + 1); - compile_log_output.appendSliceAssumeCapacity(new_val); - compile_log_output.appendAssumeCapacity('\n'); - } - - last_update.outcome = .{ .compile_errors = .{ - .errors = errors.items, - .compile_log_output = compile_log_output.items, - } }; - } else if (std.mem.eql(u8, key, "expect_compile_log")) { - fatal("line {d}: 'expect_compile_log' must immediately follow 'expect_error'", .{line_n}); - } else { - fatal("line {d}: unrecognized key '{s}'", .{ line_n, key }); - } - } - } - - if (changes.items.len > 0) { - const last_update = &updates.items[updates.items.len - 1]; - last_update.changes = changes.items; // arena so no need for toOwnedSlice - last_update.deletes = deletes.items; - } - - return .{ - .updates = updates.items, - .root_source_file = root_source_file orelse fatal("missing root source file", .{}), - .skip_targets = skip_targets.items, // arena so no need for toOwnedSlice - .modules = modules.items, - }; - } -}; - -fn requestExit(child: *std.process.Child, eval: *Eval) void { - if (child.stdin == null) return; - const io = eval.io; - - var w = eval.child.stdin.?.writerStreaming(io, &.{}); - var client: std.zig.Client = .{ - .in = undefined, - .out = &w.interface, - }; - client.serveBodylessMessage(.exit) catch |err| switch (err) { - error.WriteFailed => switch (w.err.?) { - error.BrokenPipe => {}, - else => |e| eval.fatal("failed to send exit: {t}", .{e}), - }, - }; - - // Send EOF to stdin. - child.stdin.?.close(io); - child.stdin = null; -} - -fn waitChild(child: *std.process.Child, eval: *Eval) void { - const io = eval.io; - requestExit(child, eval); - const term = child.wait(io) catch |err| eval.fatal("child process failed: {t}", .{err}); - switch (term) { - .exited => |code| if (code != 0) eval.fatal("compiler failed with code {d}", .{code}), - .signal => |sig| eval.fatal("compiler terminated with signal {t}", .{sig}), - .stopped => |sig| eval.fatal("compiler stopped unexpectedly with signal {t}", .{sig}), - .unknown => eval.fatal("compiler terminated unexpectedly", .{}), - } -} - -fn parseExpectedError(str: []const u8, l: usize) Case.ExpectedError { - // #expect_error=foo.zig:1:2: error: the error message - // #expect_error=foo.zig:1:2: note: and a note - - const fatal = std.process.fatal; - - var it = std.mem.splitScalar(u8, str, ':'); - const filename = it.first(); - const line_str, const column_str = if (filename.len > 0) .{ - it.next() orelse fatal("line {d}: incomplete error specification", .{l}), - it.next() orelse fatal("line {d}: incomplete error specification", .{l}), - } else .{ undefined, undefined }; - const error_or_note_str = std.mem.trim( - u8, - it.next() orelse fatal("line {d}: incomplete error specification", .{l}), - " ", - ); - - const is_note = if (std.mem.eql(u8, error_or_note_str, "error")) - false - else if (std.mem.eql(u8, error_or_note_str, "note")) - true - else - fatal("line {d}: expeted 'error' or 'note', found '{s}'", .{ l, error_or_note_str }); - - const message = std.mem.trim(u8, it.rest(), " "); - if (message.len == 0) fatal("line {d}: empty error message", .{l}); - - return .{ - .is_note = is_note, - .msg = message, - .src = if (filename.len == 0) null else .{ - .filename = filename, - .line = std.fmt.parseInt(u32, line_str, 10) catch - fatal("line {d}: invalid line number '{s}'", .{ l, line_str }), - .column = std.fmt.parseInt(u32, column_str, 10) catch - fatal("line {d}: invalid column number '{s}'", .{ l, column_str }), - }, - }; -} - -fn rand64(io: Io) u64 { - var x: u64 = undefined; - io.random(@ptrCast(&x)); - return x; -} - -/// Calls `std.process.fatal` on error. The error messages are prefixed with `err_prefix`. -fn parseTargetQueryAndBackend(input_str: []const u8, err_prefix: []const u8) struct { std.Target.Query, Backend } { - const fatal = std.process.fatal; - - const split_idx = std.mem.findScalarLast(u8, input_str, '-') orelse - fatal("{s}target does not include backend", .{err_prefix}); - - const query = input_str[0..split_idx]; - - const backend_str = input_str[split_idx + 1 ..]; - const backend: Backend = std.meta.stringToEnum(Backend, backend_str) orelse - fatal("{s}invalid backend '{s}'", .{ err_prefix, backend_str }); - - const parsed_query = std.Build.parseTargetQuery(.{ - .arch_os_abi = query, - .object_format = switch (backend) { - .sema, .selfhosted, .llvm => null, - .cbe => "c", - }, - }) catch fatal("{s}invalid target query '{s}'", .{ err_prefix, query }); - - return .{ parsed_query, backend }; -} - -fn badUsage(comptime fmt: []const u8, args: anytype) noreturn { - std.log.err(fmt ++ "\n{s}", args ++ .{usage}); - std.process.exit(1); -} -- 2.54.0