authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-19 06:52:35-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-26 19:08:50-04:00
logec261c5e8d569a7bf90a51638d41de6053f98e1a
tree7688c129c251adce9d1cb547a697fe9d72a7a3ce
parent4e4e8902e5bec12befd191b6ce412d60ced819f4

test-incremental: convert tests to new format


86 files changed, 1900 insertions(+), 2470 deletions(-)

build.zig+1-18
...@@ -125,7 +125,6 @@ pub fn build(b: *std.Build) !void {...@@ -125,7 +125,6 @@ pub fn build(b: *std.Build) !void {
125 const skip_darwin = b.option(bool, "skip-darwin", "Main test suite skips targets with darwin OSs") orelse false;125 const skip_darwin = b.option(bool, "skip-darwin", "Main test suite skips targets with darwin OSs") orelse false;
126 const skip_linux = b.option(bool, "skip-linux", "Main test suite skips targets with linux OS") orelse false;126 const skip_linux = b.option(bool, "skip-linux", "Main test suite skips targets with linux OS") orelse false;
127 const skip_llvm = b.option(bool, "skip-llvm", "Main test suite skips targets that use LLVM backend") orelse false;127 const skip_llvm = b.option(bool, "skip-llvm", "Main test suite skips targets that use LLVM backend") orelse false;
128 const skip_test_incremental = b.option(bool, "skip-test-incremental", "Main test step omits dependency on test-incremental step") orelse false;
129128
130 const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;129 const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;
131130
...@@ -781,22 +780,6 @@ pub fn build(b: *std.Build) !void {...@@ -781,22 +780,6 @@ pub fn build(b: *std.Build) !void {
781 test_step.dependOn(check_oracle_step);780 test_step.dependOn(check_oracle_step);
782 }781 }
783782
784 const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases");
785 try tests.addIncrementalTests(b, test_incremental_step, .{
786 .test_filters = test_filters,
787 .test_target_filters = test_target_filters,
788 .skip_non_native = skip_non_native,
789 .skip_wasm = skip_wasm,
790 .skip_freebsd = skip_freebsd,
791 .skip_netbsd = skip_netbsd,
792 .skip_openbsd = skip_openbsd,
793 .skip_windows = skip_windows,
794 .skip_darwin = skip_darwin,
795 .skip_linux = skip_linux,
796 .skip_llvm = skip_llvm,
797 });
798 if (!skip_test_incremental) test_step.dependOn(test_incremental_step);
799
800 if (tests.addLibcTestNszTests(b, .{783 if (tests.addLibcTestNszTests(b, .{
801 .optimize_modes = optimize_modes,784 .optimize_modes = optimize_modes,
802 .test_filters = test_filters,785 .test_filters = test_filters,
...@@ -812,7 +795,7 @@ pub fn build(b: *std.Build) !void {...@@ -812,7 +795,7 @@ pub fn build(b: *std.Build) !void {
812 .target = b.graph.host,795 .target = b.graph.host,
813 }),796 }),
814 });797 });
815 test_step.dependOn(try tests.addNewIncrementalTests(b, runner, .{798 test_step.dependOn(try tests.addIncrementalTests(b, runner, .{
816 .test_filters = test_filters,799 .test_filters = test_filters,
817 .test_target_filters = test_target_filters,800 .test_target_filters = test_target_filters,
818 .skip_non_native = skip_non_native,801 .skip_non_native = skip_non_native,
test/incremental/add_decl+45-18
...@@ -1,15 +1,21 @@...@@ -1,15 +1,21 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4pub fn main() !void {7pub fn main() !void {
5 try std.Io.File.stdout().writeStreamingAll(io, foo);8 try std.Io.File.stdout().writeStreamingAll(io, foo);
6}9}
7const foo = "good morning\n";10const foo = "good morning\n";
8const io = std.Io.Threaded.global_single_threaded.io();11const io = std.Io.Threaded.global_single_threaded.io();
9#expect_stdout="good morning\n"12#}
13#update
14#check stdout {
15good morning
16#}
1017
11#update=add new declaration18#write main.zig {
12#file=main.zig
13const std = @import("std");19const std = @import("std");
14pub fn main() !void {20pub fn main() !void {
15 try std.Io.File.stdout().writeStreamingAll(io, foo);21 try std.Io.File.stdout().writeStreamingAll(io, foo);
...@@ -17,10 +23,14 @@ pub fn main() !void {...@@ -17,10 +23,14 @@ pub fn main() !void {
17const foo = "good morning\n";23const foo = "good morning\n";
18const bar = "good evening\n";24const bar = "good evening\n";
19const io = std.Io.Threaded.global_single_threaded.io();25const io = std.Io.Threaded.global_single_threaded.io();
20#expect_stdout="good morning\n"26#}
27#update {
28add new declaration#}
29#check stdout {
30good morning
31#}
2132
22#update=reference new declaration33#write main.zig {
23#file=main.zig
24const std = @import("std");34const std = @import("std");
25pub fn main() !void {35pub fn main() !void {
26 try std.Io.File.stdout().writeStreamingAll(io, bar);36 try std.Io.File.stdout().writeStreamingAll(io, bar);
...@@ -28,10 +38,14 @@ pub fn main() !void {...@@ -28,10 +38,14 @@ pub fn main() !void {
28const foo = "good morning\n";38const foo = "good morning\n";
29const bar = "good evening\n";39const bar = "good evening\n";
30const io = std.Io.Threaded.global_single_threaded.io();40const io = std.Io.Threaded.global_single_threaded.io();
31#expect_stdout="good evening\n"41#}
42#update {
43reference new declaration#}
44#check stdout {
45good evening
46#}
3247
33#update=reference missing declaration48#write main.zig {
34#file=main.zig
35const std = @import("std");49const std = @import("std");
36pub fn main() !void {50pub fn main() !void {
37 try std.Io.File.stdout().writeStreamingAll(io, qux);51 try std.Io.File.stdout().writeStreamingAll(io, qux);
...@@ -39,10 +53,14 @@ pub fn main() !void {...@@ -39,10 +53,14 @@ pub fn main() !void {
39const foo = "good morning\n";53const foo = "good morning\n";
40const bar = "good evening\n";54const bar = "good evening\n";
41const io = std.Io.Threaded.global_single_threaded.io();55const io = std.Io.Threaded.global_single_threaded.io();
42#expect_error=main.zig:3:52: error: use of undeclared identifier 'qux'56#}
57#update {
58reference missing declaration#}
59#check errors {
60main.zig:3:52: error: use of undeclared identifier 'qux'
61#}
4362
44#update=add missing declaration63#write main.zig {
45#file=main.zig
46const std = @import("std");64const std = @import("std");
47pub fn main() !void {65pub fn main() !void {
48 try std.Io.File.stdout().writeStreamingAll(io, qux);66 try std.Io.File.stdout().writeStreamingAll(io, qux);
...@@ -51,14 +69,23 @@ const foo = "good morning\n";...@@ -51,14 +69,23 @@ const foo = "good morning\n";
51const bar = "good evening\n";69const bar = "good evening\n";
52const qux = "good night\n";70const qux = "good night\n";
53const io = std.Io.Threaded.global_single_threaded.io();71const io = std.Io.Threaded.global_single_threaded.io();
54#expect_stdout="good night\n"72#}
73#update {
74add missing declaration#}
75#check stdout {
76good night
77#}
5578
56#update=remove unused declarations79#write main.zig {
57#file=main.zig
58const std = @import("std");80const std = @import("std");
59pub fn main() !void {81pub fn main() !void {
60 try std.Io.File.stdout().writeStreamingAll(io, qux);82 try std.Io.File.stdout().writeStreamingAll(io, qux);
61}83}
62const qux = "good night\n";84const qux = "good night\n";
63const io = std.Io.Threaded.global_single_threaded.io();85const io = std.Io.Threaded.global_single_threaded.io();
64#expect_stdout="good night\n"86#}
87#update {
88remove unused declarations#}
89#check stdout {
90good night
91#}
test/incremental/add_decl_namespaced+46-19
...@@ -1,15 +1,21 @@...@@ -1,15 +1,21 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4pub fn main() !void {7pub fn main() !void {
5 try std.Io.File.stdout().writeStreamingAll(io, @This().foo);8 try std.Io.File.stdout().writeStreamingAll(io, @This().foo);
6}9}
7const foo = "good morning\n";10const foo = "good morning\n";
8const io = std.Io.Threaded.global_single_threaded.io();11const io = std.Io.Threaded.global_single_threaded.io();
9#expect_stdout="good morning\n"12#}
13#update
14#check stdout {
15good morning
16#}
1017
11#update=add new declaration18#write main.zig {
12#file=main.zig
13const std = @import("std");19const std = @import("std");
14pub fn main() !void {20pub fn main() !void {
15 try std.Io.File.stdout().writeStreamingAll(io, @This().foo);21 try std.Io.File.stdout().writeStreamingAll(io, @This().foo);
...@@ -17,10 +23,14 @@ pub fn main() !void {...@@ -17,10 +23,14 @@ pub fn main() !void {
17const foo = "good morning\n";23const foo = "good morning\n";
18const bar = "good evening\n";24const bar = "good evening\n";
19const io = std.Io.Threaded.global_single_threaded.io();25const io = std.Io.Threaded.global_single_threaded.io();
20#expect_stdout="good morning\n"26#}
27#update {
28add new declaration#}
29#check stdout {
30good morning
31#}
2132
22#update=reference new declaration33#write main.zig {
23#file=main.zig
24const std = @import("std");34const std = @import("std");
25pub fn main() !void {35pub fn main() !void {
26 try std.Io.File.stdout().writeStreamingAll(io, @This().bar);36 try std.Io.File.stdout().writeStreamingAll(io, @This().bar);
...@@ -28,10 +38,14 @@ pub fn main() !void {...@@ -28,10 +38,14 @@ pub fn main() !void {
28const foo = "good morning\n";38const foo = "good morning\n";
29const bar = "good evening\n";39const bar = "good evening\n";
30const io = std.Io.Threaded.global_single_threaded.io();40const io = std.Io.Threaded.global_single_threaded.io();
31#expect_stdout="good evening\n"41#}
42#update {
43reference new declaration#}
44#check stdout {
45good evening
46#}
3247
33#update=reference missing declaration48#write main.zig {
34#file=main.zig
35const std = @import("std");49const std = @import("std");
36pub fn main() !void {50pub fn main() !void {
37 try std.Io.File.stdout().writeStreamingAll(io, @This().qux);51 try std.Io.File.stdout().writeStreamingAll(io, @This().qux);
...@@ -39,11 +53,15 @@ pub fn main() !void {...@@ -39,11 +53,15 @@ pub fn main() !void {
39const foo = "good morning\n";53const foo = "good morning\n";
40const bar = "good evening\n";54const bar = "good evening\n";
41const io = std.Io.Threaded.global_single_threaded.io();55const io = std.Io.Threaded.global_single_threaded.io();
42#expect_error=main.zig:3:59: error: root source file struct 'main' has no member named 'qux'56#}
43#expect_error=main.zig:1:1: note: struct declared here57#update {
58reference missing declaration#}
59#check errors {
60main.zig:3:59: error: root source file struct 'main' has no member named 'qux'
61main.zig:1:1: note: struct declared here
62#}
4463
45#update=add missing declaration64#write main.zig {
46#file=main.zig
47const std = @import("std");65const std = @import("std");
48pub fn main() !void {66pub fn main() !void {
49 try std.Io.File.stdout().writeStreamingAll(io, @This().qux);67 try std.Io.File.stdout().writeStreamingAll(io, @This().qux);
...@@ -52,14 +70,23 @@ const foo = "good morning\n";...@@ -52,14 +70,23 @@ const foo = "good morning\n";
52const bar = "good evening\n";70const bar = "good evening\n";
53const qux = "good night\n";71const qux = "good night\n";
54const io = std.Io.Threaded.global_single_threaded.io();72const io = std.Io.Threaded.global_single_threaded.io();
55#expect_stdout="good night\n"73#}
74#update {
75add missing declaration#}
76#check stdout {
77good night
78#}
5679
57#update=remove unused declarations80#write main.zig {
58#file=main.zig
59const std = @import("std");81const std = @import("std");
60pub fn main() !void {82pub fn main() !void {
61 try std.Io.File.stdout().writeStreamingAll(io, @This().qux);83 try std.Io.File.stdout().writeStreamingAll(io, @This().qux);
62}84}
63const qux = "good night\n";85const qux = "good night\n";
64const io = std.Io.Threaded.global_single_threaded.io();86const io = std.Io.Threaded.global_single_threaded.io();
65#expect_stdout="good night\n"87#}
88#update {
89remove unused declarations#}
90#check stdout {
91good night
92#}
test/incremental/add_field_and_nested_struct_uses_changed_decl+16-6
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3pub fn main() void {6pub fn main() void {
4 _ = @as(S, undefined);7 _ = @as(S, undefined);
5}8}
...@@ -9,9 +12,12 @@ const SomeType = u8;...@@ -9,9 +12,12 @@ const SomeType = u8;
9const S = struct {12const S = struct {
10 foo: struct { inner: SomeType },13 foo: struct { inner: SomeType },
11};14};
12#expect_stdout=""15#}
13#update=add field to outer struct, change decl used by inner struct16#update
14#file=main.zig17#check stdout {
18#}
19
20#write main.zig {
15pub fn main() void {21pub fn main() void {
16 _ = @as(S, undefined);22 _ = @as(S, undefined);
17}23}
...@@ -22,4 +28,8 @@ const S = struct {...@@ -22,4 +28,8 @@ const S = struct {
22 foo: struct { inner: SomeType },28 foo: struct { inner: SomeType },
23 bar: u32,29 bar: u32,
24};30};
25#expect_stdout=""31#}
32#update {
33add field to outer struct, change decl used by inner struct#}
34#check stdout {
35#}
test/incremental/add_remove_struct_fields deleted-93
...@@ -1,93 +0,0 @@
1#update=initial version
2#file=main.zig
3const S = struct { x: u8 };
4pub fn main(init: std.process.Init) !void {
5 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
6 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
7 error.WriteFailed => return stdout_writer.err.?,
8 };
9 printOneField(&stdout_writer.interface) catch |err| switch (err) {
10 error.WriteFailed => return stdout_writer.err.?,
11 };
12}
13fn printFieldCount(w: *Writer) Writer.Error!void {
14 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
15}
16fn printOneField(w: *Writer) Writer.Error!void {
17 const val: S = .{ .x = 100 };
18 try w.print("{d}\n", .{val.x});
19}
20const std = @import("std");
21const Writer = std.Io.Writer;
22#expect_stdout="1 100\n"
23
24#update=add a field
25#file=main.zig
26const S = struct { x: u8, y: u16 = 200 };
27pub fn main(init: std.process.Init) !void {
28 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
29 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
30 error.WriteFailed => return stdout_writer.err.?,
31 };
32 printOneField(&stdout_writer.interface) catch |err| switch (err) {
33 error.WriteFailed => return stdout_writer.err.?,
34 };
35}
36fn printFieldCount(w: *Writer) Writer.Error!void {
37 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
38}
39fn printOneField(w: *Writer) Writer.Error!void {
40 const val: S = .{ .x = 100 };
41 try w.print("{d}\n", .{val.x});
42}
43const std = @import("std");
44const Writer = std.Io.Writer;
45#expect_stdout="2 100\n"
46
47#update=remove all fields
48#file=main.zig
49const S = struct {};
50pub fn main(init: std.process.Init) !void {
51 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
52 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
53 error.WriteFailed => return stdout_writer.err.?,
54 };
55 printOneField(&stdout_writer.interface) catch |err| switch (err) {
56 error.WriteFailed => return stdout_writer.err.?,
57 };
58}
59fn printFieldCount(w: *Writer) Writer.Error!void {
60 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
61}
62fn printOneField(w: *Writer) Writer.Error!void {
63 const val: S = .{ .x = 100 };
64 try w.print("{d}\n", .{val.x});
65}
66const std = @import("std");
67const Writer = std.Io.Writer;
68#expect_error=main.zig:15:24: error: no field named 'x' in struct 'main.S'
69#expect_error=main.zig:1:11: note: struct declared here
70
71#update=remove reference to non-existent field
72#file=main.zig
73const S = struct {};
74pub fn main(init: std.process.Init) !void {
75 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
76 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
77 error.WriteFailed => return stdout_writer.err.?,
78 };
79 printOneField(&stdout_writer.interface) catch |err| switch (err) {
80 error.WriteFailed => return stdout_writer.err.?,
81 };
82}
83fn printFieldCount(w: *Writer) Writer.Error!void {
84 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
85}
86fn printOneField(w: *Writer) Writer.Error!void {
87 //const val: S = .{ .x = 100 };
88 //try w.print("{d}\n", .{val.x});
89 try w.writeAll("<no fields>\n");
90}
91const std = @import("std");
92const Writer = std.Io.Writer;
93#expect_stdout="0 <no fields>\n"
test/incremental/add_remove_struct_fields/0/main.zig created+19
...@@ -0,0 +1,19 @@
1const S = struct { x: u8 };
2pub fn main(init: std.process.Init) !void {
3 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
4 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
5 error.WriteFailed => return stdout_writer.err.?,
6 };
7 printOneField(&stdout_writer.interface) catch |err| switch (err) {
8 error.WriteFailed => return stdout_writer.err.?,
9 };
10}
11fn printFieldCount(w: *Writer) Writer.Error!void {
12 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
13}
14fn printOneField(w: *Writer) Writer.Error!void {
15 const val: S = .{ .x = 100 };
16 try w.print("{d}\n", .{val.x});
17}
18const std = @import("std");
19const Writer = std.Io.Writer;
test/incremental/add_remove_struct_fields/1/main.zig created+19
...@@ -0,0 +1,19 @@
1const S = struct { x: u8, y: u16 = 200 };
2pub fn main(init: std.process.Init) !void {
3 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
4 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
5 error.WriteFailed => return stdout_writer.err.?,
6 };
7 printOneField(&stdout_writer.interface) catch |err| switch (err) {
8 error.WriteFailed => return stdout_writer.err.?,
9 };
10}
11fn printFieldCount(w: *Writer) Writer.Error!void {
12 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
13}
14fn printOneField(w: *Writer) Writer.Error!void {
15 const val: S = .{ .x = 100 };
16 try w.print("{d}\n", .{val.x});
17}
18const std = @import("std");
19const Writer = std.Io.Writer;
test/incremental/add_remove_struct_fields/2/main.zig created+19
...@@ -0,0 +1,19 @@
1const S = struct {};
2pub fn main(init: std.process.Init) !void {
3 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
4 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
5 error.WriteFailed => return stdout_writer.err.?,
6 };
7 printOneField(&stdout_writer.interface) catch |err| switch (err) {
8 error.WriteFailed => return stdout_writer.err.?,
9 };
10}
11fn printFieldCount(w: *Writer) Writer.Error!void {
12 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
13}
14fn printOneField(w: *Writer) Writer.Error!void {
15 const val: S = .{ .x = 100 };
16 try w.print("{d}\n", .{val.x});
17}
18const std = @import("std");
19const Writer = std.Io.Writer;
test/incremental/add_remove_struct_fields/3/main.zig created+20
...@@ -0,0 +1,20 @@
1const S = struct {};
2pub fn main(init: std.process.Init) !void {
3 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
4 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
5 error.WriteFailed => return stdout_writer.err.?,
6 };
7 printOneField(&stdout_writer.interface) catch |err| switch (err) {
8 error.WriteFailed => return stdout_writer.err.?,
9 };
10}
11fn printFieldCount(w: *Writer) Writer.Error!void {
12 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
13}
14fn printOneField(w: *Writer) Writer.Error!void {
15 //const val: S = .{ .x = 100 };
16 //try w.print("{d}\n", .{val.x});
17 try w.writeAll("<no fields>\n");
18}
19const std = @import("std");
20const Writer = std.Io.Writer;
test/incremental/add_remove_struct_fields/manifest created+31
...@@ -0,0 +1,31 @@
1#exe {
2-Mroot=main.zig
3#}
4
5#write main.zig 0/main.zig
6#update
7#check stdout {
81 100
9#}
10
11#write main.zig 1/main.zig
12#update {
13add a field#}
14#check stdout {
152 100
16#}
17
18#write main.zig 2/main.zig
19#update {
20remove all fields#}
21#check errors {
22main.zig:15:24: error: no field named 'x' in struct 'main.S'
23main.zig:1:11: note: struct declared here
24#}
25
26#write main.zig 3/main.zig
27#update {
28remove reference to non-existent field#}
29#check stdout {
300 <no fields>
31#}
test/incremental/add_remove_toplevel_fields deleted-96
...@@ -1,96 +0,0 @@
1#update=initial version
2#file=main.zig
3const S = @This();
4x: u8,
5pub fn main(init: std.process.Init) !void {
6 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
7 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
8 error.WriteFailed => return stdout_writer.err.?,
9 };
10 printOneField(&stdout_writer.interface) catch |err| switch (err) {
11 error.WriteFailed => return stdout_writer.err.?,
12 };
13}
14fn printFieldCount(w: *Writer) Writer.Error!void {
15 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
16}
17fn printOneField(w: *Writer) Writer.Error!void {
18 const val: S = .{ .x = 100 };
19 try w.print("{d}\n", .{val.x});
20}
21const std = @import("std");
22const Writer = std.Io.Writer;
23#expect_stdout="1 100\n"
24
25#update=add a field
26#file=main.zig
27const S = @This();
28x: u8,
29y: u16 = 200,
30pub fn main(init: std.process.Init) !void {
31 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
32 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
33 error.WriteFailed => return stdout_writer.err.?,
34 };
35 printOneField(&stdout_writer.interface) catch |err| switch (err) {
36 error.WriteFailed => return stdout_writer.err.?,
37 };
38}
39fn printFieldCount(w: *Writer) Writer.Error!void {
40 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
41}
42fn printOneField(w: *Writer) Writer.Error!void {
43 const val: S = .{ .x = 100 };
44 try w.print("{d}\n", .{val.x});
45}
46const std = @import("std");
47const Writer = std.Io.Writer;
48#expect_stdout="2 100\n"
49
50#update=remove all fields
51#file=main.zig
52const S = @This();
53pub fn main(init: std.process.Init) !void {
54 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
55 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
56 error.WriteFailed => return stdout_writer.err.?,
57 };
58 printOneField(&stdout_writer.interface) catch |err| switch (err) {
59 error.WriteFailed => return stdout_writer.err.?,
60 };
61}
62fn printFieldCount(w: *Writer) Writer.Error!void {
63 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
64}
65fn printOneField(w: *Writer) Writer.Error!void {
66 const val: S = .{ .x = 100 };
67 try w.print("{d}\n", .{val.x});
68}
69const std = @import("std");
70const Writer = std.Io.Writer;
71#expect_error=main.zig:15:24: error: no field named 'x' in struct 'main'
72#expect_error=main.zig:1:1: note: struct declared here
73
74#update=remove reference to non-existent field
75#file=main.zig
76const S = @This();
77pub fn main(init: std.process.Init) !void {
78 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
79 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
80 error.WriteFailed => return stdout_writer.err.?,
81 };
82 printOneField(&stdout_writer.interface) catch |err| switch (err) {
83 error.WriteFailed => return stdout_writer.err.?,
84 };
85}
86fn printFieldCount(w: *Writer) Writer.Error!void {
87 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
88}
89fn printOneField(w: *Writer) Writer.Error!void {
90 //const val: S = .{ .x = 100 };
91 //try w.print("{d}\n", .{val.x});
92 try w.writeAll("<no fields>\n");
93}
94const std = @import("std");
95const Writer = std.Io.Writer;
96#expect_stdout="0 <no fields>\n"
test/incremental/add_remove_toplevel_fields/0/main.zig created+20
...@@ -0,0 +1,20 @@
1const S = @This();
2x: u8,
3pub fn main(init: std.process.Init) !void {
4 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
5 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
6 error.WriteFailed => return stdout_writer.err.?,
7 };
8 printOneField(&stdout_writer.interface) catch |err| switch (err) {
9 error.WriteFailed => return stdout_writer.err.?,
10 };
11}
12fn printFieldCount(w: *Writer) Writer.Error!void {
13 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
14}
15fn printOneField(w: *Writer) Writer.Error!void {
16 const val: S = .{ .x = 100 };
17 try w.print("{d}\n", .{val.x});
18}
19const std = @import("std");
20const Writer = std.Io.Writer;
test/incremental/add_remove_toplevel_fields/1/main.zig created+21
...@@ -0,0 +1,21 @@
1const S = @This();
2x: u8,
3y: u16 = 200,
4pub fn main(init: std.process.Init) !void {
5 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
6 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
7 error.WriteFailed => return stdout_writer.err.?,
8 };
9 printOneField(&stdout_writer.interface) catch |err| switch (err) {
10 error.WriteFailed => return stdout_writer.err.?,
11 };
12}
13fn printFieldCount(w: *Writer) Writer.Error!void {
14 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
15}
16fn printOneField(w: *Writer) Writer.Error!void {
17 const val: S = .{ .x = 100 };
18 try w.print("{d}\n", .{val.x});
19}
20const std = @import("std");
21const Writer = std.Io.Writer;
test/incremental/add_remove_toplevel_fields/2/main.zig created+19
...@@ -0,0 +1,19 @@
1const S = @This();
2pub fn main(init: std.process.Init) !void {
3 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
4 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
5 error.WriteFailed => return stdout_writer.err.?,
6 };
7 printOneField(&stdout_writer.interface) catch |err| switch (err) {
8 error.WriteFailed => return stdout_writer.err.?,
9 };
10}
11fn printFieldCount(w: *Writer) Writer.Error!void {
12 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
13}
14fn printOneField(w: *Writer) Writer.Error!void {
15 const val: S = .{ .x = 100 };
16 try w.print("{d}\n", .{val.x});
17}
18const std = @import("std");
19const Writer = std.Io.Writer;
test/incremental/add_remove_toplevel_fields/3/main.zig created+20
...@@ -0,0 +1,20 @@
1const S = @This();
2pub fn main(init: std.process.Init) !void {
3 var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{});
4 printFieldCount(&stdout_writer.interface) catch |err| switch (err) {
5 error.WriteFailed => return stdout_writer.err.?,
6 };
7 printOneField(&stdout_writer.interface) catch |err| switch (err) {
8 error.WriteFailed => return stdout_writer.err.?,
9 };
10}
11fn printFieldCount(w: *Writer) Writer.Error!void {
12 try w.print("{d} ", .{@typeInfo(S).@"struct".field_names.len});
13}
14fn printOneField(w: *Writer) Writer.Error!void {
15 //const val: S = .{ .x = 100 };
16 //try w.print("{d}\n", .{val.x});
17 try w.writeAll("<no fields>\n");
18}
19const std = @import("std");
20const Writer = std.Io.Writer;
test/incremental/add_remove_toplevel_fields/manifest created+31
...@@ -0,0 +1,31 @@
1#exe {
2-Mroot=main.zig
3#}
4
5#write main.zig 0/main.zig
6#update
7#check stdout {
81 100
9#}
10
11#write main.zig 1/main.zig
12#update {
13add a field#}
14#check stdout {
152 100
16#}
17
18#write main.zig 2/main.zig
19#update {
20remove all fields#}
21#check errors {
22main.zig:15:24: error: no field named 'x' in struct 'main'
23main.zig:1:1: note: struct declared here
24#}
25
26#write main.zig 3/main.zig
27#update {
28remove reference to non-existent field#}
29#check stdout {
300 <no fields>
31#}
test/incremental/analysis_error_and_syntax_error+44-18
...@@ -1,38 +1,64 @@...@@ -1,38 +1,64 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3pub fn main() !void {6pub fn main() !void {
4 @compileError("uh oh");7 @compileError("uh oh");
5}8}
6#expect_error=main.zig:2:5: error: uh oh9#}
10#update
11#check errors {
12main.zig:2:5: error: uh oh
13#}
714
8#update=add parse error15#write main.zig {
9#file=main.zig
10pub fn main() !void {16pub fn main() !void {
11 @compileError("uh oh");17 @compileError("uh oh");
12#expect_error=main.zig:3:1: error: expected statement, found 'EOF'18#}
19#update {
20add parse error#}
21#check errors {
22main.zig:3:1: error: expected statement, found 'EOF'
23#}
1324
14#update=fix parse error25#write main.zig {
15#file=main.zig
16pub fn main() !void {26pub fn main() !void {
17 @compileError("uh oh");27 @compileError("uh oh");
18}28}
19#expect_error=main.zig:2:5: error: uh oh29#}
30#update {
31fix parse error#}
32#check errors {
33main.zig:2:5: error: uh oh
34#}
2035
21#update=add parse error again36#write main.zig {
22#file=main.zig
23pub fn main() !void {37pub fn main() !void {
24 @compileError("uh oh");38 @compileError("uh oh");
25#expect_error=main.zig:3:1: error: expected statement, found 'EOF'39#}
40#update {
41add parse error again#}
42#check errors {
43main.zig:3:1: error: expected statement, found 'EOF'
44#}
2645
27#update=comment @compileError call46#write main.zig {
28#file=main.zig
29pub fn main() !void {47pub fn main() !void {
30 //@compileError("uh oh");48 //@compileError("uh oh");
31#expect_error=main.zig:3:1: error: expected statement, found 'EOF'49#}
50#update {
51comment @compileError call#}
52#check errors {
53main.zig:3:1: error: expected statement, found 'EOF'
54#}
3255
33#update=fix parse error again56#write main.zig {
34#file=main.zig
35pub fn main() !void {57pub fn main() !void {
36 //@compileError("uh oh");58 //@compileError("uh oh");
37}59}
38#expect_stdout=""60#}
61#update {
62fix parse error again#}
63#check stdout {
64#}
test/incremental/bad_import+28-12
...@@ -1,32 +1,48 @@...@@ -1,32 +1,48 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3pub fn main() !void {6pub fn main() !void {
4 _ = @import("foo.zig");7 _ = @import("foo.zig");
5 try std.Io.File.stdout().writeStreamingAll(io, "success\n");8 try std.Io.File.stdout().writeStreamingAll(io, "success\n");
6}9}
7const std = @import("std");10const std = @import("std");
8const io = std.Io.Threaded.global_single_threaded.io();11const io = std.Io.Threaded.global_single_threaded.io();
9#file=foo.zig12#}
13#write foo.zig {
10comptime {14comptime {
11 _ = @import("bad.zig");15 _ = @import("bad.zig");
12}16}
13#expect_error=bad.zig:1:1: error: unable to load "bad.zig": FileNotFound17#}
14#expect_error=foo.zig:2:17: note: file imported here18#update
19#check errors {
20bad.zig:1:1: error: unable to load "bad.zig": FileNotFound
21foo.zig:2:17: note: file imported here
22#}
1523
16#update=change bad import24#write foo.zig {
17#file=foo.zig
18comptime {25comptime {
19 _ = @import("this_is/not_real.zig");26 _ = @import("this_is/not_real.zig");
20}27}
21#expect_error=this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound28#}
22#expect_error=foo.zig:2:17: note: file imported here29#update {
30change bad import#}
31#check errors {
32this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound
33foo.zig:2:17: note: file imported here
34#}
2335
24#update=remove import of 'foo.zig'36#write main.zig {
25#file=main.zig
26pub fn main() !void {37pub fn main() !void {
27 //_ = @import("foo.zig");38 //_ = @import("foo.zig");
28 try std.Io.File.stdout().writeStreamingAll(io, "success\n");39 try std.Io.File.stdout().writeStreamingAll(io, "success\n");
29}40}
30const std = @import("std");41const std = @import("std");
31const io = std.Io.Threaded.global_single_threaded.io();42const io = std.Io.Threaded.global_single_threaded.io();
32#expect_stdout="success\n"43#}
44#update {
45remove import of 'foo.zig'#}
46#check stdout {
47success
48#}
test/incremental/change_bitpack_backing_int+53-30
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const Foo = packed struct(u8) { a: u4, b: i4 };6const Foo = packed struct(u8) { a: u4, b: i4 };
4const Bar = packed union(u10) { a: u10, b: i10 };7const Bar = packed union(u10) { a: u10, b: i10 };
5pub fn main() void {}8pub fn main() void {}
...@@ -11,13 +14,18 @@ comptime {...@@ -11,13 +14,18 @@ comptime {
11}14}
12const std = @import("std");15const std = @import("std");
13const io = std.Io.Threaded.global_single_threaded.io();16const io = std.Io.Threaded.global_single_threaded.io();
14#expect_error=main.zig:5:5: error: found compile log statement17#}
15#expect_error=main.zig:8:5: note: also here18#update
16#expect_compile_log=@as(type, u8)19#check errors {
17#expect_compile_log=@as(comptime_int, 10)20main.zig:5:5: error: found compile log statement
21main.zig:8:5: note: also here
22
23Compile Log Output:
24@as(type, u8)
25@as(comptime_int, 10)
26#}
1827
19#update=make backing types signed28#write main.zig {
20#file=main.zig
21const Foo = packed struct(i8) { a: u4, b: i4 };29const Foo = packed struct(i8) { a: u4, b: i4 };
22const Bar = packed union(i10) { a: u10, b: i10 };30const Bar = packed union(i10) { a: u10, b: i10 };
23pub fn main() void {}31pub fn main() void {}
...@@ -29,13 +37,19 @@ comptime {...@@ -29,13 +37,19 @@ comptime {
29}37}
30const std = @import("std");38const std = @import("std");
31const io = std.Io.Threaded.global_single_threaded.io();39const io = std.Io.Threaded.global_single_threaded.io();
32#expect_error=main.zig:5:5: error: found compile log statement40#}
33#expect_error=main.zig:8:5: note: also here41#update {
34#expect_compile_log=@as(type, i8)42make backing types signed#}
35#expect_compile_log=@as(comptime_int, 10)43#check errors {
44main.zig:5:5: error: found compile log statement
45main.zig:8:5: note: also here
46
47Compile Log Output:
48@as(type, i8)
49@as(comptime_int, 10)
50#}
3651
37#update=make backing types too small52#write main.zig {
38#file=main.zig
39const Foo = packed struct(i5) { a: u4, b: i4 };53const Foo = packed struct(i5) { a: u4, b: i4 };
40const Bar = packed union(i8) { a: u10, b: i10 };54const Bar = packed union(i8) { a: u10, b: i10 };
41pub fn main() void {}55pub fn main() void {}
...@@ -47,16 +61,20 @@ comptime {...@@ -47,16 +61,20 @@ comptime {
47}61}
48const std = @import("std");62const std = @import("std");
49const io = std.Io.Threaded.global_single_threaded.io();63const io = std.Io.Threaded.global_single_threaded.io();
50#expect_error=main.zig:1:20: error: backing integer bit width does not match total bit width of fields64#}
51#expect_error=main.zig:1:27: note: backing integer 'i5' has bit width '5'65#update {
52#expect_error=main.zig:1:20: note: struct fields have total bit width '8'66make backing types too small#}
53#expect_error=main.zig:2:35: error: field bit width does not match backing integer67#check errors {
54#expect_error=main.zig:2:35: note: field type 'u10' has bit width '10'68main.zig:1:20: error: backing integer bit width does not match total bit width of fields
55#expect_error=main.zig:2:26: note: backing integer 'i8' has bit width '8'69main.zig:1:27: note: backing integer 'i5' has bit width '5'
56#expect_error=main.zig:2:35: note: all fields in a packed union must have the same bit width70main.zig:1:20: note: struct fields have total bit width '8'
71main.zig:2:35: error: field bit width does not match backing integer
72main.zig:2:35: note: field type 'u10' has bit width '10'
73main.zig:2:26: note: backing integer 'i8' has bit width '8'
74main.zig:2:35: note: all fields in a packed union must have the same bit width
75#}
5776
58#update=make backing types too big77#write main.zig {
59#file=main.zig
60const Foo = packed struct(u10) { a: u4, b: i4 };78const Foo = packed struct(u10) { a: u4, b: i4 };
61const Bar = packed union(u32) { a: u10, b: i10 };79const Bar = packed union(u32) { a: u10, b: i10 };
62pub fn main() void {}80pub fn main() void {}
...@@ -68,10 +86,15 @@ comptime {...@@ -68,10 +86,15 @@ comptime {
68}86}
69const std = @import("std");87const std = @import("std");
70const io = std.Io.Threaded.global_single_threaded.io();88const io = std.Io.Threaded.global_single_threaded.io();
71#expect_error=main.zig:1:20: error: backing integer bit width does not match total bit width of fields89#}
72#expect_error=main.zig:1:27: note: backing integer 'u10' has bit width '10'90#update {
73#expect_error=main.zig:1:20: note: struct fields have total bit width '8'91make backing types too big#}
74#expect_error=main.zig:2:36: error: field bit width does not match backing integer92#check errors {
75#expect_error=main.zig:2:36: note: field type 'u10' has bit width '10'93main.zig:1:20: error: backing integer bit width does not match total bit width of fields
76#expect_error=main.zig:2:26: note: backing integer 'u32' has bit width '32'94main.zig:1:27: note: backing integer 'u10' has bit width '10'
77#expect_error=main.zig:2:36: note: all fields in a packed union must have the same bit width95main.zig:1:20: note: struct fields have total bit width '8'
96main.zig:2:36: error: field bit width does not match backing integer
97main.zig:2:36: note: field type 'u10' has bit width '10'
98main.zig:2:26: note: backing integer 'u32' has bit width '32'
99main.zig:2:36: note: all fields in a packed union must have the same bit width
100#}
test/incremental/change_container_kind+94-41
...@@ -1,61 +1,114 @@...@@ -1,61 +1,114 @@
1#update=initial version, T is struct1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const T = @import("foo.zig").T;6const T = @import("foo.zig").T;
4pub fn main() void {7pub fn main() void {
5 @compileLog(T);8 @compileLog(T);
6 @compileLog(@tagName(@typeInfo(T)));9 @compileLog(@tagName(@typeInfo(T)));
7}10}
8#file=foo.zig11#}
12#write foo.zig {
9pub const T = struct { x: u8 };13pub const T = struct { x: u8 };
10#expect_error=main.zig:3:5: error: found compile log statement14#}
11#expect_compile_log=@as(type, foo.T)15#update {
12#expect_compile_log=@as(*const [6:0]u8, "struct")16T is struct#}
17#check errors {
18main.zig:3:5: error: found compile log statement
19
20Compile Log Output:
21@as(type, foo.T)
22@as(*const [6:0]u8, "struct")
23#}
1324
14#update=T is union25#write foo.zig {
15#file=foo.zig
16pub const T = union {};26pub const T = union {};
17#expect_error=main.zig:3:5: error: found compile log statement27#}
18#expect_compile_log=@as(type, foo.T)28#update {
19#expect_compile_log=@as(*const [5:0]u8, "union")29T is union#}
30#check errors {
31main.zig:3:5: error: found compile log statement
32
33Compile Log Output:
34@as(type, foo.T)
35@as(*const [5:0]u8, "union")
36#}
2037
21#update=T is enum38#write foo.zig {
22#file=foo.zig
23pub const T = enum {};39pub const T = enum {};
24#expect_error=main.zig:3:5: error: found compile log statement40#}
25#expect_compile_log=@as(type, foo.T)41#update {
26#expect_compile_log=@as(*const [4:0]u8, "enum")42T is enum#}
43#check errors {
44main.zig:3:5: error: found compile log statement
2745
28#update=T is opaque46Compile Log Output:
29#file=foo.zig47@as(type, foo.T)
48@as(*const [4:0]u8, "enum")
49#}
50
51#write foo.zig {
30pub const T = opaque {};52pub const T = opaque {};
31#expect_error=main.zig:3:5: error: found compile log statement53#}
32#expect_compile_log=@as(type, foo.T)54#update {
33#expect_compile_log=@as(*const [6:0]u8, "opaque")55T is opaque#}
56#check errors {
57main.zig:3:5: error: found compile log statement
58
59Compile Log Output:
60@as(type, foo.T)
61@as(*const [6:0]u8, "opaque")
62#}
3463
35#update=T is packed struct64#write foo.zig {
36#file=foo.zig
37pub const T = packed struct {};65pub const T = packed struct {};
38#expect_error=main.zig:3:5: error: found compile log statement66#}
39#expect_compile_log=@as(type, foo.T)67#update {
40#expect_compile_log=@as(*const [6:0]u8, "struct")68T is packed struct#}
69#check errors {
70main.zig:3:5: error: found compile log statement
4171
42#update=T is packed union72Compile Log Output:
43#file=foo.zig73@as(type, foo.T)
74@as(*const [6:0]u8, "struct")
75#}
76
77#write foo.zig {
44pub const T = packed union { x: void }; // packed unions need at least 1 field78pub const T = packed union { x: void }; // packed unions need at least 1 field
45#expect_error=main.zig:3:5: error: found compile log statement79#}
46#expect_compile_log=@as(type, foo.T)80#update {
47#expect_compile_log=@as(*const [5:0]u8, "union")81T is packed union#}
82#check errors {
83main.zig:3:5: error: found compile log statement
84
85Compile Log Output:
86@as(type, foo.T)
87@as(*const [5:0]u8, "union")
88#}
4889
49#update=T is extern struct90#write foo.zig {
50#file=foo.zig
51pub const T = extern struct {};91pub const T = extern struct {};
52#expect_error=main.zig:3:5: error: found compile log statement92#}
53#expect_compile_log=@as(type, foo.T)93#update {
54#expect_compile_log=@as(*const [6:0]u8, "struct")94T is extern struct#}
95#check errors {
96main.zig:3:5: error: found compile log statement
5597
56#update=T is extern union98Compile Log Output:
57#file=foo.zig99@as(type, foo.T)
100@as(*const [6:0]u8, "struct")
101#}
102
103#write foo.zig {
58pub const T = extern union { x: void }; // extern unions need at least 1 field104pub const T = extern union { x: void }; // extern unions need at least 1 field
59#expect_error=main.zig:3:5: error: found compile log statement105#}
60#expect_compile_log=@as(type, foo.T)106#update {
61#expect_compile_log=@as(*const [5:0]u8, "union")107T is extern union#}
108#check errors {
109main.zig:3:5: error: found compile log statement
110
111Compile Log Output:
112@as(type, foo.T)
113@as(*const [5:0]u8, "union")
114#}
test/incremental/change_embed_file+46-19
...@@ -1,45 +1,72 @@...@@ -1,45 +1,72 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4const string = @embedFile("string.txt");7const string = @embedFile("string.txt");
5pub fn main() !void {8pub fn main() !void {
6 try std.Io.File.stdout().writeStreamingAll(io, string);9 try std.Io.File.stdout().writeStreamingAll(io, string);
7}10}
8const io = std.Io.Threaded.global_single_threaded.io();11const io = std.Io.Threaded.global_single_threaded.io();
9#file=string.txt12#}
13#write string.txt {
14Hello, World!
15#}
16#update
17#check stdout {
10Hello, World!18Hello, World!
11#expect_stdout="Hello, World!\n"19#}
1220
13#update=change file contents21#write string.txt {
14#file=string.txt
15Hello again, World!22Hello again, World!
16#expect_stdout="Hello again, World!\n"23#}
24#update {
25change file contents#}
26#check stdout {
27Hello again, World!
28#}
1729
18#update=delete file30#delete string.txt
19#rm_file=string.txt31#update {
20#expect_error=main.zig:2:27: error: failed opening "string.txt": FileNotFound32delete file#}
33#check errors {
34main.zig:2:27: error: failed opening "string.txt": FileNotFound
35#}
2136
22#update=remove reference to file37#write main.zig {
23#file=main.zig
24const std = @import("std");38const std = @import("std");
25const string = @embedFile("string.txt");39const string = @embedFile("string.txt");
26pub fn main() !void {40pub fn main() !void {
27 try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");41 try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");
28}42}
29const io = std.Io.Threaded.global_single_threaded.io();43const io = std.Io.Threaded.global_single_threaded.io();
30#expect_stdout="a hardcoded string\n"44#}
45#update {
46remove reference to file#}
47#check stdout {
48a hardcoded string
49#}
3150
32#update=re-introduce reference to file51#write main.zig {
33#file=main.zig
34const std = @import("std");52const std = @import("std");
35const string = @embedFile("string.txt");53const string = @embedFile("string.txt");
36pub fn main() !void {54pub fn main() !void {
37 try std.Io.File.stdout().writeStreamingAll(io, string);55 try std.Io.File.stdout().writeStreamingAll(io, string);
38}56}
39const io = std.Io.Threaded.global_single_threaded.io();57const io = std.Io.Threaded.global_single_threaded.io();
40#expect_error=main.zig:2:27: error: failed opening "string.txt": FileNotFound58#}
59#update {
60re-introduce reference to file#}
61#check errors {
62main.zig:2:27: error: failed opening "string.txt": FileNotFound
63#}
4164
42#update=recreate file65#write string.txt {
43#file=string.txt66We're back, World!
67#}
68#update {
69recreate file#}
70#check stdout {
44We're back, World!71We're back, World!
45#expect_stdout="We're back, World!\n"72#}
test/incremental/change_enum_tag_type deleted-93
...@@ -1,93 +0,0 @@
1#update=initial version
2#file=main.zig
3const Tag = u2;
4const Foo = enum(Tag) {
5 a,
6 b,
7 c,
8 d,
9};
10pub fn main() !void {
11 var val: Foo = undefined;
12 val = .a;
13 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
14 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
15}
16const std = @import("std");
17const io = std.Io.Threaded.global_single_threaded.io();
18#expect_stdout="a\n"
19#update=too many enum fields
20#file=main.zig
21const Tag = u2;
22const Foo = enum(Tag) {
23 a,
24 b,
25 c,
26 d,
27 e,
28};
29pub fn main() !void {
30 var val: Foo = undefined;
31 val = .a;
32 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
33 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
34}
35comptime {
36 // These can't be true at the same time; analysis should stop as soon as it sees `Foo`
37 std.debug.assert(@intFromEnum(Foo.e) == 4);
38 std.debug.assert(@TypeOf(@intFromEnum(Foo.e)) == Tag);
39}
40const std = @import("std");
41const io = std.Io.Threaded.global_single_threaded.io();
42#expect_error=main.zig:7:5: error: enum tag value '4' too large for type 'u2'
43#update=increase tag size
44#file=main.zig
45const Tag = u3;
46const Foo = enum(Tag) {
47 a,
48 b,
49 c,
50 d,
51 e,
52};
53pub fn main() !void {
54 var val: Foo = undefined;
55 val = .a;
56 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
57 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
58}
59const std = @import("std");
60const io = std.Io.Threaded.global_single_threaded.io();
61#expect_stdout="a\n"
62#update=specify tag directly
63#file=main.zig
64const Foo = enum(u3) {
65 a,
66 b,
67 c,
68 d,
69 e,
70};
71pub fn main() !void {
72 @compileLog(@typeInfo(Foo).@"enum".tag_type);
73}
74const std = @import("std");
75const io = std.Io.Threaded.global_single_threaded.io();
76#expect_error=main.zig:9:5: error: found compile log statement
77#expect_compile_log=@as(type, u3)
78#update=change directly-specified tag type
79#file=main.zig
80const Foo = enum(u8) {
81 a,
82 b,
83 c,
84 d,
85 e,
86};
87pub fn main() !void {
88 @compileLog(@typeInfo(Foo).@"enum".tag_type);
89}
90const std = @import("std");
91const io = std.Io.Threaded.global_single_threaded.io();
92#expect_error=main.zig:9:5: error: found compile log statement
93#expect_compile_log=@as(type, u8)
test/incremental/change_enum_tag_type/0/main.zig created+15
...@@ -0,0 +1,15 @@
1const Tag = u2;
2const Foo = enum(Tag) {
3 a,
4 b,
5 c,
6 d,
7};
8pub fn main() !void {
9 var val: Foo = undefined;
10 val = .a;
11 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
12 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
13}
14const std = @import("std");
15const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_enum_tag_type/1/main.zig created+21
...@@ -0,0 +1,21 @@
1const Tag = u2;
2const Foo = enum(Tag) {
3 a,
4 b,
5 c,
6 d,
7 e,
8};
9pub fn main() !void {
10 var val: Foo = undefined;
11 val = .a;
12 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
13 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
14}
15comptime {
16 // These can't be true at the same time; analysis should stop as soon as it sees `Foo`
17 std.debug.assert(@backingInt(Foo.e) == 4);
18 std.debug.assert(@TypeOf(@backingInt(Foo.e)) == Tag);
19}
20const std = @import("std");
21const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_enum_tag_type/2/main.zig created+16
...@@ -0,0 +1,16 @@
1const Tag = u3;
2const Foo = enum(Tag) {
3 a,
4 b,
5 c,
6 d,
7 e,
8};
9pub fn main() !void {
10 var val: Foo = undefined;
11 val = .a;
12 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
13 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
14}
15const std = @import("std");
16const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_enum_tag_type/3/main.zig created+12
...@@ -0,0 +1,12 @@
1const Foo = enum(u3) {
2 a,
3 b,
4 c,
5 d,
6 e,
7};
8pub fn main() !void {
9 @compileLog(@typeInfo(Foo).@"enum".tag_type);
10}
11const std = @import("std");
12const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_enum_tag_type/4/main.zig created+12
...@@ -0,0 +1,12 @@
1const Foo = enum(u8) {
2 a,
3 b,
4 c,
5 d,
6 e,
7};
8pub fn main() !void {
9 @compileLog(@typeInfo(Foo).@"enum".tag_type);
10}
11const std = @import("std");
12const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_enum_tag_type/manifest created+43
...@@ -0,0 +1,43 @@
1#exe {
2-Mroot=main.zig
3#}
4
5#write main.zig 0/main.zig
6#update
7#check stdout {
8a
9#}
10
11#write main.zig 1/main.zig
12#update {
13too many enum fields#}
14#check errors {
15main.zig:7:5: error: enum tag value '4' too large for type 'u2'
16#}
17
18#write main.zig 2/main.zig
19#update {
20increase tag size#}
21#check stdout {
22a
23#}
24
25#write main.zig 3/main.zig
26#update {
27specify tag directly#}
28#check errors {
29main.zig:9:5: error: found compile log statement
30
31Compile Log Output:
32@as(type, u3)
33#}
34
35#write main.zig 4/main.zig
36#update {
37change directly-specified tag type#}
38#check errors {
39main.zig:9:5: error: found compile log statement
40
41Compile Log Output:
42@as(type, u8)
43#}
test/incremental/change_exports deleted-169
...@@ -1,169 +0,0 @@
1#update=initial version
2#file=main.zig
3export fn foo() void {}
4const bar: u32 = 123;
5const other: u32 = 456;
6comptime {
7 @export(&bar, .{ .name = "bar" });
8}
9pub fn main() !void {
10 const S = struct {
11 extern fn foo() void;
12 extern const bar: u32;
13 };
14 S.foo();
15 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
16 try stdout_writer.interface.print("{}\n", .{S.bar});
17}
18const std = @import("std");
19const io = std.Io.Threaded.global_single_threaded.io();
20#expect_stdout="123\n"
21
22#update=add conflict
23#file=main.zig
24export fn foo() void {}
25const bar: u32 = 123;
26const other: u32 = 456;
27comptime {
28 @export(&bar, .{ .name = "bar" });
29 @export(&other, .{ .name = "foo" });
30}
31pub fn main() !void {
32 const S = struct {
33 extern fn foo() void;
34 extern const bar: u32;
35 extern const other: u32;
36 };
37 S.foo();
38 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
39 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
40}
41const std = @import("std");
42const io = std.Io.Threaded.global_single_threaded.io();
43#expect_error=main.zig:6:5: error: exported symbol collision: foo
44#expect_error=main.zig:1:1: note: other symbol here
45
46#update=resolve conflict
47#file=main.zig
48export fn foo() void {}
49const bar: u32 = 123;
50const other: u32 = 456;
51comptime {
52 @export(&bar, .{ .name = "bar" });
53 @export(&other, .{ .name = "other" });
54}
55pub fn main() !void {
56 const S = struct {
57 extern fn foo() void;
58 extern const bar: u32;
59 extern const other: u32;
60 };
61 S.foo();
62 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
63 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
64}
65const std = @import("std");
66const io = std.Io.Threaded.global_single_threaded.io();
67#expect_stdout="123 456\n"
68
69#update=put exports in decl
70#file=main.zig
71export fn foo() void {}
72const bar: u32 = 123;
73const other: u32 = 456;
74const does_exports = {
75 @export(&bar, .{ .name = "bar" });
76 @export(&other, .{ .name = "other" });
77};
78comptime {
79 _ = does_exports;
80}
81pub fn main() !void {
82 const S = struct {
83 extern fn foo() void;
84 extern const bar: u32;
85 extern const other: u32;
86 };
87 S.foo();
88 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
89 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
90}
91const std = @import("std");
92const io = std.Io.Threaded.global_single_threaded.io();
93#expect_stdout="123 456\n"
94
95#update=remove reference to exporting decl
96#file=main.zig
97export fn foo() void {}
98const bar: u32 = 123;
99const other: u32 = 456;
100const does_exports = {
101 @export(&bar, .{ .name = "bar" });
102 @export(&other, .{ .name = "other" });
103};
104comptime {
105 //_ = does_exports;
106}
107pub fn main() !void {
108 const S = struct {
109 extern fn foo() void;
110 };
111 S.foo();
112}
113const std = @import("std");
114#expect_stdout=""
115
116#update=mark consts as export
117#file=main.zig
118export fn foo() void {}
119export const bar: u32 = 123;
120export const other: u32 = 456;
121const does_exports = {
122 @export(&bar, .{ .name = "bar" });
123 @export(&other, .{ .name = "other" });
124};
125comptime {
126 //_ = does_exports;
127}
128pub fn main() !void {
129 const S = struct {
130 extern fn foo() void;
131 extern const bar: u32;
132 extern const other: u32;
133 };
134 S.foo();
135 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
136 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
137}
138const std = @import("std");
139const io = std.Io.Threaded.global_single_threaded.io();
140#expect_stdout="123 456\n"
141
142#update=reintroduce reference to exporting decl, introducing conflict
143#file=main.zig
144export fn foo() void {}
145export const bar: u32 = 123;
146export const other: u32 = 456;
147const does_exports = {
148 @export(&bar, .{ .name = "bar" });
149 @export(&other, .{ .name = "other" });
150};
151comptime {
152 _ = does_exports;
153}
154pub fn main() !void {
155 const S = struct {
156 extern fn foo() void;
157 extern const bar: u32;
158 extern const other: u32;
159 };
160 S.foo();
161 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
162 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
163}
164const std = @import("std");
165const io = std.Io.Threaded.global_single_threaded.io();
166#expect_error=main.zig:5:5: error: exported symbol collision: bar
167#expect_error=main.zig:2:1: note: other symbol here
168#expect_error=main.zig:6:5: error: exported symbol collision: other
169#expect_error=main.zig:3:1: note: other symbol here
test/incremental/change_exports/0/main.zig created+17
...@@ -0,0 +1,17 @@
1export fn foo() void {}
2const bar: u32 = 123;
3const other: u32 = 456;
4comptime {
5 @export(&bar, .{ .name = "bar" });
6}
7pub fn main() !void {
8 const S = struct {
9 extern fn foo() void;
10 extern const bar: u32;
11 };
12 S.foo();
13 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
14 try stdout_writer.interface.print("{}\n", .{S.bar});
15}
16const std = @import("std");
17const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_exports/1/main.zig created+19
...@@ -0,0 +1,19 @@
1export fn foo() void {}
2const bar: u32 = 123;
3const other: u32 = 456;
4comptime {
5 @export(&bar, .{ .name = "bar" });
6 @export(&other, .{ .name = "foo" });
7}
8pub fn main() !void {
9 const S = struct {
10 extern fn foo() void;
11 extern const bar: u32;
12 extern const other: u32;
13 };
14 S.foo();
15 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
16 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
17}
18const std = @import("std");
19const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_exports/2/main.zig created+19
...@@ -0,0 +1,19 @@
1export fn foo() void {}
2const bar: u32 = 123;
3const other: u32 = 456;
4comptime {
5 @export(&bar, .{ .name = "bar" });
6 @export(&other, .{ .name = "other" });
7}
8pub fn main() !void {
9 const S = struct {
10 extern fn foo() void;
11 extern const bar: u32;
12 extern const other: u32;
13 };
14 S.foo();
15 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
16 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
17}
18const std = @import("std");
19const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_exports/3/main.zig created+22
...@@ -0,0 +1,22 @@
1export fn foo() void {}
2const bar: u32 = 123;
3const other: u32 = 456;
4const does_exports = {
5 @export(&bar, .{ .name = "bar" });
6 @export(&other, .{ .name = "other" });
7};
8comptime {
9 _ = does_exports;
10}
11pub fn main() !void {
12 const S = struct {
13 extern fn foo() void;
14 extern const bar: u32;
15 extern const other: u32;
16 };
17 S.foo();
18 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
19 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
20}
21const std = @import("std");
22const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_exports/4/main.zig created+17
...@@ -0,0 +1,17 @@
1export fn foo() void {}
2const bar: u32 = 123;
3const other: u32 = 456;
4const does_exports = {
5 @export(&bar, .{ .name = "bar" });
6 @export(&other, .{ .name = "other" });
7};
8comptime {
9 //_ = does_exports;
10}
11pub fn main() !void {
12 const S = struct {
13 extern fn foo() void;
14 };
15 S.foo();
16}
17const std = @import("std");
test/incremental/change_exports/5/main.zig created+22
...@@ -0,0 +1,22 @@
1export fn foo() void {}
2export const bar: u32 = 123;
3export const other: u32 = 456;
4const does_exports = {
5 @export(&bar, .{ .name = "bar" });
6 @export(&other, .{ .name = "other" });
7};
8comptime {
9 //_ = does_exports;
10}
11pub fn main() !void {
12 const S = struct {
13 extern fn foo() void;
14 extern const bar: u32;
15 extern const other: u32;
16 };
17 S.foo();
18 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
19 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
20}
21const std = @import("std");
22const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_exports/6/main.zig created+22
...@@ -0,0 +1,22 @@
1export fn foo() void {}
2export const bar: u32 = 123;
3export const other: u32 = 456;
4const does_exports = {
5 @export(&bar, .{ .name = "bar" });
6 @export(&other, .{ .name = "other" });
7};
8comptime {
9 _ = does_exports;
10}
11pub fn main() !void {
12 const S = struct {
13 extern fn foo() void;
14 extern const bar: u32;
15 extern const other: u32;
16 };
17 S.foo();
18 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
19 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
20}
21const std = @import("std");
22const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_exports/manifest created+54
...@@ -0,0 +1,54 @@
1#exe {
2-Mroot=main.zig
3#}
4
5#write main.zig 0/main.zig
6#update
7#check stdout {
8123
9#}
10
11#write main.zig 1/main.zig
12#update {
13add conflict#}
14#check errors {
15main.zig:6:5: error: exported symbol collision: foo
16main.zig:1:1: note: other symbol here
17#}
18
19#write main.zig 2/main.zig
20#update {
21resolve conflict#}
22#check stdout {
23123 456
24#}
25
26#write main.zig 3/main.zig
27#update {
28put exports in decl#}
29#check stdout {
30123 456
31#}
32
33#write main.zig 4/main.zig
34#update {
35remove reference to exporting decl#}
36#check stdout {
37#}
38
39#write main.zig 5/main.zig
40#update {
41mark consts as export#}
42#check stdout {
43123 456
44#}
45
46#write main.zig 6/main.zig
47#update {
48reintroduce reference to exporting decl, introducing conflict#}
49#check errors {
50main.zig:5:5: error: exported symbol collision: bar
51main.zig:2:1: note: other symbol here
52main.zig:6:5: error: exported symbol collision: other
53main.zig:3:1: note: other symbol here
54#}
test/incremental/change_fn_type+24-9
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3pub fn main() !void {6pub fn main() !void {
4 try foo(123);7 try foo(123);
5}8}
...@@ -9,10 +12,13 @@ fn foo(x: u8) !void {...@@ -9,10 +12,13 @@ fn foo(x: u8) !void {
9}12}
10const std = @import("std");13const std = @import("std");
11const io = std.Io.Threaded.global_single_threaded.io();14const io = std.Io.Threaded.global_single_threaded.io();
12#expect_stdout="123\n"15#}
16#update
17#check stdout {
18123
19#}
1320
14#update=change function type21#write main.zig {
15#file=main.zig
16pub fn main() !void {22pub fn main() !void {
17 try foo(123);23 try foo(123);
18}24}
...@@ -22,10 +28,14 @@ fn foo(x: i64) !void {...@@ -22,10 +28,14 @@ fn foo(x: i64) !void {
22}28}
23const std = @import("std");29const std = @import("std");
24const io = std.Io.Threaded.global_single_threaded.io();30const io = std.Io.Threaded.global_single_threaded.io();
25#expect_stdout="123\n"31#}
32#update {
33change function type#}
34#check stdout {
35123
36#}
2637
27#update=change function argument38#write main.zig {
28#file=main.zig
29pub fn main() !void {39pub fn main() !void {
30 try foo(-42);40 try foo(-42);
31}41}
...@@ -35,4 +45,9 @@ fn foo(x: i64) !void {...@@ -35,4 +45,9 @@ fn foo(x: i64) !void {
35}45}
36const std = @import("std");46const std = @import("std");
37const io = std.Io.Threaded.global_single_threaded.io();47const io = std.Io.Threaded.global_single_threaded.io();
38#expect_stdout="-42\n"48#}
49#update {
50change function argument#}
51#check stdout {
52-42
53#}
test/incremental/change_generic_line_number+20-6
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4const io = std.Io.Threaded.global_single_threaded.io();7const io = std.Io.Threaded.global_single_threaded.io();
5fn Printer(message: []const u8) type {8fn Printer(message: []const u8) type {
...@@ -13,9 +16,14 @@ pub fn main() !void {...@@ -13,9 +16,14 @@ pub fn main() !void {
13 try Printer("foo\n").print();16 try Printer("foo\n").print();
14 try Printer("bar\n").print();17 try Printer("bar\n").print();
15}18}
16#expect_stdout="foo\nbar\n"19#}
17#update=change line number20#update
18#file=main.zig21#check stdout {
22foo
23bar
24#}
25
26#write main.zig {
19const std = @import("std");27const std = @import("std");
20const io = std.Io.Threaded.global_single_threaded.io();28const io = std.Io.Threaded.global_single_threaded.io();
2129
...@@ -30,4 +38,10 @@ pub fn main() !void {...@@ -30,4 +38,10 @@ pub fn main() !void {
30 try Printer("foo\n").print();38 try Printer("foo\n").print();
31 try Printer("bar\n").print();39 try Printer("bar\n").print();
32}40}
33#expect_stdout="foo\nbar\n"41#}
42#update {
43change line number#}
44#check stdout {
45foo
46bar
47#}
test/incremental/change_line_number+18-6
...@@ -1,17 +1,29 @@...@@ -1,17 +1,29 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4pub fn main() !void {7pub fn main() !void {
5 try std.Io.File.stdout().writeStreamingAll(io, "foo\n");8 try std.Io.File.stdout().writeStreamingAll(io, "foo\n");
6}9}
7const io = std.Io.Threaded.global_single_threaded.io();10const io = std.Io.Threaded.global_single_threaded.io();
8#expect_stdout="foo\n"11#}
9#update=change line number12#update
10#file=main.zig13#check stdout {
14foo
15#}
16
17#write main.zig {
11const std = @import("std");18const std = @import("std");
1219
13pub fn main() !void {20pub fn main() !void {
14 try std.Io.File.stdout().writeStreamingAll(io, "foo\n");21 try std.Io.File.stdout().writeStreamingAll(io, "foo\n");
15}22}
16const io = std.Io.Threaded.global_single_threaded.io();23const io = std.Io.Threaded.global_single_threaded.io();
17#expect_stdout="foo\n"24#}
25#update {
26change line number#}
27#check stdout {
28foo
29#}
test/incremental/change_module+49-23
...@@ -1,61 +1,87 @@...@@ -1,61 +1,87 @@
1#module=foo=foo.zig1#exe {
2--dep foo -Mroot=main.zig
3-Mfoo=foo.zig
4#}
25
3#update=initial version6#write main.zig {
4#file=main.zig
5pub fn main() void {7pub fn main() void {
6 _ = @import("foo");8 _ = @import("foo");
7 //_ = @import("other.zig");9 //_ = @import("other.zig");
8}10}
9#file=foo.zig11#}
12#write foo.zig {
10comptime {13comptime {
11 _ = @import("other.zig");14 _ = @import("other.zig");
12}15}
13#file=other.zig16#}
17#write other.zig {
14fn f() void {18fn f() void {
15 @compileLog(@src().module);19 @compileLog(@src().module);
16}20}
17comptime {21comptime {
18 f();22 f();
19}23}
20#expect_error=other.zig:2:5: error: found compile log statement24#}
21#expect_compile_log=@as([:0]const u8, "foo"[0..3])25#update
26#check errors {
27other.zig:2:5: error: found compile log statement
2228
23#update=change module of other.zig29Compile Log Output:
24#file=main.zig30@as([:0]const u8, "foo"[0..3])
31#}
32
33#write main.zig {
25pub fn main() void {34pub fn main() void {
26 _ = @import("foo");35 _ = @import("foo");
27 _ = @import("other.zig");36 _ = @import("other.zig");
28}37}
29#file=foo.zig38#}
39#write foo.zig {
30comptime {40comptime {
31 //_ = @import("other.zig");41 //_ = @import("other.zig");
32}42}
33#expect_error=other.zig:2:5: error: found compile log statement43#}
34#expect_compile_log=@as([:0]const u8, "root"[0..4])44#update {
45change module of other.zig#}
46#check errors {
47other.zig:2:5: error: found compile log statement
48
49Compile Log Output:
50@as([:0]const u8, "root"[0..4])
51#}
3552
36#update=put other.zig in both modules53#write main.zig {
37#file=main.zig
38pub fn main() void {54pub fn main() void {
39 _ = @import("foo");55 _ = @import("foo");
40 _ = @import("other.zig");56 _ = @import("other.zig");
41}57}
42#file=foo.zig58#}
59#write foo.zig {
43comptime {60comptime {
44 _ = @import("other.zig");61 _ = @import("other.zig");
45}62}
46#expect_error=other.zig:1:1: error: file exists in modules 'root' and 'foo'63#}
47#expect_error=other.zig:1:1: note: files must belong to only one module64#update {
48#expect_error=main.zig:3:17: note: file is imported here by the root of module 'root'65put other.zig in both modules#}
49#expect_error=foo.zig:2:17: note: file is imported here by the root of module 'foo'66#check errors {
67other.zig:1:1: error: file exists in modules 'root' and 'foo'
68other.zig:1:1: note: files must belong to only one module
69main.zig:3:17: note: file is imported here by the root of module 'root'
70foo.zig:2:17: note: file is imported here by the root of module 'foo'
71#}
5072
51#update=put other.zig in no modules73#write main.zig {
52#file=main.zig
53pub fn main() void {74pub fn main() void {
54 _ = @import("foo");75 _ = @import("foo");
55 //_ = @import("other.zig");76 //_ = @import("other.zig");
56}77}
57#file=foo.zig78#}
79#write foo.zig {
58comptime {80comptime {
59 //_ = @import("other.zig");81 //_ = @import("other.zig");
60}82}
61#expect_stdout=""83#}
84#update {
85put other.zig in no modules#}
86#check stdout {
87#}
test/incremental/change_panic_handler+24-9
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3pub fn main() !u8 {6pub fn main() !u8 {
4 var a: u8 = undefined;7 var a: u8 = undefined;
5 a = 255;8 a = 255;
...@@ -14,10 +17,13 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {...@@ -14,10 +17,13 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {
14}17}
15const std = @import("std");18const std = @import("std");
16const io = std.Io.Threaded.global_single_threaded.io();19const io = std.Io.Threaded.global_single_threaded.io();
17#expect_stdout="panic message: integer overflow\n"20#}
21#update
22#check stdout {
23panic message: integer overflow
24#}
1825
19#update=change the panic handler body26#write main.zig {
20#file=main.zig
21pub fn main() !u8 {27pub fn main() !u8 {
22 var a: u8 = undefined;28 var a: u8 = undefined;
23 a = 255;29 a = 255;
...@@ -32,10 +38,14 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {...@@ -32,10 +38,14 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {
32}38}
33const std = @import("std");39const std = @import("std");
34const io = std.Io.Threaded.global_single_threaded.io();40const io = std.Io.Threaded.global_single_threaded.io();
35#expect_stdout="new panic message: integer overflow\n"41#}
42#update {
43change the panic handler body#}
44#check stdout {
45new panic message: integer overflow
46#}
3647
37#update=change the panic handler function value48#write main.zig {
38#file=main.zig
39pub fn main() !u8 {49pub fn main() !u8 {
40 var a: u8 = undefined;50 var a: u8 = undefined;
41 a = 255;51 a = 255;
...@@ -50,4 +60,9 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn {...@@ -50,4 +60,9 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
50}60}
51const std = @import("std");61const std = @import("std");
52const io = std.Io.Threaded.global_single_threaded.io();62const io = std.Io.Threaded.global_single_threaded.io();
53#expect_stdout="third panic message: integer overflow\n"63#}
64#update {
65change the panic handler function value#}
66#check stdout {
67third panic message: integer overflow
68#}
test/incremental/change_panic_handler_explicit deleted-149
...@@ -1,149 +0,0 @@
1#update=initial version
2#file=main.zig
3pub fn main() !u8 {
4 var a: u8 = undefined;
5 a = 255;
6 _ = a + 1;
7 return 1;
8}
9const no_panic = std.debug.no_panic;
10pub const panic = struct {
11 pub const call = myPanic;
12 pub fn integerOverflow() noreturn {
13 @panic("integer overflow");
14 }
15 pub const sentinelMismatch = no_panic.sentinelMismatch;
16 pub const unwrapError = no_panic.unwrapError;
17 pub const outOfBounds = no_panic.outOfBounds;
18 pub const startGreaterThanEnd = no_panic.startGreaterThanEnd;
19 pub const inactiveUnionField = no_panic.inactiveUnionField;
20 pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder;
21 pub const reachedUnreachable = no_panic.reachedUnreachable;
22 pub const unwrapNull = no_panic.unwrapNull;
23 pub const castToNull = no_panic.castToNull;
24 pub const incorrectAlignment = no_panic.incorrectAlignment;
25 pub const invalidErrorCode = no_panic.invalidErrorCode;
26 pub const unexpectedErrorCode = no_panic.unexpectedErrorCode;
27 pub const integerOutOfBounds = no_panic.integerOutOfBounds;
28 pub const shlOverflow = no_panic.shlOverflow;
29 pub const shrOverflow = no_panic.shrOverflow;
30 pub const divideByZero = no_panic.divideByZero;
31 pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
32 pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
33 pub const corruptSwitch = no_panic.corruptSwitch;
34 pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
35 pub const invalidEnumValue = no_panic.invalidEnumValue;
36 pub const forLenMismatch = no_panic.forLenMismatch;
37 pub const copyLenMismatch = no_panic.copyLenMismatch;
38 pub const memcpyAlias = no_panic.memcpyAlias;
39 pub const noreturnReturned = no_panic.noreturnReturned;
40 pub const loadUninstantiableType = no_panic.loadUninstantiableType;
41};
42fn myPanic(msg: []const u8, _: ?usize) noreturn {
43 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
44 stdout_writer.interface.print("panic message: {s}\n", .{msg}) catch {};
45 std.process.exit(0);
46}
47const std = @import("std");
48const io = std.Io.Threaded.global_single_threaded.io();
49#expect_stdout="panic message: integer overflow\n"
50
51#update=change the panic handler body
52#file=main.zig
53pub fn main() !u8 {
54 var a: u8 = undefined;
55 a = 255;
56 _ = a + 1;
57 return 1;
58}
59const no_panic = std.debug.no_panic;
60pub const panic = struct {
61 pub const call = myPanic;
62 pub fn integerOverflow() noreturn {
63 @panic("integer overflow");
64 }
65 pub const sentinelMismatch = no_panic.sentinelMismatch;
66 pub const unwrapError = no_panic.unwrapError;
67 pub const outOfBounds = no_panic.outOfBounds;
68 pub const startGreaterThanEnd = no_panic.startGreaterThanEnd;
69 pub const inactiveUnionField = no_panic.inactiveUnionField;
70 pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder;
71 pub const reachedUnreachable = no_panic.reachedUnreachable;
72 pub const unwrapNull = no_panic.unwrapNull;
73 pub const castToNull = no_panic.castToNull;
74 pub const incorrectAlignment = no_panic.incorrectAlignment;
75 pub const invalidErrorCode = no_panic.invalidErrorCode;
76 pub const unexpectedErrorCode = no_panic.unexpectedErrorCode;
77 pub const integerOutOfBounds = no_panic.integerOutOfBounds;
78 pub const shlOverflow = no_panic.shlOverflow;
79 pub const shrOverflow = no_panic.shrOverflow;
80 pub const divideByZero = no_panic.divideByZero;
81 pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
82 pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
83 pub const corruptSwitch = no_panic.corruptSwitch;
84 pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
85 pub const invalidEnumValue = no_panic.invalidEnumValue;
86 pub const forLenMismatch = no_panic.forLenMismatch;
87 pub const copyLenMismatch = no_panic.copyLenMismatch;
88 pub const memcpyAlias = no_panic.memcpyAlias;
89 pub const noreturnReturned = no_panic.noreturnReturned;
90 pub const loadUninstantiableType = no_panic.loadUninstantiableType;
91};
92fn myPanic(msg: []const u8, _: ?usize) noreturn {
93 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
94 stdout_writer.interface.print("new panic message: {s}\n", .{msg}) catch {};
95 std.process.exit(0);
96}
97const std = @import("std");
98const io = std.Io.Threaded.global_single_threaded.io();
99#expect_stdout="new panic message: integer overflow\n"
100
101#update=change the panic handler function value
102#file=main.zig
103pub fn main() !u8 {
104 var a: u8 = undefined;
105 a = 255;
106 _ = a + 1;
107 return 1;
108}
109const no_panic = std.debug.no_panic;
110pub const panic = struct {
111 pub const call = myPanicNew;
112 pub fn integerOverflow() noreturn {
113 @panic("integer overflow");
114 }
115 pub const sentinelMismatch = std.debug.no_panic.sentinelMismatch;
116 pub const unwrapError = std.debug.no_panic.unwrapError;
117 pub const outOfBounds = std.debug.no_panic.outOfBounds;
118 pub const startGreaterThanEnd = std.debug.no_panic.startGreaterThanEnd;
119 pub const inactiveUnionField = std.debug.no_panic.inactiveUnionField;
120 pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder;
121 pub const reachedUnreachable = no_panic.reachedUnreachable;
122 pub const unwrapNull = no_panic.unwrapNull;
123 pub const castToNull = no_panic.castToNull;
124 pub const incorrectAlignment = no_panic.incorrectAlignment;
125 pub const invalidErrorCode = no_panic.invalidErrorCode;
126 pub const unexpectedErrorCode = no_panic.unexpectedErrorCode;
127 pub const integerOutOfBounds = no_panic.integerOutOfBounds;
128 pub const shlOverflow = no_panic.shlOverflow;
129 pub const shrOverflow = no_panic.shrOverflow;
130 pub const divideByZero = no_panic.divideByZero;
131 pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
132 pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
133 pub const corruptSwitch = no_panic.corruptSwitch;
134 pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
135 pub const invalidEnumValue = no_panic.invalidEnumValue;
136 pub const forLenMismatch = no_panic.forLenMismatch;
137 pub const copyLenMismatch = no_panic.copyLenMismatch;
138 pub const memcpyAlias = no_panic.memcpyAlias;
139 pub const noreturnReturned = no_panic.noreturnReturned;
140 pub const loadUninstantiableType = no_panic.loadUninstantiableType;
141};
142fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
143 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
144 stdout_writer.interface.print("third panic message: {s}\n", .{msg}) catch {};
145 std.process.exit(0);
146}
147const std = @import("std");
148const io = std.Io.Threaded.global_single_threaded.io();
149#expect_stdout="third panic message: integer overflow\n"
test/incremental/change_panic_handler_explicit/0/main.zig created+46
...@@ -0,0 +1,46 @@
1pub fn main() !u8 {
2 var a: u8 = undefined;
3 a = 255;
4 _ = a + 1;
5 return 1;
6}
7const no_panic = std.debug.no_panic;
8pub const panic = struct {
9 pub const call = myPanic;
10 pub fn integerOverflow() noreturn {
11 @panic("integer overflow");
12 }
13 pub const sentinelMismatch = no_panic.sentinelMismatch;
14 pub const unwrapError = no_panic.unwrapError;
15 pub const outOfBounds = no_panic.outOfBounds;
16 pub const startGreaterThanEnd = no_panic.startGreaterThanEnd;
17 pub const inactiveUnionField = no_panic.inactiveUnionField;
18 pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder;
19 pub const reachedUnreachable = no_panic.reachedUnreachable;
20 pub const unwrapNull = no_panic.unwrapNull;
21 pub const castToNull = no_panic.castToNull;
22 pub const incorrectAlignment = no_panic.incorrectAlignment;
23 pub const invalidErrorCode = no_panic.invalidErrorCode;
24 pub const unexpectedErrorCode = no_panic.unexpectedErrorCode;
25 pub const integerOutOfBounds = no_panic.integerOutOfBounds;
26 pub const shlOverflow = no_panic.shlOverflow;
27 pub const shrOverflow = no_panic.shrOverflow;
28 pub const divideByZero = no_panic.divideByZero;
29 pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
30 pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
31 pub const corruptSwitch = no_panic.corruptSwitch;
32 pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
33 pub const invalidEnumValue = no_panic.invalidEnumValue;
34 pub const forLenMismatch = no_panic.forLenMismatch;
35 pub const copyLenMismatch = no_panic.copyLenMismatch;
36 pub const memcpyAlias = no_panic.memcpyAlias;
37 pub const noreturnReturned = no_panic.noreturnReturned;
38 pub const loadUninstantiableType = no_panic.loadUninstantiableType;
39};
40fn myPanic(msg: []const u8, _: ?usize) noreturn {
41 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
42 stdout_writer.interface.print("panic message: {s}\n", .{msg}) catch {};
43 std.process.exit(0);
44}
45const std = @import("std");
46const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_panic_handler_explicit/1/main.zig created+46
...@@ -0,0 +1,46 @@
1pub fn main() !u8 {
2 var a: u8 = undefined;
3 a = 255;
4 _ = a + 1;
5 return 1;
6}
7const no_panic = std.debug.no_panic;
8pub const panic = struct {
9 pub const call = myPanic;
10 pub fn integerOverflow() noreturn {
11 @panic("integer overflow");
12 }
13 pub const sentinelMismatch = no_panic.sentinelMismatch;
14 pub const unwrapError = no_panic.unwrapError;
15 pub const outOfBounds = no_panic.outOfBounds;
16 pub const startGreaterThanEnd = no_panic.startGreaterThanEnd;
17 pub const inactiveUnionField = no_panic.inactiveUnionField;
18 pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder;
19 pub const reachedUnreachable = no_panic.reachedUnreachable;
20 pub const unwrapNull = no_panic.unwrapNull;
21 pub const castToNull = no_panic.castToNull;
22 pub const incorrectAlignment = no_panic.incorrectAlignment;
23 pub const invalidErrorCode = no_panic.invalidErrorCode;
24 pub const unexpectedErrorCode = no_panic.unexpectedErrorCode;
25 pub const integerOutOfBounds = no_panic.integerOutOfBounds;
26 pub const shlOverflow = no_panic.shlOverflow;
27 pub const shrOverflow = no_panic.shrOverflow;
28 pub const divideByZero = no_panic.divideByZero;
29 pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
30 pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
31 pub const corruptSwitch = no_panic.corruptSwitch;
32 pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
33 pub const invalidEnumValue = no_panic.invalidEnumValue;
34 pub const forLenMismatch = no_panic.forLenMismatch;
35 pub const copyLenMismatch = no_panic.copyLenMismatch;
36 pub const memcpyAlias = no_panic.memcpyAlias;
37 pub const noreturnReturned = no_panic.noreturnReturned;
38 pub const loadUninstantiableType = no_panic.loadUninstantiableType;
39};
40fn myPanic(msg: []const u8, _: ?usize) noreturn {
41 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
42 stdout_writer.interface.print("new panic message: {s}\n", .{msg}) catch {};
43 std.process.exit(0);
44}
45const std = @import("std");
46const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_panic_handler_explicit/2/main.zig created+46
...@@ -0,0 +1,46 @@
1pub fn main() !u8 {
2 var a: u8 = undefined;
3 a = 255;
4 _ = a + 1;
5 return 1;
6}
7const no_panic = std.debug.no_panic;
8pub const panic = struct {
9 pub const call = myPanicNew;
10 pub fn integerOverflow() noreturn {
11 @panic("integer overflow");
12 }
13 pub const sentinelMismatch = no_panic.sentinelMismatch;
14 pub const unwrapError = no_panic.unwrapError;
15 pub const outOfBounds = no_panic.outOfBounds;
16 pub const startGreaterThanEnd = no_panic.startGreaterThanEnd;
17 pub const inactiveUnionField = no_panic.inactiveUnionField;
18 pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder;
19 pub const reachedUnreachable = no_panic.reachedUnreachable;
20 pub const unwrapNull = no_panic.unwrapNull;
21 pub const castToNull = no_panic.castToNull;
22 pub const incorrectAlignment = no_panic.incorrectAlignment;
23 pub const invalidErrorCode = no_panic.invalidErrorCode;
24 pub const unexpectedErrorCode = no_panic.unexpectedErrorCode;
25 pub const integerOutOfBounds = no_panic.integerOutOfBounds;
26 pub const shlOverflow = no_panic.shlOverflow;
27 pub const shrOverflow = no_panic.shrOverflow;
28 pub const divideByZero = no_panic.divideByZero;
29 pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
30 pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
31 pub const corruptSwitch = no_panic.corruptSwitch;
32 pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
33 pub const invalidEnumValue = no_panic.invalidEnumValue;
34 pub const forLenMismatch = no_panic.forLenMismatch;
35 pub const copyLenMismatch = no_panic.copyLenMismatch;
36 pub const memcpyAlias = no_panic.memcpyAlias;
37 pub const noreturnReturned = no_panic.noreturnReturned;
38 pub const loadUninstantiableType = no_panic.loadUninstantiableType;
39};
40fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
41 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
42 stdout_writer.interface.print("third panic message: {s}\n", .{msg}) catch {};
43 std.process.exit(0);
44}
45const std = @import("std");
46const io = std.Io.Threaded.global_single_threaded.io();
test/incremental/change_panic_handler_explicit/manifest created+23
...@@ -0,0 +1,23 @@
1#exe {
2-Mroot=main.zig
3#}
4
5#write main.zig 0/main.zig
6#update
7#check stdout {
8panic message: integer overflow
9#}
10
11#write main.zig 1/main.zig
12#update {
13change the panic handler body#}
14#check stdout {
15new panic message: integer overflow
16#}
17
18#write main.zig 2/main.zig
19#update {
20change the panic handler function value#}
21#check stdout {
22third panic message: integer overflow
23#}
test/incremental/change_reify_struct_field_type+16-6
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{struct { tag: Enum }}, &.{.{}})) Enum {6fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{struct { tag: Enum }}, &.{.{}})) Enum {
4 return s.field.tag;7 return s.field.tag;
5}8}
...@@ -8,9 +11,12 @@ pub fn main(init: std.process.Init) !void {...@@ -8,9 +11,12 @@ pub fn main(init: std.process.Init) !void {
8}11}
9const Enum = enum { foo, bar };12const Enum = enum { foo, bar };
10const std = @import("std");13const std = @import("std");
11#expect_stdout="foo"14#}
12#update=change field type15#update
13#file=main.zig16#check stdout {
17foo#}
18
19#write main.zig {
14fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{Enum}, &.{.{}})) Enum {20fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{Enum}, &.{.{}})) Enum {
15 return s.field;21 return s.field;
16}22}
...@@ -19,4 +25,8 @@ pub fn main(init: std.process.Init) !void {...@@ -19,4 +25,8 @@ pub fn main(init: std.process.Init) !void {
19}25}
20const Enum = enum { foo, bar };26const Enum = enum { foo, bar };
21const std = @import("std");27const std = @import("std");
22#expect_stdout="bar"28#}
29#update {
30change field type#}
31#check stdout {
32bar#}
test/incremental/change_shift_op+18-6
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3pub fn main() !void {6pub fn main() !void {
4 try foo(0x1300);7 try foo(0x1300);
5}8}
...@@ -9,9 +12,13 @@ fn foo(x: u16) !void {...@@ -9,9 +12,13 @@ fn foo(x: u16) !void {
9}12}
10const std = @import("std");13const std = @import("std");
11const io = std.Io.Threaded.global_single_threaded.io();14const io = std.Io.Threaded.global_single_threaded.io();
12#expect_stdout="0x3000\n"15#}
13#update=change to right shift16#update
14#file=main.zig17#check stdout {
180x3000
19#}
20
21#write main.zig {
15pub fn main() !void {22pub fn main() !void {
16 try foo(0x1300);23 try foo(0x1300);
17}24}
...@@ -21,4 +28,9 @@ fn foo(x: u16) !void {...@@ -21,4 +28,9 @@ fn foo(x: u16) !void {
21}28}
22const std = @import("std");29const std = @import("std");
23const io = std.Io.Threaded.global_single_threaded.io();30const io = std.Io.Threaded.global_single_threaded.io();
24#expect_stdout="0x130\n"31#}
32#update {
33change to right shift#}
34#check stdout {
350x130
36#}
test/incremental/change_struct_same_fields+24-9
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const S = extern struct { x: u8, y: u8 };6const S = extern struct { x: u8, y: u8 };
4pub fn main() !void {7pub fn main() !void {
5 const val: S = .{ .x = 100, .y = 200 };8 const val: S = .{ .x = 100, .y = 200 };
...@@ -14,10 +17,13 @@ fn foo(val: *const S) !void {...@@ -14,10 +17,13 @@ fn foo(val: *const S) !void {
14}17}
15const std = @import("std");18const std = @import("std");
16const io = std.Io.Threaded.global_single_threaded.io();19const io = std.Io.Threaded.global_single_threaded.io();
17#expect_stdout="100 200\n"20#}
21#update
22#check stdout {
23100 200
24#}
1825
19#update=change struct layout26#write main.zig {
20#file=main.zig
21const S = extern struct { x: u32, y: u32 };27const S = extern struct { x: u32, y: u32 };
22pub fn main() !void {28pub fn main() !void {
23 const val: S = .{ .x = 100, .y = 200 };29 const val: S = .{ .x = 100, .y = 200 };
...@@ -32,10 +38,14 @@ fn foo(val: *const S) !void {...@@ -32,10 +38,14 @@ fn foo(val: *const S) !void {
32}38}
33const std = @import("std");39const std = @import("std");
34const io = std.Io.Threaded.global_single_threaded.io();40const io = std.Io.Threaded.global_single_threaded.io();
35#expect_stdout="100 200\n"41#}
42#update {
43change struct layout#}
44#check stdout {
45100 200
46#}
3647
37#update=change values48#write main.zig {
38#file=main.zig
39const S = extern struct { x: u32, y: u32 };49const S = extern struct { x: u32, y: u32 };
40pub fn main() !void {50pub fn main() !void {
41 const val: S = .{ .x = 1234, .y = 5678 };51 const val: S = .{ .x = 1234, .y = 5678 };
...@@ -50,4 +60,9 @@ fn foo(val: *const S) !void {...@@ -50,4 +60,9 @@ fn foo(val: *const S) !void {
50}60}
51const std = @import("std");61const std = @import("std");
52const io = std.Io.Threaded.global_single_threaded.io();62const io = std.Io.Threaded.global_single_threaded.io();
53#expect_stdout="1234 5678\n"63#}
64#update {
65change values#}
66#check stdout {
671234 5678
68#}
test/incremental/change_union_tag_type+25-10
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const A = enum(u8) { a };6const A = enum(u8) { a };
4const B = enum(u8) { b };7const B = enum(u8) { b };
5const Foo = union(A) { a: u8 };8const Foo = union(A) { a: u8 };
...@@ -9,10 +12,13 @@ pub fn main(init: std.process.Init) !void {...@@ -9,10 +12,13 @@ pub fn main(init: std.process.Init) !void {
9 try stdout_writer.interface.print("{s}\n", .{field_name});12 try stdout_writer.interface.print("{s}\n", .{field_name});
10}13}
11const std = @import("std");14const std = @import("std");
12#expect_stdout="a\n"15#}
16#update
17#check stdout {
18a
19#}
1320
14#update=change tag type21#write main.zig {
15#file=main.zig
16const A = enum(u8) { a };22const A = enum(u8) { a };
17const B = enum(u8) { b };23const B = enum(u8) { b };
18const Foo = union(B) { a: u8 };24const Foo = union(B) { a: u8 };
...@@ -22,11 +28,15 @@ pub fn main(init: std.process.Init) !void {...@@ -22,11 +28,15 @@ pub fn main(init: std.process.Init) !void {
22 try stdout_writer.interface.print("{s}\n", .{field_name});28 try stdout_writer.interface.print("{s}\n", .{field_name});
23}29}
24const std = @import("std");30const std = @import("std");
25#expect_error=main.zig:3:24: error: no field named 'a' in enum 'main.B'31#}
26#expect_error=main.zig:2:11: note: enum declared here32#update {
33change tag type#}
34#check errors {
35main.zig:3:24: error: no field named 'a' in enum 'main.B'
36main.zig:2:11: note: enum declared here
37#}
2738
28#update=change field name to match new tag type39#write main.zig {
29#file=main.zig
30const A = enum(u8) { a };40const A = enum(u8) { a };
31const B = enum(u8) { b };41const B = enum(u8) { b };
32const Foo = union(B) { b: u8 };42const Foo = union(B) { b: u8 };
...@@ -36,4 +46,9 @@ pub fn main(init: std.process.Init) !void {...@@ -36,4 +46,9 @@ pub fn main(init: std.process.Init) !void {
36 try stdout_writer.interface.print("{s}\n", .{field_name});46 try stdout_writer.interface.print("{s}\n", .{field_name});
37}47}
38const std = @import("std");48const std = @import("std");
39#expect_stdout="b\n"49#}
50#update {
51change field name to match new tag type#}
52#check stdout {
53b
54#}
test/incremental/change_zon_file+48-21
...@@ -1,47 +1,74 @@...@@ -1,47 +1,74 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4const message: []const u8 = @import("message.zon");7const message: []const u8 = @import("message.zon");
5pub fn main() !void {8pub fn main() !void {
6 try std.Io.File.stdout().writeStreamingAll(io, message);9 try std.Io.File.stdout().writeStreamingAll(io, message);
7}10}
8const io = std.Io.Threaded.global_single_threaded.io();11const io = std.Io.Threaded.global_single_threaded.io();
9#file=message.zon12#}
13#write message.zon {
10"Hello, World!\n"14"Hello, World!\n"
11#expect_stdout="Hello, World!\n"15#}
16#update
17#check stdout {
18Hello, World!
19#}
1220
13#update=change ZON file contents21#write message.zon {
14#file=message.zon
15"Hello again, World!\n"22"Hello again, World!\n"
16#expect_stdout="Hello again, World!\n"23#}
24#update {
25change ZON file contents#}
26#check stdout {
27Hello again, World!
28#}
1729
18#update=delete file30#delete message.zon
19#rm_file=message.zon31#update {
20#expect_error=message.zon:1:1: error: unable to load "message.zon": FileNotFound32delete file#}
21#expect_error=main.zig:2:37: note: file imported here33#check errors {
34message.zon:1:1: error: unable to load "message.zon": FileNotFound
35main.zig:2:37: note: file imported here
36#}
2237
23#update=remove reference to ZON file38#write main.zig {
24#file=main.zig
25const std = @import("std");39const std = @import("std");
26const message: []const u8 = @import("message.zon");40const message: []const u8 = @import("message.zon");
27pub fn main() !void {41pub fn main() !void {
28 try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");42 try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");
29}43}
30const io = std.Io.Threaded.global_single_threaded.io();44const io = std.Io.Threaded.global_single_threaded.io();
31#expect_error=message.zon:1:1: error: unable to load "message.zon": FileNotFound45#}
32#expect_error=main.zig:2:37: note: file imported here46#update {
47remove reference to ZON file#}
48#check errors {
49message.zon:1:1: error: unable to load "message.zon": FileNotFound
50main.zig:2:37: note: file imported here
51#}
3352
34#update=recreate ZON file53#write message.zon {
35#file=message.zon
36"We're back, World!\n"54"We're back, World!\n"
37#expect_stdout="a hardcoded string\n"55#}
56#update {
57recreate ZON file#}
58#check stdout {
59a hardcoded string
60#}
3861
39#update=re-introduce reference to ZON file62#write main.zig {
40#file=main.zig
41const std = @import("std");63const std = @import("std");
42const message: []const u8 = @import("message.zon");64const message: []const u8 = @import("message.zon");
43pub fn main() !void {65pub fn main() !void {
44 try std.Io.File.stdout().writeStreamingAll(io, message);66 try std.Io.File.stdout().writeStreamingAll(io, message);
45}67}
46const io = std.Io.Threaded.global_single_threaded.io();68const io = std.Io.Threaded.global_single_threaded.io();
47#expect_stdout="We're back, World!\n"69#}
70#update {
71re-introduce reference to ZON file#}
72#check stdout {
73We're back, World!
74#}
test/incremental/change_zon_file_no_result_type+19-7
...@@ -1,21 +1,33 @@...@@ -1,21 +1,33 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4const io = std.Io.Threaded.global_single_threaded.io();7const io = std.Io.Threaded.global_single_threaded.io();
5pub fn main() !void {8pub fn main() !void {
6 try std.Io.File.stdout().writeStreamingAll(io, @import("foo.zon").message);9 try std.Io.File.stdout().writeStreamingAll(io, @import("foo.zon").message);
7}10}
8#file=foo.zon11#}
12#write foo.zon {
9.{13.{
10 .message = "Hello, World!\n",14 .message = "Hello, World!\n",
11 .a_number = 0,15 .a_number = 0,
12}16}
13#expect_stdout="Hello, World!\n"17#}
18#update
19#check stdout {
20Hello, World!
21#}
1422
15#update=change ZON file23#write foo.zon {
16#file=foo.zon
17.{24.{
18 .message = "Hello again, World!\n",25 .message = "Hello again, World!\n",
19 .b_number = 0,26 .b_number = 0,
20}27}
21#expect_stdout="Hello again, World!\n"28#}
29#update {
30change ZON file#}
31#check stdout {
32Hello again, World!
33#}
test/incremental/compile_error_then_log+24-8
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version with compile error1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3pub fn main() void {}6pub fn main() void {}
4comptime {7comptime {
5 @compileError("this is an error");8 @compileError("this is an error");
...@@ -7,11 +10,17 @@ comptime {...@@ -7,11 +10,17 @@ comptime {
7comptime {10comptime {
8 @compileLog("this is a log");11 @compileLog("this is a log");
9}12}
10#expect_error=main.zig:3:5: error: this is an error13#}
11#expect_compile_log=@as(*const [13:0]u8, "this is a log")14#update {
15compile error#}
16#check errors {
17main.zig:3:5: error: this is an error
18
19Compile Log Output:
20@as(*const [13:0]u8, "this is a log")
21#}
1222
13#update=remove the compile error23#write main.zig {
14#file=main.zig
15pub fn main() void {}24pub fn main() void {}
16comptime {25comptime {
17 //@compileError("this is an error");26 //@compileError("this is an error");
...@@ -19,5 +28,12 @@ comptime {...@@ -19,5 +28,12 @@ comptime {
19comptime {28comptime {
20 @compileLog("this is a log");29 @compileLog("this is a log");
21}30}
22#expect_error=main.zig:6:5: error: found compile log statement31#}
23#expect_compile_log=@as(*const [13:0]u8, "this is a log")32#update {
33remove the compile error#}
34#check errors {
35main.zig:6:5: error: found compile log statement
36
37Compile Log Output:
38@as(*const [13:0]u8, "this is a log")
39#}
test/incremental/compile_log+28-10
...@@ -1,28 +1,46 @@...@@ -1,28 +1,46 @@
1#update=initial version with no compile log1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4pub fn main() !void {7pub fn main() !void {
5 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");8 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
6}9}
7const io = std.Io.Threaded.global_single_threaded.io();10const io = std.Io.Threaded.global_single_threaded.io();
8#expect_stdout="Hello, World!\n"11#}
12#update {
13no compile log#}
14#check stdout {
15Hello, World!
16#}
917
10#update=add compile log18#write main.zig {
11#file=main.zig
12const std = @import("std");19const std = @import("std");
13pub fn main() !void {20pub fn main() !void {
14 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");21 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
15 @compileLog("this is a log");22 @compileLog("this is a log");
16}23}
17const io = std.Io.Threaded.global_single_threaded.io();24const io = std.Io.Threaded.global_single_threaded.io();
18#expect_error=main.zig:4:5: error: found compile log statement25#}
19#expect_compile_log=@as(*const [13:0]u8, "this is a log")26#update {
27add compile log#}
28#check errors {
29main.zig:4:5: error: found compile log statement
30
31Compile Log Output:
32@as(*const [13:0]u8, "this is a log")
33#}
2034
21#update=remove compile log35#write main.zig {
22#file=main.zig
23const std = @import("std");36const std = @import("std");
24pub fn main() !void {37pub fn main() !void {
25 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");38 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
26}39}
27const io = std.Io.Threaded.global_single_threaded.io();40const io = std.Io.Threaded.global_single_threaded.io();
28#expect_stdout="Hello, World!\n"41#}
42#update {
43remove compile log#}
44#check stdout {
45Hello, World!
46#}
test/incremental/delete_comptime_decls+20-9
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3pub fn main() void {}6pub fn main() void {}
4comptime {7comptime {
5 var array = [_:0]u8{ 1, 2, 3, 4 };8 var array = [_:0]u8{ 1, 2, 3, 4 };
...@@ -22,13 +25,16 @@ comptime {...@@ -22,13 +25,16 @@ comptime {
22 const slice = array[3..2];25 const slice = array[3..2];
23 _ = slice;26 _ = slice;
24}27}
25#expect_error=main.zig:5:32: error: end index 6 out of bounds for slice of length 4 +1 (sentinel)28#}
26#expect_error=main.zig:10:28: error: end index 6 out of bounds for array of length 4 +1 (sentinel)29#update
27#expect_error=main.zig:15:28: error: end index 5 out of bounds for array of length 430#check errors {
28#expect_error=main.zig:20:25: error: start index 3 is larger than end index 231main.zig:5:32: error: end index 6 out of bounds for slice of length 4 +1 (sentinel)
32main.zig:10:28: error: end index 6 out of bounds for array of length 4 +1 (sentinel)
33main.zig:15:28: error: end index 5 out of bounds for array of length 4
34main.zig:20:25: error: start index 3 is larger than end index 2
35#}
2936
30#update=delete and modify comptime decls37#write main.zig {
31#file=main.zig
32pub fn main() void {}38pub fn main() void {}
33comptime {39comptime {
34 const x: [*c]u8 = null;40 const x: [*c]u8 = null;
...@@ -37,4 +43,9 @@ comptime {...@@ -37,4 +43,9 @@ comptime {
37 const y = x[0..runtime_len];43 const y = x[0..runtime_len];
38 _ = y;44 _ = y;
39}45}
40#expect_error=main.zig:6:16: error: slice of null pointer46#}
47#update {
48delete and modify comptime decls#}
49#check errors {
50main.zig:6:16: error: slice of null pointer
51#}
test/incremental/dependency_on_type_of_inferred_global+17-6
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const foo = @as(u8, 123);6const foo = @as(u8, 123);
4comptime {7comptime {
5 // depends on value of `foo`8 // depends on value of `foo`
...@@ -10,9 +13,12 @@ comptime {...@@ -10,9 +13,12 @@ comptime {
10 if (@TypeOf(&foo) != *const u8) unreachable;13 if (@TypeOf(&foo) != *const u8) unreachable;
11}14}
12pub fn main() void {}15pub fn main() void {}
13#expect_stdout=""16#}
14#update=change the type17#update
15#file=main.zig18#check stdout {
19#}
20
21#write main.zig {
16const foo = @as(u16, 123);22const foo = @as(u16, 123);
17comptime {23comptime {
18 // depends on value of `foo`24 // depends on value of `foo`
...@@ -23,4 +29,9 @@ comptime {...@@ -23,4 +29,9 @@ comptime {
23 if (@TypeOf(&foo) != *const u8) unreachable;29 if (@TypeOf(&foo) != *const u8) unreachable;
24}30}
25pub fn main() void {}31pub fn main() void {}
26#expect_error=main.zig:8:37: error: reached unreachable code32#}
33#update {
34change the type#}
35#check errors {
36main.zig:8:37: error: reached unreachable code
37#}
test/incremental/do_nothing+19-7
...@@ -1,6 +1,11 @@...@@ -1,6 +1,11 @@
1// TODO: it'd be great if we could actually check that no analysis happened!1#todo {
2#update=initial version2it'd be great if we could actually check that no analysis happened!
3#file=main.zig3#}
4#exe {
5-Mroot=main.zig
6#}
7
8#write main.zig {
4pub fn main() void {9pub fn main() void {
5 const ptr: *const O = @ptrFromInt(0x1000);10 const ptr: *const O = @ptrFromInt(0x1000);
6 _ = ptr;11 _ = ptr;
...@@ -18,9 +23,12 @@ const O = opaque {...@@ -18,9 +23,12 @@ const O = opaque {
18 _ = wrapper;23 _ = wrapper;
19 }24 }
20};25};
21#expect_stdout=""26#}
22#update=do literally nothing27#update
23#file=main.zig28#check stdout {
29#}
30
31#write main.zig {
24pub fn main() void {32pub fn main() void {
25 const ptr: *const O = @ptrFromInt(0x1000);33 const ptr: *const O = @ptrFromInt(0x1000);
26 _ = ptr;34 _ = ptr;
...@@ -38,4 +46,8 @@ const O = opaque {...@@ -38,4 +46,8 @@ const O = opaque {
38 _ = wrapper;46 _ = wrapper;
39 }47 }
40};48};
41#expect_stdout=""49#}
50#update {
51do literally nothing#}
52#check stdout {
53#}
test/incremental/fix_astgen_failure+37-13
...@@ -1,35 +1,59 @@...@@ -1,35 +1,59 @@
1#update=initial version with error1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3pub fn main() !void {6pub fn main() !void {
4 try @import("foo.zig").hello();7 try @import("foo.zig").hello();
5}8}
6#file=foo.zig9#}
10#write foo.zig {
7pub fn hello() !void {11pub fn hello() !void {
8 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");12 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
9}13}
10#expect_error=foo.zig:2:9: error: use of undeclared identifier 'std'14#}
11#update=fix the error15#update {
12#file=foo.zig16error#}
17#check errors {
18foo.zig:2:9: error: use of undeclared identifier 'std'
19#}
20
21#write foo.zig {
13const std = @import("std");22const std = @import("std");
14pub fn hello() !void {23pub fn hello() !void {
15 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");24 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
16}25}
17const io = std.Io.Threaded.global_single_threaded.io();26const io = std.Io.Threaded.global_single_threaded.io();
18#expect_stdout="Hello, World!\n"27#}
19#update=add new error28#update {
20#file=foo.zig29fix the error#}
30#check stdout {
31Hello, World!
32#}
33
34#write foo.zig {
21const std = @import("std");35const std = @import("std");
22pub fn hello() !void {36pub fn hello() !void {
23 try std.Io.File.stdout().writeStreamingAll(io, hello_str);37 try std.Io.File.stdout().writeStreamingAll(io, hello_str);
24}38}
25const io = std.Io.Threaded.global_single_threaded.io();39const io = std.Io.Threaded.global_single_threaded.io();
26#expect_error=foo.zig:3:52: error: use of undeclared identifier 'hello_str'40#}
27#update=fix the new error41#update {
28#file=foo.zig42add new error#}
43#check errors {
44foo.zig:3:52: error: use of undeclared identifier 'hello_str'
45#}
46
47#write foo.zig {
29const std = @import("std");48const std = @import("std");
30const hello_str = "Hello, World! Again!\n";49const hello_str = "Hello, World! Again!\n";
31pub fn hello() !void {50pub fn hello() !void {
32 try std.Io.File.stdout().writeStreamingAll(io, hello_str);51 try std.Io.File.stdout().writeStreamingAll(io, hello_str);
33}52}
34const io = std.Io.Threaded.global_single_threaded.io();53const io = std.Io.Threaded.global_single_threaded.io();
35#expect_stdout="Hello, World! Again!\n"54#}
55#update {
56fix the new error#}
57#check stdout {
58Hello, World! Again!
59#}
test/incremental/function_becomes_inline+25-9
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=non-inline version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3pub fn main() !void {6pub fn main() !void {
4 try foo();7 try foo();
5}8}
...@@ -8,10 +11,14 @@ fn foo() !void {...@@ -8,10 +11,14 @@ fn foo() !void {
8}11}
9const std = @import("std");12const std = @import("std");
10const io = std.Io.Threaded.global_single_threaded.io();13const io = std.Io.Threaded.global_single_threaded.io();
11#expect_stdout="Hello, World!\n"14#}
15#update {
16non-inline version#}
17#check stdout {
18Hello, World!
19#}
1220
13#update=make function inline21#write main.zig {
14#file=main.zig
15pub fn main() !void {22pub fn main() !void {
16 try foo();23 try foo();
17}24}
...@@ -20,10 +27,14 @@ inline fn foo() !void {...@@ -20,10 +27,14 @@ inline fn foo() !void {
20}27}
21const std = @import("std");28const std = @import("std");
22const io = std.Io.Threaded.global_single_threaded.io();29const io = std.Io.Threaded.global_single_threaded.io();
23#expect_stdout="Hello, World!\n"30#}
31#update {
32make function inline#}
33#check stdout {
34Hello, World!
35#}
2436
25#update=change string37#write main.zig {
26#file=main.zig
27pub fn main() !void {38pub fn main() !void {
28 try foo();39 try foo();
29}40}
...@@ -32,4 +43,9 @@ inline fn foo() !void {...@@ -32,4 +43,9 @@ inline fn foo() !void {
32}43}
33const std = @import("std");44const std = @import("std");
34const io = std.Io.Threaded.global_single_threaded.io();45const io = std.Io.Threaded.global_single_threaded.io();
35#expect_stdout="Hello, `inline` World!\n"46#}
47#update {
48change string#}
49#check stdout {
50Hello, `inline` World!
51#}
test/incremental/hello+18-6
...@@ -1,16 +1,28 @@...@@ -1,16 +1,28 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4const io = std.Io.Threaded.global_single_threaded.io();7const io = std.Io.Threaded.global_single_threaded.io();
5pub fn main() !void {8pub fn main() !void {
6 try std.Io.File.stdout().writeStreamingAll(io, "good morning\n");9 try std.Io.File.stdout().writeStreamingAll(io, "good morning\n");
7}10}
8#expect_stdout="good morning\n"11#}
9#update=change the string12#update
10#file=main.zig13#check stdout {
14good morning
15#}
16
17#write main.zig {
11const std = @import("std");18const std = @import("std");
12const io = std.Io.Threaded.global_single_threaded.io();19const io = std.Io.Threaded.global_single_threaded.io();
13pub fn main() !void {20pub fn main() !void {
14 try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n");21 try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n");
15}22}
16#expect_stdout="おはようございます\n"23#}
24#update {
25change the string#}
26#check stdout {
27おはようございます
28#}
test/incremental/increase_array_field_length+17-6
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const Big = struct { arr: [10]u8 };6const Big = struct { arr: [10]u8 };
4pub fn main(init: std.process.Init) !void {7pub fn main(init: std.process.Init) !void {
5 var big: Big = undefined;8 var big: Big = undefined;
...@@ -12,10 +15,13 @@ pub fn main(init: std.process.Init) !void {...@@ -12,10 +15,13 @@ pub fn main(init: std.process.Init) !void {
12 };15 };
13}16}
14const std = @import("std");17const std = @import("std");
15#expect_stdout="arr[9] = 234\n"18#}
19#update
20#check stdout {
21arr[9] = 234
22#}
1623
17#update=increase array length24#write main.zig {
18#file=main.zig
19const Big = struct { arr: [1000]u8 };25const Big = struct { arr: [1000]u8 };
20pub fn main(init: std.process.Init) !void {26pub fn main(init: std.process.Init) !void {
21 var big: Big = undefined;27 var big: Big = undefined;
...@@ -28,4 +34,9 @@ pub fn main(init: std.process.Init) !void {...@@ -28,4 +34,9 @@ pub fn main(init: std.process.Init) !void {
28 };34 };
29}35}
30const std = @import("std");36const std = @import("std");
31#expect_stdout="arr[999] = 234\n"37#}
38#update {
39increase array length#}
40#check stdout {
41arr[999] = 234
42#}
test/incremental/make_decl_pub+20-8
...@@ -1,23 +1,35 @@...@@ -1,23 +1,35 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const foo = @import("foo.zig");6const foo = @import("foo.zig");
4pub fn main() !void {7pub fn main() !void {
5 try foo.hello();8 try foo.hello();
6}9}
7#file=foo.zig10#}
11#write foo.zig {
8const std = @import("std");12const std = @import("std");
9fn hello() !void {13fn hello() !void {
10 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");14 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
11}15}
12const io = std.Io.Threaded.global_single_threaded.io();16const io = std.Io.Threaded.global_single_threaded.io();
13#expect_error=main.zig:3:12: error: 'hello' is not marked 'pub'17#}
14#expect_error=foo.zig:2:1: note: declared here18#update
19#check errors {
20main.zig:3:12: error: 'hello' is not marked 'pub'
21foo.zig:2:1: note: declared here
22#}
1523
16#update=make hello pub24#write foo.zig {
17#file=foo.zig
18const std = @import("std");25const std = @import("std");
19pub fn hello() !void {26pub fn hello() !void {
20 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");27 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
21}28}
22const io = std.Io.Threaded.global_single_threaded.io();29const io = std.Io.Threaded.global_single_threaded.io();
23#expect_stdout="Hello, World!\n"30#}
31#update {
32make hello pub#}
33#check stdout {
34Hello, World!
35#}
test/incremental/modify_inline_fn+18-6
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4pub fn main() !void {7pub fn main() !void {
5 const str = getStr();8 const str = getStr();
...@@ -9,9 +12,13 @@ inline fn getStr() []const u8 {...@@ -9,9 +12,13 @@ inline fn getStr() []const u8 {
9 return "foo\n";12 return "foo\n";
10}13}
11const io = std.Io.Threaded.global_single_threaded.io();14const io = std.Io.Threaded.global_single_threaded.io();
12#expect_stdout="foo\n"15#}
13#update=change the string16#update
14#file=main.zig17#check stdout {
18foo
19#}
20
21#write main.zig {
15const std = @import("std");22const std = @import("std");
16pub fn main() !void {23pub fn main() !void {
17 const str = getStr();24 const str = getStr();
...@@ -21,4 +28,9 @@ inline fn getStr() []const u8 {...@@ -21,4 +28,9 @@ inline fn getStr() []const u8 {
21 return "bar\n";28 return "bar\n";
22}29}
23const io = std.Io.Threaded.global_single_threaded.io();30const io = std.Io.Threaded.global_single_threaded.io();
24#expect_stdout="bar\n"31#}
32#update {
33change the string#}
34#check stdout {
35bar
36#}
test/incremental/move_src+17-6
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4pub fn main() !void {7pub fn main() !void {
5 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});8 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
...@@ -12,10 +15,13 @@ fn bar() u32 {...@@ -12,10 +15,13 @@ fn bar() u32 {
12 return 123;15 return 123;
13}16}
14const io = std.Io.Threaded.global_single_threaded.io();17const io = std.Io.Threaded.global_single_threaded.io();
15#expect_stdout="7 123\n"18#}
19#update
20#check stdout {
217 123
22#}
1623
17#update=add newline24#write main.zig {
18#file=main.zig
19const std = @import("std");25const std = @import("std");
20pub fn main() !void {26pub fn main() !void {
21 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});27 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
...@@ -29,4 +35,9 @@ fn bar() u32 {...@@ -29,4 +35,9 @@ fn bar() u32 {
29 return 123;35 return 123;
30}36}
31const io = std.Io.Threaded.global_single_threaded.io();37const io = std.Io.Threaded.global_single_threaded.io();
32#expect_stdout="8 123\n"38#}
39#update {
40add newline#}
41#check stdout {
428 123
43#}
test/incremental/pointer_to_decl_with_astgen_error+22-9
...@@ -1,23 +1,36 @@...@@ -1,23 +1,36 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const foo = {};6const foo = {};
4pub fn main() void {7pub fn main() void {
5 _ = &foo;8 _ = &foo;
6}9}
7#expect_stdout=""10#}
11#update
12#check stdout {
13#}
814
9#update=introduce use of undeclared identifier15#write main.zig {
10#file=main.zig
11const foo = something;16const foo = something;
12pub fn main() void {17pub fn main() void {
13 _ = &foo;18 _ = &foo;
14}19}
15#expect_error=main.zig:1:13: error: use of undeclared identifier 'something'20#}
21#update {
22introduce use of undeclared identifier#}
23#check errors {
24main.zig:1:13: error: use of undeclared identifier 'something'
25#}
1626
17#update=revert use of undeclared identifier27#write main.zig {
18#file=main.zig
19const foo = {};28const foo = {};
20pub fn main() void {29pub fn main() void {
21 _ = &foo;30 _ = &foo;
22}31}
23#expect_stdout=""32#}
33#update {
34revert use of undeclared identifier#}
35#check stdout {
36#}
test/incremental/recursive_function_becomes_non_recursive+17-6
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3pub fn main() !void {6pub fn main() !void {
4 try foo(false);7 try foo(false);
5}8}
...@@ -10,10 +13,13 @@ fn foo(recurse: bool) !void {...@@ -10,10 +13,13 @@ fn foo(recurse: bool) !void {
10}13}
11const std = @import("std");14const std = @import("std");
12const io = std.Io.Threaded.global_single_threaded.io();15const io = std.Io.Threaded.global_single_threaded.io();
13#expect_stdout="non-recursive path\n"16#}
17#update
18#check stdout {
19non-recursive path
20#}
1421
15#update=eliminate recursion and change argument22#write main.zig {
16#file=main.zig
17pub fn main() !void {23pub fn main() !void {
18 try foo(true);24 try foo(true);
19}25}
...@@ -24,4 +30,9 @@ fn foo(recurse: bool) !void {...@@ -24,4 +30,9 @@ fn foo(recurse: bool) !void {
24}30}
25const std = @import("std");31const std = @import("std");
26const io = std.Io.Threaded.global_single_threaded.io();32const io = std.Io.Threaded.global_single_threaded.io();
27#expect_stdout="x==1\n"33#}
34#update {
35eliminate recursion and change argument#}
36#check stdout {
37x==1
38#}
test/incremental/remove_enum_field+21-9
...@@ -1,27 +1,39 @@...@@ -1,27 +1,39 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const MyEnum = enum(u8) {6const MyEnum = enum(u8) {
4 foo = 1,7 foo = 1,
5 bar = 2,8 bar = 2,
6};9};
7pub fn main() !void {10pub fn main() !void {
8 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});11 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
9 try stdout_writer.interface.print("{}\n", .{@intFromEnum(MyEnum.foo)});12 try stdout_writer.interface.print("{}\n", .{@backingInt(MyEnum.foo)});
10}13}
11const std = @import("std");14const std = @import("std");
12const io = std.Io.Threaded.global_single_threaded.io();15const io = std.Io.Threaded.global_single_threaded.io();
13#expect_stdout="1\n"16#}
14#update=remove enum field17#update
15#file=main.zig18#check stdout {
191
20#}
21
22#write main.zig {
16const MyEnum = enum(u8) {23const MyEnum = enum(u8) {
17 //foo = 1,24 //foo = 1,
18 bar = 2,25 bar = 2,
19};26};
20pub fn main() !void {27pub fn main() !void {
21 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});28 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
22 try stdout_writer.interface.print("{}\n", .{@intFromEnum(MyEnum.foo)});29 try stdout_writer.interface.print("{}\n", .{@backingInt(MyEnum.foo)});
23}30}
24const std = @import("std");31const std = @import("std");
25const io = std.Io.Threaded.global_single_threaded.io();32const io = std.Io.Threaded.global_single_threaded.io();
26#expect_error=main.zig:7:69: error: enum 'main.MyEnum' has no member named 'foo'33#}
27#expect_error=main.zig:1:16: note: enum declared here34#update {
35remove enum field#}
36#check errors {
37main.zig:7:68: error: enum 'main.MyEnum' has no member named 'foo'
38main.zig:1:16: note: enum declared here
39#}
test/incremental/remove_function_with_changed_callee+16-6
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4const io = std.Io.Threaded.global_single_threaded.io();7const io = std.Io.Threaded.global_single_threaded.io();
58
...@@ -23,9 +26,12 @@ fn bar(a: A) !void {...@@ -23,9 +26,12 @@ fn bar(a: A) !void {
23pub fn main() !void {26pub fn main() !void {
24 try foo();27 try foo();
25}28}
26#expect_stdout="0"29#}
27#update=remove foo and change bar wasm function type30#update
28#file=main.zig31#check stdout {
320#}
33
34#write main.zig {
29//! This update must preserve `bar` `InternPool.Index` value, while changing its wasm function type.35//! This update must preserve `bar` `InternPool.Index` value, while changing its wasm function type.
30//! If `foo` code is preserved in the binary without any changes, wasm type checking will fail.36//! If `foo` code is preserved in the binary without any changes, wasm type checking will fail.
31const std = @import("std");37const std = @import("std");
...@@ -47,4 +53,8 @@ fn bar(a: A) !void {...@@ -47,4 +53,8 @@ fn bar(a: A) !void {
47pub fn main() !void {53pub fn main() !void {
48 try bar(.one);54 try bar(.one);
49}55}
50#expect_stdout="1"56#}
57#update {
58remove foo and change bar wasm function type#}
59#check stdout {
601#}
test/incremental/remove_invalid_union_backing_enum+18-7
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const E = enum { a, b, c };6const E = enum { a, b, c };
4const U = union(E) {7const U = union(E) {
5 a: i32,8 a: i32,
...@@ -11,10 +14,14 @@ pub fn main() void {...@@ -11,10 +14,14 @@ pub fn main() void {
11 const u: U = .{ .a = 123 };14 const u: U = .{ .a = 123 };
12 _ = u;15 _ = u;
13}16}
14#expect_error=main.zig:6:5: error: no field named 'd' in enum 'main.E'17#}
15#expect_error=main.zig:1:11: note: enum declared here18#update
16#update=remove invalid backing enum19#check errors {
17#file=main.zig20main.zig:6:5: error: no field named 'd' in enum 'main.E'
21main.zig:1:11: note: enum declared here
22#}
23
24#write main.zig {
18const U = union {25const U = union {
19 a: i32,26 a: i32,
20 b: f64,27 b: f64,
...@@ -25,4 +32,8 @@ pub fn main() void {...@@ -25,4 +32,8 @@ pub fn main() void {
25 const u: U = .{ .a = 123 };32 const u: U = .{ .a = 123 };
26 _ = u;33 _ = u;
27}34}
28#expect_stdout=""35#}
36#update {
37remove invalid backing enum#}
38#check stdout {
39#}
test/incremental/struct_reification_becomes_anon_init+17-6
...@@ -1,19 +1,30 @@...@@ -1,19 +1,30 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const Foo = @Struct(.auto, null, &.{"reified_field"}, &.{void}, &.{.{}});6const Foo = @Struct(.auto, null, &.{"reified_field"}, &.{void}, &.{.{}});
4pub fn main(init: std.process.Init) !void {7pub fn main(init: std.process.Init) !void {
5 const field_name = @typeInfo(Foo).@"struct".field_names[0];8 const field_name = @typeInfo(Foo).@"struct".field_names[0];
6 try std.Io.File.stdout().writeStreamingAll(init.io, field_name ++ "\n");9 try std.Io.File.stdout().writeStreamingAll(init.io, field_name ++ "\n");
7}10}
8const std = @import("std");11const std = @import("std");
9#expect_stdout="reified_field\n"12#}
13#update
14#check stdout {
15reified_field
16#}
1017
11#update=change to `@TypeOf` anonymous init18#write main.zig {
12#file=main.zig
13const Foo = @TypeOf(.{ .anon_field = 123 });19const Foo = @TypeOf(.{ .anon_field = 123 });
14pub fn main(init: std.process.Init) !void {20pub fn main(init: std.process.Init) !void {
15 const field_name = @typeInfo(Foo).@"struct".field_names[0];21 const field_name = @typeInfo(Foo).@"struct".field_names[0];
16 try std.Io.File.stdout().writeStreamingAll(init.io, field_name ++ "\n");22 try std.Io.File.stdout().writeStreamingAll(init.io, field_name ++ "\n");
17}23}
18const std = @import("std");24const std = @import("std");
19#expect_stdout="anon_field\n"25#}
26#update {
27change to `@TypeOf` anonymous init#}
28#check stdout {
29anon_field
30#}
test/incremental/tag_name+23-9
...@@ -1,27 +1,41 @@...@@ -1,27 +1,41 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4var some_enum: enum { first, second } = .first;7var some_enum: enum { first, second } = .first;
5const io = std.Io.Threaded.global_single_threaded.io();8const io = std.Io.Threaded.global_single_threaded.io();
6pub fn main() !void {9pub fn main() !void {
7 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));10 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
8}11}
9#expect_stdout="first"12#}
10#update=no change13#update
11#file=main.zig14#check stdout {
15first#}
16
17#write main.zig {
12const std = @import("std");18const std = @import("std");
13var some_enum: enum { first, second } = .first;19var some_enum: enum { first, second } = .first;
14const io = std.Io.Threaded.global_single_threaded.io();20const io = std.Io.Threaded.global_single_threaded.io();
15pub fn main() !void {21pub fn main() !void {
16 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));22 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
17}23}
18#expect_stdout="first"24#}
19#update=swap fields25#update {
20#file=main.zig26no change#}
27#check stdout {
28first#}
29
30#write main.zig {
21const std = @import("std");31const std = @import("std");
22var some_enum: enum { second, first } = .first;32var some_enum: enum { second, first } = .first;
23const io = std.Io.Threaded.global_single_threaded.io();33const io = std.Io.Threaded.global_single_threaded.io();
24pub fn main() !void {34pub fn main() !void {
25 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));35 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
26}36}
27#expect_stdout="first"37#}
38#update {
39swap fields#}
40#check stdout {
41first#}
test/incremental/temporary_analysis_error_in_generic_signature+25-10
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3//! The original repro here depends on re-analysis order, which depends on6//! The original repro here depends on re-analysis order, which depends on
4//! declaration order, so this exact declaration order must be used.7//! declaration order, so this exact declaration order must be used.
5const Foo = struct { x: u8 };8const Foo = struct { x: u8 };
...@@ -11,10 +14,13 @@ fn bar(comptime x: u8) @This().Foo {...@@ -11,10 +14,13 @@ fn bar(comptime x: u8) @This().Foo {
11 return .{ .x = x };14 return .{ .x = x };
12}15}
13const std = @import("std");16const std = @import("std");
14#expect_stdout="Z\n"17#}
18#update
19#check stdout {
20Z
21#}
1522
16#update=change generic signature to use non-existent member23#write main.zig {
17#file=main.zig
18//! The original repro here depends on re-analysis order, which depends on24//! The original repro here depends on re-analysis order, which depends on
19//! declaration order, so this exact declaration order must be used.25//! declaration order, so this exact declaration order must be used.
20const Foo = struct { x: u8 };26const Foo = struct { x: u8 };
...@@ -26,11 +32,15 @@ fn bar(comptime x: u8) @This().FooAlias {...@@ -26,11 +32,15 @@ fn bar(comptime x: u8) @This().FooAlias {
26 return .{ .x = x };32 return .{ .x = x };
27}33}
28const std = @import("std");34const std = @import("std");
29#expect_error=main.zig:8:31: error: root source file struct 'main' has no member named 'FooAlias'35#}
30#expect_error=main.zig:1:1: note: struct declared here36#update {
37change generic signature to use non-existent member#}
38#check errors {
39main.zig:8:31: error: root source file struct 'main' has no member named 'FooAlias'
40main.zig:1:1: note: struct declared here
41#}
3142
32#update=add that member, fixing the error43#write main.zig {
33#file=main.zig
34//! The original repro here depends on re-analysis order, which depends on44//! The original repro here depends on re-analysis order, which depends on
35//! declaration order, so this exact declaration order must be used.45//! declaration order, so this exact declaration order must be used.
36const Foo = struct { x: u8 };46const Foo = struct { x: u8 };
...@@ -43,4 +53,9 @@ fn bar(comptime x: u8) @This().FooAlias {...@@ -43,4 +53,9 @@ fn bar(comptime x: u8) @This().FooAlias {
43 return .{ .x = x };53 return .{ .x = x };
44}54}
45const std = @import("std");55const std = @import("std");
46#expect_stdout="Z\n"56#}
57#update {
58add that member, fixing the error#}
59#check stdout {
60Z
61#}
test/incremental/temporary_parse_error+22-9
...@@ -1,15 +1,28 @@...@@ -1,15 +1,28 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4pub fn main() !void {}7pub fn main() !void {}
5#expect_stdout=""8#}
9#update
10#check stdout {
11#}
612
7#update=introduce parse error13#write main.zig {
8#file=main.zig
9pub fn main() !void {14pub fn main() !void {
10#expect_error=main.zig:2:1: error: expected statement, found 'EOF'15#}
16#update {
17introduce parse error#}
18#check errors {
19main.zig:2:1: error: expected statement, found 'EOF'
20#}
1121
12#update=fix parse error22#write main.zig {
13#file=main.zig
14pub fn main() !void {}23pub fn main() !void {}
15#expect_stdout=""24#}
25#update {
26fix parse error#}
27#check stdout {
28#}
test/incremental/type_becomes_comptime_only+21-9
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const SomeType = u32;6const SomeType = u32;
4const S = struct {7const S = struct {
5 x: SomeType,8 x: SomeType,
...@@ -9,10 +12,12 @@ pub fn main() void {...@@ -9,10 +12,12 @@ pub fn main() void {
9 const s: S = .{ .x = 456 };12 const s: S = .{ .x = 456 };
10 s.foo();13 s.foo();
11}14}
12#expect_stdout=""15#}
16#update
17#check stdout {
18#}
1319
14#update=make S comptime-only20#write main.zig {
15#file=main.zig
16const SomeType = comptime_int;21const SomeType = comptime_int;
17const S = struct {22const S = struct {
18 x: SomeType,23 x: SomeType,
...@@ -22,10 +27,13 @@ pub fn main() void {...@@ -22,10 +27,13 @@ pub fn main() void {
22 const s: S = .{ .x = 456 };27 const s: S = .{ .x = 456 };
23 s.foo();28 s.foo();
24}29}
25#expect_stdout=""30#}
31#update {
32make S comptime-only#}
33#check stdout {
34#}
2635
27#update=make S runtime again36#write main.zig {
28#file=main.zig
29const SomeType = u16;37const SomeType = u16;
30const S = struct {38const S = struct {
31 x: SomeType,39 x: SomeType,
...@@ -35,4 +43,8 @@ pub fn main() void {...@@ -35,4 +43,8 @@ pub fn main() void {
35 const s: S = .{ .x = 456 };43 const s: S = .{ .x = 456 };
36 s.foo();44 s.foo();
37}45}
38#expect_stdout=""46#}
47#update {
48make S runtime again#}
49#check stdout {
50#}
test/incremental/type_dependency_loop+41-21
...@@ -1,50 +1,70 @@...@@ -1,50 +1,70 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3pub const A = struct { b: B };6pub const A = struct { b: B };
4pub const B = struct { a: A };7pub const B = struct { a: A };
5pub fn main() void {8pub fn main() void {
6 _ = @as(B, undefined);9 _ = @as(B, undefined);
7}10}
8#expect_error=:error: dependency loop with length 211#}
9#expect_error=main.zig:2:27: note: type 'main.B' depends on type 'main.A' for field declared here12#update
10#expect_error=main.zig:1:27: note: type 'main.A' depends on type 'main.B' for field declared here13#check errors {
11#expect_error=:note: eliminate any one of these dependencies to break the loop14error: dependency loop with length 2
15 main.zig:2:27: note: type 'main.B' depends on type 'main.A' for field declared here
16 main.zig:1:27: note: type 'main.A' depends on type 'main.B' for field declared here
17 note: eliminate any one of these dependencies to break the loop
18#}
1219
13#update=remove reference to dependency loop20#write main.zig {
14#file=main.zig
15pub const A = struct { b: B };21pub const A = struct { b: B };
16pub const B = struct { a: A };22pub const B = struct { a: A };
17pub fn main() void {23pub fn main() void {
18 _ = B;24 _ = B;
19}25}
20#expect_stdout=""26#}
27#update {
28remove reference to dependency loop#}
29#check stdout {
30#}
2131
22#update=change dependency loop without fixing it32#write main.zig {
23#file=main.zig
24pub const A = struct { b: B };33pub const A = struct { b: B };
25pub const B = struct { a: *align(@alignOf(A)) A };34pub const B = struct { a: *align(@alignOf(A)) A };
26pub fn main() void {35pub fn main() void {
27 _ = B;36 _ = B;
28}37}
29#expect_stdout=""38#}
39#update {
40change dependency loop without fixing it#}
41#check stdout {
42#}
3043
31#update=reference dependency loop again44#write main.zig {
32#file=main.zig
33pub const A = struct { b: B };45pub const A = struct { b: B };
34pub const B = struct { a: *align(@alignOf(A)) A };46pub const B = struct { a: *align(@alignOf(A)) A };
35pub fn main() void {47pub fn main() void {
36 _ = @as(B, undefined);48 _ = @as(B, undefined);
37}49}
38#expect_error=:error: dependency loop with length 250#}
39#expect_error=main.zig:2:43: note: type 'main.B' depends on type 'main.A' for alignment query here51#update {
40#expect_error=main.zig:1:27: note: type 'main.A' depends on type 'main.B' for field declared here52reference dependency loop again#}
41#expect_error=:note: eliminate any one of these dependencies to break the loop53#check errors {
54error: dependency loop with length 2
55 main.zig:2:43: note: type 'main.B' depends on type 'main.A' for alignment query here
56 main.zig:1:27: note: type 'main.A' depends on type 'main.B' for field declared here
57 note: eliminate any one of these dependencies to break the loop
58#}
4259
43#update=fix dependency loop60#write main.zig {
44#file=main.zig
45pub const A = struct { b: B };61pub const A = struct { b: B };
46pub const B = struct { a: *A };62pub const B = struct { a: *A };
47pub fn main() void {63pub fn main() void {
48 _ = @as(B, undefined);64 _ = @as(B, undefined);
49}65}
50#expect_stdout=""66#}
67#update {
68fix dependency loop#}
69#check stdout {
70#}
test/incremental/unreferenced_error+31-12
...@@ -1,25 +1,35 @@...@@ -1,25 +1,35 @@
1#update=initial version1#exe {
2#file=main.zig2-Mroot=main.zig
3#}
4
5#write main.zig {
3const std = @import("std");6const std = @import("std");
4pub fn main() !void {7pub fn main() !void {
5 try std.Io.File.stdout().writeStreamingAll(io, a);8 try std.Io.File.stdout().writeStreamingAll(io, a);
6}9}
7const a = "Hello, World!\n";10const a = "Hello, World!\n";
8const io = std.Io.Threaded.global_single_threaded.io();11const io = std.Io.Threaded.global_single_threaded.io();
9#expect_stdout="Hello, World!\n"12#}
13#update
14#check stdout {
15Hello, World!
16#}
1017
11#update=introduce compile error18#write main.zig {
12#file=main.zig
13const std = @import("std");19const std = @import("std");
14pub fn main() !void {20pub fn main() !void {
15 try std.Io.File.stdout().writeStreamingAll(io, a);21 try std.Io.File.stdout().writeStreamingAll(io, a);
16}22}
17const a = @compileError("bad a");23const a = @compileError("bad a");
18const io = std.Io.Threaded.global_single_threaded.io();24const io = std.Io.Threaded.global_single_threaded.io();
19#expect_error=main.zig:5:11: error: bad a25#}
26#update {
27introduce compile error#}
28#check errors {
29main.zig:5:11: error: bad a
30#}
2031
21#update=remove error reference32#write main.zig {
22#file=main.zig
23const std = @import("std");33const std = @import("std");
24pub fn main() !void {34pub fn main() !void {
25 try std.Io.File.stdout().writeStreamingAll(io, b);35 try std.Io.File.stdout().writeStreamingAll(io, b);
...@@ -27,10 +37,14 @@ pub fn main() !void {...@@ -27,10 +37,14 @@ pub fn main() !void {
27const a = @compileError("bad a");37const a = @compileError("bad a");
28const b = "Hi there!\n";38const b = "Hi there!\n";
29const io = std.Io.Threaded.global_single_threaded.io();39const io = std.Io.Threaded.global_single_threaded.io();
30#expect_stdout="Hi there!\n"40#}
41#update {
42remove error reference#}
43#check stdout {
44Hi there!
45#}
3146
32#update=introduce and remove reference to error47#write main.zig {
33#file=main.zig
34const std = @import("std");48const std = @import("std");
35pub fn main() !void {49pub fn main() !void {
36 try std.Io.File.stdout().writeStreamingAll(io, a);50 try std.Io.File.stdout().writeStreamingAll(io, a);
...@@ -38,4 +52,9 @@ pub fn main() !void {...@@ -38,4 +52,9 @@ pub fn main() !void {
38const a = "Back to a\n";52const a = "Back to a\n";
39const b = @compileError("bad b");53const b = @compileError("bad b");
40const io = std.Io.Threaded.global_single_threaded.io();54const io = std.Io.Threaded.global_single_threaded.io();
41#expect_stdout="Back to a\n"55#}
56#update {
57introduce and remove reference to error#}
58#check stdout {
59Back to a
60#}
test/incremental2/bad_import deleted-48
...@@ -1,48 +0,0 @@
1#exe {
2-Mroot=main.zig
3#}
4
5#write main.zig {
6pub fn main() !void {
7 _ = @import("foo.zig");
8 try std.Io.File.stdout().writeStreamingAll(io, "success\n");
9}
10const std = @import("std");
11const io = std.Io.Threaded.global_single_threaded.io();
12#}
13#write foo.zig {
14comptime {
15 _ = @import("bad.zig");
16}
17#}
18#update
19#check errors {
20bad.zig:1:1: error: unable to load "bad.zig": FileNotFound
21foo.zig:2:17: note: file imported here
22#}
23
24#write foo.zig {
25comptime {
26 _ = @import("this_is/not_real.zig");
27}
28#}
29#update {
30change bad import#}
31#check errors {
32this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound
33foo.zig:2:17: note: file imported here
34#}
35
36#write main.zig {
37pub fn main() !void {
38 //_ = @import("foo.zig");
39 try std.Io.File.stdout().writeStreamingAll(io, "success\n");
40}
41const std = @import("std");
42const io = std.Io.Threaded.global_single_threaded.io();
43#}
44#update {
45remove import of 'foo.zig'#}
46#check stdout {
47success
48#}
test/incremental2/change_panic_handler_explicit/0/main.zig deleted-46
...@@ -1,46 +0,0 @@
1pub fn main() !u8 {
2 var a: u8 = undefined;
3 a = 255;
4 _ = a + 1;
5 return 1;
6}
7const no_panic = std.debug.no_panic;
8pub const panic = struct {
9 pub const call = myPanic;
10 pub fn integerOverflow() noreturn {
11 @panic("integer overflow");
12 }
13 pub const sentinelMismatch = no_panic.sentinelMismatch;
14 pub const unwrapError = no_panic.unwrapError;
15 pub const outOfBounds = no_panic.outOfBounds;
16 pub const startGreaterThanEnd = no_panic.startGreaterThanEnd;
17 pub const inactiveUnionField = no_panic.inactiveUnionField;
18 pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder;
19 pub const reachedUnreachable = no_panic.reachedUnreachable;
20 pub const unwrapNull = no_panic.unwrapNull;
21 pub const castToNull = no_panic.castToNull;
22 pub const incorrectAlignment = no_panic.incorrectAlignment;
23 pub const invalidErrorCode = no_panic.invalidErrorCode;
24 pub const unexpectedErrorCode = no_panic.unexpectedErrorCode;
25 pub const integerOutOfBounds = no_panic.integerOutOfBounds;
26 pub const shlOverflow = no_panic.shlOverflow;
27 pub const shrOverflow = no_panic.shrOverflow;
28 pub const divideByZero = no_panic.divideByZero;
29 pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
30 pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
31 pub const corruptSwitch = no_panic.corruptSwitch;
32 pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
33 pub const invalidEnumValue = no_panic.invalidEnumValue;
34 pub const forLenMismatch = no_panic.forLenMismatch;
35 pub const copyLenMismatch = no_panic.copyLenMismatch;
36 pub const memcpyAlias = no_panic.memcpyAlias;
37 pub const noreturnReturned = no_panic.noreturnReturned;
38 pub const loadUninstantiableType = no_panic.loadUninstantiableType;
39};
40fn myPanic(msg: []const u8, _: ?usize) noreturn {
41 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
42 stdout_writer.interface.print("panic message: {s}\n", .{msg}) catch {};
43 std.process.exit(0);
44}
45const std = @import("std");
46const io = std.Io.Threaded.global_single_threaded.io();
test/incremental2/change_panic_handler_explicit/1/main.zig deleted-46
...@@ -1,46 +0,0 @@
1pub fn main() !u8 {
2 var a: u8 = undefined;
3 a = 255;
4 _ = a + 1;
5 return 1;
6}
7const no_panic = std.debug.no_panic;
8pub const panic = struct {
9 pub const call = myPanic;
10 pub fn integerOverflow() noreturn {
11 @panic("integer overflow");
12 }
13 pub const sentinelMismatch = no_panic.sentinelMismatch;
14 pub const unwrapError = no_panic.unwrapError;
15 pub const outOfBounds = no_panic.outOfBounds;
16 pub const startGreaterThanEnd = no_panic.startGreaterThanEnd;
17 pub const inactiveUnionField = no_panic.inactiveUnionField;
18 pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder;
19 pub const reachedUnreachable = no_panic.reachedUnreachable;
20 pub const unwrapNull = no_panic.unwrapNull;
21 pub const castToNull = no_panic.castToNull;
22 pub const incorrectAlignment = no_panic.incorrectAlignment;
23 pub const invalidErrorCode = no_panic.invalidErrorCode;
24 pub const unexpectedErrorCode = no_panic.unexpectedErrorCode;
25 pub const integerOutOfBounds = no_panic.integerOutOfBounds;
26 pub const shlOverflow = no_panic.shlOverflow;
27 pub const shrOverflow = no_panic.shrOverflow;
28 pub const divideByZero = no_panic.divideByZero;
29 pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
30 pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
31 pub const corruptSwitch = no_panic.corruptSwitch;
32 pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
33 pub const invalidEnumValue = no_panic.invalidEnumValue;
34 pub const forLenMismatch = no_panic.forLenMismatch;
35 pub const copyLenMismatch = no_panic.copyLenMismatch;
36 pub const memcpyAlias = no_panic.memcpyAlias;
37 pub const noreturnReturned = no_panic.noreturnReturned;
38 pub const loadUninstantiableType = no_panic.loadUninstantiableType;
39};
40fn myPanic(msg: []const u8, _: ?usize) noreturn {
41 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
42 stdout_writer.interface.print("new panic message: {s}\n", .{msg}) catch {};
43 std.process.exit(0);
44}
45const std = @import("std");
46const io = std.Io.Threaded.global_single_threaded.io();
test/incremental2/change_panic_handler_explicit/2/main.zig deleted-46
...@@ -1,46 +0,0 @@
1pub fn main() !u8 {
2 var a: u8 = undefined;
3 a = 255;
4 _ = a + 1;
5 return 1;
6}
7const no_panic = std.debug.no_panic;
8pub const panic = struct {
9 pub const call = myPanicNew;
10 pub fn integerOverflow() noreturn {
11 @panic("integer overflow");
12 }
13 pub const sentinelMismatch = no_panic.sentinelMismatch;
14 pub const unwrapError = no_panic.unwrapError;
15 pub const outOfBounds = no_panic.outOfBounds;
16 pub const startGreaterThanEnd = no_panic.startGreaterThanEnd;
17 pub const inactiveUnionField = no_panic.inactiveUnionField;
18 pub const sliceCastLenRemainder = no_panic.sliceCastLenRemainder;
19 pub const reachedUnreachable = no_panic.reachedUnreachable;
20 pub const unwrapNull = no_panic.unwrapNull;
21 pub const castToNull = no_panic.castToNull;
22 pub const incorrectAlignment = no_panic.incorrectAlignment;
23 pub const invalidErrorCode = no_panic.invalidErrorCode;
24 pub const unexpectedErrorCode = no_panic.unexpectedErrorCode;
25 pub const integerOutOfBounds = no_panic.integerOutOfBounds;
26 pub const shlOverflow = no_panic.shlOverflow;
27 pub const shrOverflow = no_panic.shrOverflow;
28 pub const divideByZero = no_panic.divideByZero;
29 pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
30 pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
31 pub const corruptSwitch = no_panic.corruptSwitch;
32 pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
33 pub const invalidEnumValue = no_panic.invalidEnumValue;
34 pub const forLenMismatch = no_panic.forLenMismatch;
35 pub const copyLenMismatch = no_panic.copyLenMismatch;
36 pub const memcpyAlias = no_panic.memcpyAlias;
37 pub const noreturnReturned = no_panic.noreturnReturned;
38 pub const loadUninstantiableType = no_panic.loadUninstantiableType;
39};
40fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
41 var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});
42 stdout_writer.interface.print("third panic message: {s}\n", .{msg}) catch {};
43 std.process.exit(0);
44}
45const std = @import("std");
46const io = std.Io.Threaded.global_single_threaded.io();
test/incremental2/change_panic_handler_explicit/manifest deleted-23
...@@ -1,23 +0,0 @@
1#exe {
2-Mroot=main.zig
3#}
4
5#write main.zig 0/main.zig
6#update
7#check stdout {
8panic message: integer overflow
9#}
10
11#write main.zig 1/main.zig
12#update {
13change the panic handler body#}
14#check stdout {
15new panic message: integer overflow
16#}
17
18#write main.zig 2/main.zig
19#update {
20change the panic handler function value#}
21#check stdout {
22third panic message: integer overflow
23#}
test/incremental2/hello deleted-28
...@@ -1,28 +0,0 @@
1#exe {
2-Mroot=main.zig
3#}
4
5#write main.zig {
6const std = @import("std");
7const io = std.Io.Threaded.global_single_threaded.io();
8pub fn main() !void {
9 try std.Io.File.stdout().writeStreamingAll(io, "good morning\n");
10}
11#}
12#update
13#check stdout {
14good morning
15#}
16
17#write main.zig {
18const std = @import("std");
19const io = std.Io.Threaded.global_single_threaded.io();
20pub fn main() !void {
21 try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n");
22}
23#}
24#update {
25change the string#}
26#check stdout {
27おはようございます
28#}
test/src/runner.zig+14-5
...@@ -471,7 +471,7 @@ fn runTest(...@@ -471,7 +471,7 @@ fn runTest(
471 continue;471 continue;
472 }472 }
473 const cmd = std.meta.stringToEnum(473 const cmd = std.meta.stringToEnum(
474 enum { skip, exe, lib, obj, write, delete, update, check },474 enum { todo, skip, exe, lib, obj, write, delete, update, check },
475 cmd_str,475 cmd_str,
476 ) orelse return error.UnknownCommand;476 ) orelse return error.UnknownCommand;
477 var maybe_arg = line_it.next();477 var maybe_arg = line_it.next();
...@@ -525,6 +525,7 @@ fn runTest(...@@ -525,6 +525,7 @@ fn runTest(
525 };525 };
526 defer cmd_prog_node.end();526 defer cmd_prog_node.end();
527 cmd: switch (cmd) {527 cmd: switch (cmd) {
528 .todo => _ = try contents_r.discardRemaining(),
528 .skip => if (!allow_skip)529 .skip => if (!allow_skip)
529 return error.NonInitialSkipCommand // #skip must appear first530 return error.NonInitialSkipCommand // #skip must appear first
530 else if (std.mem.eql(u8, target_string, maybe_arg orelse return error.MissingArg))531 else if (std.mem.eql(u8, target_string, maybe_arg orelse return error.MissingArg))
...@@ -646,12 +647,12 @@ fn runTest(...@@ -646,12 +647,12 @@ fn runTest(
646 update_num += 1;647 update_num += 1;
647 },648 },
648 .check => {649 .check => {
649 const expected = try contents_r.allocRemaining(gpa, .unlimited);
650 defer gpa.free(expected);
651 const check = std.meta.stringToEnum(650 const check = std.meta.stringToEnum(
652 enum { errors, stdout, exit, lldb },651 enum { errors, stdout, exit, lldb },
653 maybe_arg orelse return error.MissingCheckArg,652 maybe_arg orelse return error.MissingCheckArg,
654 ) orelse return error.UnknownCheck;653 ) orelse return error.UnknownCheck;
654 const expected = try contents_r.allocRemaining(gpa, .unlimited);
655 defer gpa.free(expected);
655656
656 const comp = &(compiler orelse return error.MissingCompiler);657 const comp = &(compiler orelse return error.MissingCompiler);
657 if (comp.state != .update) return error.MissingUpdate;658 if (comp.state != .update) return error.MissingUpdate;
...@@ -753,7 +754,9 @@ fn runTest(...@@ -753,7 +754,9 @@ fn runTest(
753 var error_aw: std.Io.Writer.Allocating = .init(gpa);754 var error_aw: std.Io.Writer.Allocating = .init(gpa);
754 defer error_aw.deinit();755 defer error_aw.deinit();
755 try error_bundle.renderToWriter(.{756 try error_bundle.renderToWriter(.{
757 .include_reference_trace = false,
756 .include_source_line = false,758 .include_source_line = false,
759 .include_log_text = true,
757 }, &error_aw.writer);760 }, &error_aw.writer);
758 try std.testing.expectEqualStrings(expected, error_aw.written());761 try std.testing.expectEqualStrings(expected, error_aw.written());
759 },762 },
...@@ -783,12 +786,18 @@ fn runTest(...@@ -783,12 +786,18 @@ fn runTest(
783 },786 },
784 }787 }
785 std.debug.assert(try contents_r.discardRemaining() == 0);788 std.debug.assert(try contents_r.discardRemaining() == 0);
786 if (cmd != .skip) allow_skip = false;789 switch (cmd) {
790 .todo, .skip => {},
791 else => allow_skip = false,
792 }
787 } else |err| switch (err) {793 } else |err| switch (err) {
788 else => |e| return e,794 else => |e| return e,
789 error.EndOfStream => if (skip_delimiter) return error.MissingDelimiter,795 error.EndOfStream => if (skip_delimiter) return error.MissingDelimiter,
790 }796 }
791 if (compiler) |*comp| try comp.exit(io);797 if (compiler) |*comp| {
798 if (comp.state != .idle) return error.MissingCheck;
799 try comp.exit(io);
800 }
792}801}
793const DelimitedReader = struct {802const DelimitedReader = struct {
794 const Io = std.Io;803 const Io = std.Io;
test/tests.zig+3-96
...@@ -3343,109 +3343,16 @@ const IncrementalTestOptions = struct {...@@ -3343,109 +3343,16 @@ const IncrementalTestOptions = struct {
3343};3343};
33443344
3345pub fn addIncrementalTests(3345pub fn addIncrementalTests(
3346 b: *std.Build,
3347 test_step: *Step,
3348 options: IncrementalTestOptions,
3349) !void {
3350 const io = b.graph.io;
3351
3352 const incr_check = b.addExecutable(.{
3353 .name = "incr-check",
3354 .root_module = b.createModule(.{
3355 .root_source_file = b.path("tools/incr-check.zig"),
3356 .target = b.graph.host,
3357 .optimize = .debug,
3358 }),
3359 });
3360
3361 b.dependOnDirectoryContents(b.path("test/incremental"));
3362
3363 var dir = try b.root.openDir(io, "test/incremental", .{ .iterate = true });
3364 defer dir.close(io);
3365
3366 var it = try dir.walk(b.graph.arena);
3367 while (try it.next(io)) |entry| {
3368 if (isEditorFileName(entry.basename)) continue;
3369
3370 for (options.test_filters) |test_filter| {
3371 if (std.mem.find(u8, entry.path, test_filter)) |_| break;
3372 } else if (options.test_filters.len > 0) continue;
3373
3374 switch (entry.kind) {
3375 .file => {},
3376 .directory => {
3377 b.dependOnDirectoryContents(b.path(b.pathJoin(&.{ "test", "incremental", entry.path })));
3378 },
3379 else => continue,
3380 }
3381 b.dependOnFileContents(b.path(b.pathJoin(&.{ "test", "incremental", entry.path })));
3382
3383 for (incremental_targets) |test_target| {
3384 const resolved_target = b.resolveTargetQuery(test_target.target);
3385
3386 if (options.skip_non_native and !isNative(&resolved_target, &b.graph.host.result))
3387 continue;
3388
3389 const target = &resolved_target.result;
3390
3391 if (options.skip_wasm and target.cpu.arch.isWasm()) continue;
3392
3393 if (options.skip_freebsd and target.os.tag == .freebsd) continue;
3394 if (options.skip_netbsd and target.os.tag == .netbsd) continue;
3395 if (options.skip_openbsd and target.os.tag == .openbsd) continue;
3396 if (options.skip_windows and target.os.tag == .windows) continue;
3397 if (options.skip_darwin and target.os.tag.isDarwin()) continue;
3398 if (options.skip_linux and target.os.tag == .linux) continue;
3399
3400 if (options.skip_llvm and test_target.backend == .llvm) continue;
3401
3402 const target_str = b.fmt("{s}-{t}", .{
3403 resolved_target.query.zigTriple(b.allocator) catch @panic("OOM"),
3404 test_target.backend,
3405 });
3406
3407 if (options.test_target_filters.len > 0) {
3408 for (options.test_target_filters) |filter| {
3409 if (std.mem.find(u8, target_str, filter) != null) break;
3410 } else continue;
3411 }
3412
3413 const run = b.addRunArtifact(incr_check);
3414 run.setName(b.fmt("incr-check {s} '{s}'", .{ target_str, entry.basename }));
3415
3416 run.addArg(b.graph.zig_exe);
3417 run.addFileArg(b.path("test/incremental/").path(b, entry.path));
3418
3419 run.addArg("--zig-lib-dir");
3420 run.addDirectoryArg(.zig_lib);
3421
3422 run.addArgs(&.{ "--target", target_str });
3423
3424 run.addArg("--quiet"); // don't fill stderr telling us about skipped tests etc
3425
3426 run.addThirdPartyEnabledArgDarling(.{ .enabled = "-fdarling" });
3427 run.addThirdPartyEnabledArgQemu(.{ .enabled = "-fqemu" });
3428 run.addThirdPartyEnabledArgRosetta(.{ .enabled = "-frosetta" });
3429 run.addThirdPartyEnabledArgWasmtime(.{ .enabled = "-fwasmtime" });
3430 run.addThirdPartyEnabledArgWine(.{ .enabled = "-fwine" });
3431
3432 run.addCheck(.{ .expect_term = .{ .exited = 0 } });
3433 test_step.dependOn(&run.step);
3434 }
3435 }
3436}
3437
3438pub fn addNewIncrementalTests(
3439 b: *std.Build,3346 b: *std.Build,
3440 runner: *std.Build.Step.Compile,3347 runner: *std.Build.Step.Compile,
3441 options: IncrementalTestOptions,3348 options: IncrementalTestOptions,
3442) !*Step {3349) !*Step {
3443 const tests_step = b.step("test-new-incremental", "Run the new incremental compilation test cases");3350 const tests_step = b.step("test-incremental", "Run the new incremental compilation test cases");
34443351
3445 const tests_path = b.path("test/incremental2");3352 const tests_path = b.path("test/incremental");
3446 b.dependOnDirectoryContents(tests_path);3353 b.dependOnDirectoryContents(tests_path);
34473354
3448 var tests_dir = try b.root.openDir(b.graph.io, "test/incremental2", .{ .iterate = true });3355 var tests_dir = try b.root.openDir(b.graph.io, "test/incremental", .{ .iterate = true });
3449 defer tests_dir.close(b.graph.io);3356 defer tests_dir.close(b.graph.io);
3450 var test_it = tests_dir.iterate();3357 var test_it = tests_dir.iterate();
3451 while (try test_it.next(b.graph.io)) |@"test"| {3358 while (try test_it.next(b.graph.io)) |@"test"| {
tools/incr-check.zig deleted-1032
...@@ -1,1032 +0,0 @@
1const std = @import("std");
2const Io = std.Io;
3const Dir = std.Io.Dir;
4const Allocator = std.mem.Allocator;
5const Cache = std.Build.Cache;
6
7const usage =
8 \\Usage: incr-check <zig binary path> <input file> [options]
9 \\Options:
10 \\ --target triple-backend
11 \\ --quiet
12 \\ --zig-lib-dir /path/to/zig/lib
13 \\ --zig-cc-binary /path/to/zig
14 \\ -fqemu
15 \\ -fwine
16 \\ -fwasmtime
17 \\Debug Options:
18 \\ --preserve-tmp
19 \\ --debug-log foo
20 \\ --debug-link-snapshot
21;
22
23pub const std_options: std.Options = .{
24 .logFn = logImpl,
25};
26var log_cur_update: ?*const Case.Update = null;
27fn logImpl(
28 comptime level: std.log.Level,
29 comptime scope: @EnumLiteral(),
30 comptime format: []const u8,
31 args: anytype,
32) void {
33 const update = log_cur_update orelse {
34 return std.log.defaultLog(level, scope, format, args);
35 };
36 std.log.defaultLog(
37 level,
38 scope,
39 "['{s}'] " ++ format,
40 .{update.name} ++ args,
41 );
42}
43
44pub fn main(init: std.process.Init) !void {
45 const gpa = init.gpa;
46 const arena = init.arena.allocator();
47 const io = init.io;
48 const environ_map = init.environ_map;
49 const cwd_path = try std.process.currentPathAlloc(io, arena);
50
51 var opt_zig_exe: ?[]const u8 = null;
52 var opt_input_file_name: ?[]const u8 = null;
53 var opt_lib_dir: ?[]const u8 = null;
54 var opt_cc_zig: ?[]const u8 = null;
55 var opt_target: ?struct { std.Target.Query, Backend } = null;
56 var preserve_tmp = false;
57 var enable_qemu: bool = false;
58 var enable_wine: bool = false;
59 var enable_wasmtime: bool = false;
60 var enable_darling: bool = false;
61 var quiet: bool = false;
62
63 var debug_log_args: std.ArrayList([]const u8) = .empty;
64 var debug_link_snapshot = false;
65
66 var arg_it = try init.minimal.args.iterateAllocator(arena);
67 _ = arg_it.skip();
68 while (arg_it.next()) |arg| {
69 if (arg.len > 0 and arg[0] == '-') {
70 if (std.mem.eql(u8, arg, "--zig-lib-dir")) {
71 opt_lib_dir = arg_it.next() orelse badUsage("expected arg after --zig-lib-dir", .{});
72 } else if (std.mem.eql(u8, arg, "--target")) {
73 const str = arg_it.next() orelse badUsage("expected arg after --zig-cc-binary", .{});
74 opt_target = parseTargetQueryAndBackend(str, "");
75 } else if (std.mem.eql(u8, arg, "--quiet")) {
76 quiet = true;
77 } else if (std.mem.eql(u8, arg, "--debug-log")) {
78 try debug_log_args.append(
79 arena,
80 arg_it.next() orelse badUsage("expected arg after --debug-log", .{}),
81 );
82 } else if (std.mem.eql(u8, arg, "--debug-link-snapshot")) {
83 debug_link_snapshot = true;
84 } else if (std.mem.eql(u8, arg, "--preserve-tmp")) {
85 preserve_tmp = true;
86 } else if (std.mem.eql(u8, arg, "-fqemu")) {
87 enable_qemu = true;
88 } else if (std.mem.eql(u8, arg, "-fwine")) {
89 enable_wine = true;
90 } else if (std.mem.eql(u8, arg, "-fwasmtime")) {
91 enable_wasmtime = true;
92 } else if (std.mem.eql(u8, arg, "-fdarling")) {
93 enable_darling = true;
94 } else if (std.mem.eql(u8, arg, "--zig-cc-binary")) {
95 opt_cc_zig = arg_it.next() orelse badUsage("expected arg after --zig-cc-binary", .{});
96 } else {
97 badUsage("unknown option '{s}'", .{arg});
98 }
99 continue;
100 }
101 if (opt_zig_exe == null) {
102 opt_zig_exe = arg;
103 } else if (opt_input_file_name == null) {
104 opt_input_file_name = arg;
105 } else {
106 badUsage("unknown argument '{s}'\n{s}", .{ arg, usage });
107 }
108 }
109 const zig_exe = opt_zig_exe orelse badUsage("missing path to zig", .{});
110 const input_file_name = opt_input_file_name orelse badUsage("missing input file", .{});
111 const target_query, const backend = opt_target orelse badUsage("missing required option '--target'", .{});
112
113 if (backend == .cbe and opt_lib_dir == null) {
114 std.process.fatal("'--zig-lib-dir' required when using backend 'cbe'", .{});
115 }
116
117 const input_file_bytes = try Dir.cwd().readFileAlloc(io, input_file_name, arena, .limited(std.math.maxInt(u32)));
118 const case: Case = try .parse(arena, input_file_bytes);
119
120 for (case.skip_targets) |skip| {
121 if (target_query.eql(skip.query) and backend == skip.backend) {
122 if (!quiet) std.log.warn("skipping test because of a 'skip_target' match", .{});
123 return;
124 }
125 }
126
127 const target = try std.zig.system.resolveTargetQuery(io, target_query);
128
129 const prog_node = std.Progress.start(io, .{});
130 defer prog_node.end();
131
132 const rand_int = rand64(io);
133 const tmp_dir_path = "tmp_" ++ std.fmt.hex(rand_int);
134 var tmp_dir = try Dir.cwd().createDirPathOpen(io, tmp_dir_path, .{});
135 defer {
136 tmp_dir.close(io);
137 if (!preserve_tmp) {
138 Dir.cwd().deleteTree(io, tmp_dir_path) catch |err| {
139 std.log.warn("failed to delete tree '{s}': {t}", .{ tmp_dir_path, err });
140 };
141 }
142 }
143
144 // Convert paths to be relative to the cwd of the subprocess.
145 const resolved_zig_exe = try Dir.path.relative(arena, cwd_path, environ_map, tmp_dir_path, zig_exe);
146 const opt_resolved_lib_dir = if (opt_lib_dir) |lib_dir|
147 try Dir.path.relative(arena, cwd_path, environ_map, tmp_dir_path, lib_dir)
148 else
149 null;
150
151 const host = try std.zig.system.resolveTargetQuery(io, .{});
152
153 var child_args: std.ArrayList([]const u8) = .empty;
154 try child_args.appendSlice(arena, &.{
155 resolved_zig_exe, "build-exe",
156 "-fincremental", "-fno-ubsan-rt",
157 "-target", try target_query.zigTriple(arena),
158 "--cache-dir", ".local-cache",
159 "--global-cache-dir", ".global-cache",
160 });
161
162 if (opt_resolved_lib_dir) |resolved_lib_dir| {
163 try child_args.appendSlice(arena, &.{ "--zig-lib-dir", resolved_lib_dir });
164 }
165 switch (backend) {
166 .sema => try child_args.append(arena, "-fno-emit-bin"),
167 .selfhosted => try child_args.appendSlice(arena, &.{ "-fno-llvm", "-fno-lld" }),
168 .llvm => try child_args.appendSlice(arena, &.{ "-fllvm", "-flld" }),
169 .cbe => try child_args.appendSlice(arena, &.{ "-ofmt=c", "-lc" }),
170 }
171 for (debug_log_args.items) |arg| {
172 try child_args.appendSlice(arena, &.{ "--debug-log", arg });
173 }
174 if (debug_link_snapshot) {
175 try child_args.append(arena, "--debug-link-snapshot");
176 }
177 for (case.modules) |mod| {
178 try child_args.appendSlice(arena, &.{ "--dep", mod.name });
179 }
180 try child_args.append(arena, try std.fmt.allocPrint(arena, "-Mroot={s}", .{case.root_source_file}));
181 for (case.modules) |mod| {
182 try child_args.append(arena, try std.fmt.allocPrint(arena, "-M{s}={s}", .{ mod.name, mod.file }));
183 }
184 try child_args.append(arena, "--listen=-");
185
186 const zig_prog_node = prog_node.start("zig", 0);
187 defer zig_prog_node.end();
188
189 var cc_child_args: std.ArrayList([]const u8) = .empty;
190 if (backend == .cbe) {
191 const resolved_cc_zig_exe = if (opt_cc_zig) |cc_zig_exe|
192 try Dir.path.relative(arena, cwd_path, environ_map, tmp_dir_path, cc_zig_exe)
193 else
194 resolved_zig_exe;
195
196 try cc_child_args.appendSlice(arena, &.{
197 resolved_cc_zig_exe, "build-exe",
198 "-target", try target_query.zigTriple(arena),
199 "--cache-dir", ".local-cache",
200 "--global-cache-dir", ".global-cache",
201 "-I", opt_resolved_lib_dir.?, // verified earlier
202 "-lc",
203 });
204 }
205
206 const allow_compiler_stderr = debug_log_args.items.len != 0;
207
208 if (allow_compiler_stderr) {
209 const cmd: std.zig.SubprocessCommand = .{
210 .argv = child_args.items,
211 .cwd = tmp_dir_path,
212 };
213 std.log.scoped(.spawn).info("{f}", .{cmd});
214 }
215
216 var child = try std.process.spawn(io, .{
217 .argv = child_args.items,
218 .stdin = .pipe,
219 .stdout = .pipe,
220 .stderr = .pipe,
221 .progress_node = zig_prog_node,
222 .cwd = .{ .path = tmp_dir_path },
223 });
224 defer child.kill(io);
225
226 const updates_prog_node = prog_node.start("updates", case.updates.len);
227 defer updates_prog_node.end();
228
229 var eval: Eval = .{
230 .arena = arena,
231 .io = io,
232 .case = case,
233 .host = host,
234 .target = target,
235 .backend = backend,
236 .tmp_dir = tmp_dir,
237 .tmp_dir_path = tmp_dir_path,
238 .child = &child,
239 .allow_compiler_stderr = allow_compiler_stderr,
240 .quiet = quiet,
241 .preserve_tmp_on_fatal = preserve_tmp,
242 .cc_child_args = &cc_child_args,
243 .enable_qemu = enable_qemu,
244 .enable_wine = enable_wine,
245 .enable_wasmtime = enable_wasmtime,
246 .enable_darling = enable_darling,
247 };
248
249 var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined;
250 var multi_reader: Io.File.MultiReader = undefined;
251 multi_reader.init(gpa, io, multi_reader_buffer.toStreams(), &.{ child.stdout.?, child.stderr.? });
252 defer multi_reader.deinit();
253
254 var update_mtime = Io.Clock.real.now(io);
255 for (case.updates) |update| {
256 var update_prog_node = updates_prog_node.start(update.name, 0);
257 defer update_prog_node.end();
258
259 if (debug_log_args.items.len != 0) {
260 // Print a line separating the debug logs from the compiler in the stderr output.
261 std.log.scoped(.status).info("update: '{s}'", .{update.name});
262 }
263
264 log_cur_update = &update;
265 defer log_cur_update = null;
266
267 eval.write(update, update_mtime);
268 update_mtime = update_mtime.addDuration(.fromSeconds(5));
269 try eval.requestUpdate();
270 try eval.check(&multi_reader, update, update_prog_node);
271 }
272
273 try eval.end(&multi_reader);
274
275 waitChild(&child, &eval);
276}
277
278const Eval = struct {
279 arena: Allocator,
280 io: Io,
281 case: Case,
282 host: std.Target,
283 target: std.Target,
284 backend: Backend,
285 tmp_dir: Dir,
286 tmp_dir_path: []const u8,
287 child: *std.process.Child,
288 allow_compiler_stderr: bool,
289 quiet: bool,
290 preserve_tmp_on_fatal: bool,
291 /// When `backend == .cbe`, this contains the first few arguments to `zig cc` to build the generated binary.
292 /// The arguments `out.c in.c` must be appended before spawning the subprocess.
293 cc_child_args: *std.ArrayList([]const u8),
294
295 enable_qemu: bool,
296 enable_wine: bool,
297 enable_wasmtime: bool,
298 enable_darling: bool,
299
300 /// Currently this function assumes the previous updates have already been written.
301 fn write(eval: *Eval, update: Case.Update, mtime: Io.Timestamp) void {
302 const io = eval.io;
303 for (update.changes) |full_contents| {
304 var update_file = eval.tmp_dir.createFile(io, full_contents.name, .{}) catch |err| {
305 eval.fatal("failed to create update '{s}': {t}", .{ full_contents.name, err });
306 };
307 defer update_file.close(io);
308 update_file.writeStreamingAll(io, full_contents.bytes) catch |err| {
309 eval.fatal("failed to write update '{s}': {t}", .{ full_contents.name, err });
310 };
311 update_file.setTimestamps(io, .{ .modify_timestamp = .{ .new = mtime } }) catch |err| {
312 eval.fatal("failed to set mtime for '{s}': {t}", .{ full_contents.name, err });
313 };
314 }
315 for (update.deletes) |doomed_name| {
316 eval.tmp_dir.deleteFile(io, doomed_name) catch |err| {
317 eval.fatal("failed to delete '{s}': {t}", .{ doomed_name, err });
318 };
319 }
320 }
321
322 fn check(eval: *Eval, mr: *Io.File.MultiReader, update: Case.Update, prog_node: std.Progress.Node) !void {
323 const arena = eval.arena;
324 const stdout = mr.reader(0);
325 const stderr = mr.reader(1);
326
327 var client: std.zig.Client = .{
328 .in = stdout,
329 .out = undefined,
330 };
331
332 while (true) {
333 const header = client.receiveMessageWithMultiReader(mr, .none) catch |err| switch (err) {
334 error.Timeout => unreachable,
335 error.EndOfStream => break,
336 else => |e| return e,
337 };
338 const body = client.in.take(header.bytes_len) catch unreachable;
339
340 switch (header.tag) {
341 .error_bundle => {
342 const result_error_bundle = try std.zig.Server.allocErrorBundle(arena, body);
343 if (stderr.bufferedLen() > 0) {
344 if (eval.allow_compiler_stderr) {
345 std.log.info("error_bundle stderr:\n{s}", .{stderr.buffered()});
346 } else {
347 eval.fatal("error_bundle unexpected stderr:\n{s}", .{stderr.buffered()});
348 }
349 stderr.tossBuffered();
350 }
351 if (result_error_bundle.errorMessageCount() != 0) {
352 try eval.checkErrorOutcome(update, result_error_bundle);
353 }
354 // This message indicates the end of the update.
355 return;
356 },
357 .emit_digest => {
358 var r: std.Io.Reader = .fixed(body);
359 _ = r.takeStruct(std.zig.Server.Message.EmitDigest, .little) catch unreachable;
360
361 if (stderr.bufferedLen() > 0) {
362 if (eval.allow_compiler_stderr) {
363 std.log.info("emit_digest stderr:\n{s}", .{stderr.buffered()});
364 } else {
365 eval.fatal("emit_digest unexpected stderr:\n{s}", .{stderr.buffered()});
366 }
367 stderr.tossBuffered();
368 }
369 if (eval.backend == .sema) {
370 try eval.checkSuccessOutcome(update, null, prog_node);
371 continue;
372 }
373
374 const digest = r.takeArray(Cache.bin_digest_len) catch unreachable;
375 const result_dir = ".local-cache" ++ Dir.path.sep_str ++ "o" ++ Dir.path.sep_str ++ Cache.binToHex(digest.*);
376
377 const bin_name = try std.zig.EmitArtifact.bin.cacheName(arena, .{
378 .root_name = "root", // corresponds to the module name "root"
379 .cpu_arch = eval.target.cpu.arch,
380 .os_tag = eval.target.os.tag,
381 .ofmt = eval.target.ofmt,
382 .abi = eval.target.abi,
383 .output_mode = .Exe,
384 });
385 const bin_path = try Dir.path.join(arena, &.{ result_dir, bin_name });
386
387 try eval.checkSuccessOutcome(update, bin_path, prog_node);
388 },
389 else => {
390 // Ignore other messages.
391 },
392 }
393 }
394
395 const buffered_stderr = stderr.buffered();
396 if (buffered_stderr.len > 0) {
397 if (eval.allow_compiler_stderr) {
398 std.log.info("stderr:\n{s}", .{buffered_stderr});
399 } else {
400 eval.fatal("unexpected stderr:\n{s}", .{buffered_stderr});
401 }
402 }
403
404 waitChild(eval.child, eval);
405 eval.fatal("compiler failed to send terminating error_bundle", .{});
406 }
407
408 fn checkErrorOutcome(eval: *Eval, update: Case.Update, error_bundle: std.zig.ErrorBundle) !void {
409 const io = eval.io;
410 const expected = switch (update.outcome) {
411 .unknown => return,
412 .compile_errors => |ce| ce,
413 .stdout, .exit_code => {
414 try error_bundle.renderToStderr(io, .{}, .auto);
415 eval.fatal("unexpected compile errors", .{});
416 },
417 };
418
419 var expected_idx: usize = 0;
420
421 for (error_bundle.getMessages()) |err_idx| {
422 if (expected_idx == expected.errors.len) {
423 try error_bundle.renderToStderr(io, .{}, .auto);
424 eval.fatal("more errors than expected", .{});
425 }
426 try eval.checkOneError(error_bundle, expected.errors[expected_idx], false, err_idx);
427 expected_idx += 1;
428
429 for (error_bundle.getNotes(err_idx)) |note_idx| {
430 if (expected_idx == expected.errors.len) {
431 try error_bundle.renderToStderr(io, .{}, .auto);
432 eval.fatal("more error notes than expected", .{});
433 }
434 try eval.checkOneError(error_bundle, expected.errors[expected_idx], true, note_idx);
435 expected_idx += 1;
436 }
437 }
438
439 if (!std.mem.eql(u8, error_bundle.getCompileLogOutput(), expected.compile_log_output)) {
440 try error_bundle.renderToStderr(io, .{}, .auto);
441 eval.fatal("unexpected compile log output", .{});
442 }
443 }
444
445 fn checkOneError(
446 eval: *Eval,
447 eb: std.zig.ErrorBundle,
448 expected: Case.ExpectedError,
449 is_note: bool,
450 err_idx: std.zig.ErrorBundle.MessageIndex,
451 ) Allocator.Error!void {
452 const io = eval.io;
453 const err = eb.getErrorMessage(err_idx);
454 if (err.count != 1) @panic("TODO error message with count>1");
455 const msg = eb.nullTerminatedString(err.msg);
456 const matches = matches: {
457 if (expected.is_note != is_note) break :matches false;
458 if (!std.mem.eql(u8, expected.msg, msg)) break :matches false;
459 if (err.src_loc == .none) {
460 break :matches expected.src == null;
461 }
462 const expected_src = expected.src orelse break :matches false;
463 const src = eb.getSourceLocation(err.src_loc);
464 const raw_filename = eb.nullTerminatedString(src.src_path);
465 // We need to replace backslashes for consistency between platforms.
466 const filename = name: {
467 if (std.mem.findScalar(u8, raw_filename, '\\') == null) break :name raw_filename;
468 const copied = try eval.arena.dupe(u8, raw_filename);
469 std.mem.replaceScalar(u8, copied, '\\', '/');
470 break :name copied;
471 };
472 if (!std.mem.eql(u8, expected_src.filename, filename)) break :matches false;
473 if (expected_src.line != src.line + 1) break :matches false;
474 if (expected_src.column != src.column + 1) break :matches false;
475 break :matches true;
476 };
477 if (!matches) {
478 eb.renderToStderr(io, .{}, .auto) catch {};
479 eval.fatal("compile error did not match expected error", .{});
480 }
481 }
482
483 fn checkSuccessOutcome(eval: *Eval, update: Case.Update, opt_emitted_path: ?[]const u8, prog_node: std.Progress.Node) !void {
484 switch (update.outcome) {
485 .unknown => return,
486 .compile_errors => eval.fatal("expected compile errors but compilation incorrectly succeeded", .{}),
487 .stdout, .exit_code => {},
488 }
489 const emitted_path = opt_emitted_path orelse {
490 std.debug.assert(eval.backend == .sema);
491 return;
492 };
493 const io = eval.io;
494
495 const binary_path = switch (eval.backend) {
496 .sema => unreachable,
497 .selfhosted, .llvm => emitted_path,
498 .cbe => bin: {
499 const rand_int = rand64(io);
500 const out_bin_name = "./out_" ++ std.fmt.hex(rand_int);
501 try eval.buildCOutput(emitted_path, out_bin_name, prog_node);
502 break :bin out_bin_name;
503 },
504 };
505
506 var argv_buf: [2][]const u8 = undefined;
507 const argv: []const []const u8, const is_foreign: bool = sw: switch (std.zig.system.getExternalExecutor(
508 io,
509 &eval.target,
510 .{
511 .link_libc = eval.backend == .cbe,
512 .host_cpu_arch = eval.host.cpu.arch,
513 .host_os_tag = eval.host.os.tag,
514 },
515 )) {
516 .bad_dl, .bad_os_or_cpu => {
517 // This binary cannot be executed on this host.
518 if (!eval.quiet) {
519 std.log.warn("skipping execution because host '{s}' cannot execute binaries for foreign target '{s}'", .{
520 try eval.host.zigTriple(eval.arena),
521 try eval.target.zigTriple(eval.arena),
522 });
523 }
524 return;
525 },
526 .native, .rosetta => argv: {
527 argv_buf[0] = binary_path;
528 break :argv .{ argv_buf[0..1], false };
529 },
530 .qemu => |executor_cmd| argv: {
531 if (eval.enable_qemu) {
532 argv_buf[0] = executor_cmd;
533 argv_buf[1] = binary_path;
534 break :argv .{ argv_buf[0..2], true };
535 } else {
536 continue :sw .bad_os_or_cpu;
537 }
538 },
539 .wine => |executor_cmd| argv: {
540 if (eval.enable_wine) {
541 argv_buf[0] = executor_cmd;
542 argv_buf[1] = binary_path;
543 break :argv .{ argv_buf[0..2], true };
544 } else {
545 continue :sw .bad_os_or_cpu;
546 }
547 },
548 .wasmtime => |executor_cmd| argv: {
549 if (eval.enable_wasmtime) {
550 argv_buf[0] = executor_cmd;
551 argv_buf[1] = binary_path;
552 break :argv .{ argv_buf[0..2], true };
553 } else {
554 continue :sw .bad_os_or_cpu;
555 }
556 },
557 .darling => |executor_cmd| argv: {
558 if (eval.enable_darling) {
559 argv_buf[0] = executor_cmd;
560 argv_buf[1] = binary_path;
561 break :argv .{ argv_buf[0..2], true };
562 } else {
563 continue :sw .bad_os_or_cpu;
564 }
565 },
566 };
567
568 const run_prog_node = prog_node.start("run generated executable", 0);
569 defer run_prog_node.end();
570
571 const result = std.process.run(eval.arena, io, .{
572 .argv = argv,
573 .cwd = .{ .path = eval.tmp_dir_path },
574 }) catch |err| {
575 if (is_foreign) {
576 // Chances are the foreign executor isn't available. Skip this evaluation.
577 if (!eval.quiet) {
578 std.log.warn("skipping execution of '{s}' via executor for foreign target '{s}': {t}", .{
579 binary_path,
580 try eval.target.zigTriple(eval.arena),
581 err,
582 });
583 }
584 return;
585 }
586 eval.fatal("failed to run the generated executable '{s}': {t}", .{ binary_path, err });
587 };
588
589 // Some executors (looking at you, Wine) like throwing some stderr in, just for fun.
590 // Therefore, we'll ignore stderr when using a foreign executor.
591 if (!is_foreign and result.stderr.len != 0) {
592 std.log.err("generated executable '{s}' had unexpected stderr:\n{s}", .{
593 binary_path, result.stderr,
594 });
595 }
596
597 switch (result.term) {
598 .exited => |code| switch (update.outcome) {
599 .unknown, .compile_errors => unreachable,
600 .stdout => |expected_stdout| {
601 if (code != 0) {
602 eval.fatal("generated executable '{s}' failed with code {d}", .{ binary_path, code });
603 }
604 try std.testing.expectEqualStrings(expected_stdout, result.stdout);
605 },
606 .exit_code => |expected_code| try std.testing.expectEqual(expected_code, code),
607 },
608 .signal => |sig| {
609 eval.fatal("generated executable '{s}' terminated with signal {t}", .{ binary_path, sig });
610 },
611 .stopped => |sig| {
612 eval.fatal("generated executable '{s}' stopped with signal {t}", .{ binary_path, sig });
613 },
614 .unknown => {
615 eval.fatal("generated executable '{s}' terminated unexpectedly", .{binary_path});
616 },
617 }
618
619 if (!is_foreign and result.stderr.len != 0) std.process.exit(1);
620 }
621
622 fn requestUpdate(eval: *Eval) !void {
623 const io = eval.io;
624
625 var w = eval.child.stdin.?.writerStreaming(io, &.{});
626 var client: std.zig.Client = .{
627 .in = undefined,
628 .out = &w.interface,
629 };
630 client.serveBodylessMessage(.update) catch |err| switch (err) {
631 error.WriteFailed => return w.err.?,
632 };
633 }
634
635 fn end(eval: *Eval, mr: *Io.File.MultiReader) !void {
636 requestExit(eval.child, eval);
637
638 var client: std.zig.Client = .{
639 .in = mr.reader(0),
640 .out = undefined,
641 };
642
643 while (true) {
644 const header = client.receiveMessageWithMultiReader(mr, .none) catch |err| switch (err) {
645 error.Timeout => unreachable,
646 error.EndOfStream => |e| {
647 if (client.in.bufferedLen() == 0) break;
648 return e;
649 },
650 else => |e| return e,
651 };
652 try client.in.discardAll(header.bytes_len);
653 }
654
655 const stderr = mr.reader(1).buffered();
656 if (stderr.len > 0) eval.fatal("unexpected stderr:\n{s}", .{stderr});
657 }
658
659 fn buildCOutput(eval: *Eval, c_path: []const u8, out_path: []const u8, prog_node: std.Progress.Node) !void {
660 std.debug.assert(eval.cc_child_args.items.len > 0);
661
662 const child_prog_node = prog_node.start("build cbe output", 0);
663 defer child_prog_node.end();
664
665 try eval.cc_child_args.append(eval.arena, try std.fmt.allocPrint(eval.arena, "-femit-bin={s}", .{out_path}));
666 try eval.cc_child_args.append(eval.arena, c_path);
667 defer eval.cc_child_args.items.len -= 2;
668
669 if (eval.allow_compiler_stderr) {
670 const cmd: std.zig.SubprocessCommand = .{
671 .argv = eval.cc_child_args.items,
672 .cwd = eval.tmp_dir_path,
673 };
674 std.log.scoped(.spawn).info("{f}", .{cmd});
675 }
676
677 const result = std.process.run(eval.arena, eval.io, .{
678 .argv = eval.cc_child_args.items,
679 .cwd = .{ .path = eval.tmp_dir_path },
680 .progress_node = child_prog_node,
681 }) catch |err| {
682 eval.fatal("failed to spawn zig cc for '{s}': {t}", .{ c_path, err });
683 };
684
685 if (result.term == .exited and result.term.exited == 0) return;
686
687 if (result.stderr.len != 0) {
688 std.log.err("zig cc stderr:\n{s}", .{result.stderr});
689 }
690 switch (result.term) {
691 .exited => |code| eval.fatal("zig cc for '{s}' failed with code {d}", .{ c_path, code }),
692 .signal => |sig| eval.fatal("zig cc for '{s}' terminated unexpectedly with signal {t}", .{ c_path, sig }),
693 .stopped => |sig| eval.fatal("zig cc for '{s}' stopped unexpectedly with signal {t}", .{ c_path, sig }),
694 .unknown => eval.fatal("zig cc for '{s}' terminated unexpectedly", .{c_path}),
695 }
696 }
697
698 fn fatal(eval: *Eval, comptime fmt: []const u8, args: anytype) noreturn {
699 const io = eval.io;
700 eval.tmp_dir.close(io);
701 if (!eval.preserve_tmp_on_fatal) {
702 // Kill the child since it holds an open handle to its CWD which is the tmp dir path
703 eval.child.kill(io);
704 Dir.cwd().deleteTree(io, eval.tmp_dir_path) catch |err| {
705 std.log.warn("failed to delete tree '{s}': {t}", .{ eval.tmp_dir_path, err });
706 };
707 }
708 std.process.fatal(fmt, args);
709 }
710};
711
712const Backend = enum {
713 /// Run semantic analysis only. Runtime output will not be tested, but we still verify
714 /// that compilation succeeds. Corresponds to `-fno-emit-bin`.
715 sema,
716 /// Use the self-hosted code generation backend for this target.
717 /// Corresponds to `-fno-llvm -fno-lld`.
718 selfhosted,
719 /// Use the LLVM backend.
720 /// Corresponds to `-fllvm -flld`.
721 llvm,
722 /// Use the C backend. The output is compiled with `zig cc`.
723 /// Corresponds to `-ofmt=c`.
724 cbe,
725};
726
727const Case = struct {
728 updates: []Update,
729 root_source_file: []const u8,
730 skip_targets: []const SkipTarget,
731 modules: []const Module,
732
733 const SkipTarget = struct {
734 query: std.Target.Query,
735 backend: Backend,
736 };
737
738 const Module = struct {
739 name: []const u8,
740 file: []const u8,
741 };
742
743 const Update = struct {
744 name: []const u8,
745 outcome: Outcome,
746 changes: []const FullContents = &.{},
747 deletes: []const []const u8 = &.{},
748 };
749
750 const FullContents = struct {
751 name: []const u8,
752 bytes: []const u8,
753 };
754
755 const Outcome = union(enum) {
756 unknown,
757 compile_errors: struct {
758 errors: []const ExpectedError,
759 compile_log_output: []const u8,
760 },
761 stdout: []const u8,
762 exit_code: u8,
763 };
764
765 const ExpectedError = struct {
766 is_note: bool,
767 msg: []const u8,
768 src: ?struct {
769 filename: []const u8,
770 line: u32,
771 column: u32,
772 },
773 };
774
775 fn parse(arena: Allocator, bytes: []const u8) !Case {
776 const fatal = std.process.fatal;
777
778 var skip_targets: std.ArrayList(SkipTarget) = .empty;
779 var modules: std.ArrayList(Module) = .empty;
780 var updates: std.ArrayList(Update) = .empty;
781 var changes: std.ArrayList(FullContents) = .empty;
782 var deletes: std.ArrayList([]const u8) = .empty;
783 var it = std.mem.splitScalar(u8, bytes, '\n');
784 var line_n: usize = 1;
785 var root_source_file: ?[]const u8 = null;
786 while (it.next()) |line| : (line_n += 1) {
787 if (std.mem.startsWith(u8, line, "#")) {
788 var line_it = std.mem.splitScalar(u8, line, '=');
789 const key = line_it.first()[1..];
790 const val = std.mem.trimEnd(u8, line_it.rest(), "\r"); // windows moment
791 if (val.len == 0) {
792 fatal("line {d}: missing value", .{line_n});
793 } else if (std.mem.eql(u8, key, "skip_target")) {
794 const query, const backend = parseTargetQueryAndBackend(
795 val,
796 try std.fmt.allocPrint(arena, "line {d}: ", .{line_n}),
797 );
798 try skip_targets.append(arena, .{
799 .query = query,
800 .backend = backend,
801 });
802 } else if (std.mem.eql(u8, key, "module")) {
803 const split_idx = std.mem.findScalar(u8, val, '=') orelse
804 fatal("line {d}: module does not include file", .{line_n});
805 const name = val[0..split_idx];
806 const file = val[split_idx + 1 ..];
807 try modules.append(arena, .{
808 .name = name,
809 .file = file,
810 });
811 } else if (std.mem.eql(u8, key, "update")) {
812 if (updates.items.len > 0) {
813 const last_update = &updates.items[updates.items.len - 1];
814 last_update.changes = try changes.toOwnedSlice(arena);
815 last_update.deletes = try deletes.toOwnedSlice(arena);
816 }
817 try updates.append(arena, .{
818 .name = val,
819 .outcome = .unknown,
820 });
821 } else if (std.mem.eql(u8, key, "file")) {
822 if (updates.items.len == 0) fatal("line {d}: file directive before update", .{line_n});
823
824 if (root_source_file == null)
825 root_source_file = val;
826
827 // Because Windows is so excellent, we need to convert CRLF to LF, so
828 // can't just slice into the input here. How delightful!
829 var src: std.ArrayList(u8) = .empty;
830
831 while (true) {
832 const next_line_raw = it.peek() orelse fatal("line {d}: unexpected EOF", .{line_n});
833 const next_line = std.mem.trimEnd(u8, next_line_raw, "\r");
834 if (std.mem.startsWith(u8, next_line, "#")) break;
835
836 _ = it.next();
837 line_n += 1;
838
839 try src.ensureUnusedCapacity(arena, next_line.len + 1);
840 src.appendSliceAssumeCapacity(next_line);
841 src.appendAssumeCapacity('\n');
842 }
843
844 try changes.append(arena, .{
845 .name = val,
846 .bytes = src.items,
847 });
848 } else if (std.mem.eql(u8, key, "rm_file")) {
849 if (updates.items.len == 0) fatal("line {d}: rm_file directive before update", .{line_n});
850 try deletes.append(arena, val);
851 } else if (std.mem.eql(u8, key, "expect_stdout")) {
852 if (updates.items.len == 0) fatal("line {d}: expect directive before update", .{line_n});
853 const last_update = &updates.items[updates.items.len - 1];
854 if (last_update.outcome != .unknown) fatal("line {d}: conflicting expect directive", .{line_n});
855 last_update.outcome = .{
856 .stdout = std.zig.string_literal.parseAlloc(arena, val) catch |err| {
857 fatal("line {d}: bad string literal: {t}", .{ line_n, err });
858 },
859 };
860 } else if (std.mem.eql(u8, key, "expect_error")) {
861 if (updates.items.len == 0) fatal("line {d}: expect directive before update", .{line_n});
862 const last_update = &updates.items[updates.items.len - 1];
863 if (last_update.outcome != .unknown) fatal("line {d}: conflicting expect directive", .{line_n});
864
865 var errors: std.ArrayList(ExpectedError) = .empty;
866 try errors.append(arena, parseExpectedError(val, line_n));
867 while (true) {
868 const next_line = it.peek() orelse break;
869 if (!std.mem.startsWith(u8, next_line, "#")) break;
870 var new_line_it = std.mem.splitScalar(u8, next_line, '=');
871 const new_key = new_line_it.first()[1..];
872 const new_val = std.mem.trimEnd(u8, new_line_it.rest(), "\r");
873 if (new_val.len == 0) break;
874 if (!std.mem.eql(u8, new_key, "expect_error")) break;
875
876 _ = it.next();
877 line_n += 1;
878 try errors.append(arena, parseExpectedError(new_val, line_n));
879 }
880
881 var compile_log_output: std.ArrayList(u8) = .empty;
882 while (true) {
883 const next_line = it.peek() orelse break;
884 if (!std.mem.startsWith(u8, next_line, "#")) break;
885 var new_line_it = std.mem.splitScalar(u8, next_line, '=');
886 const new_key = new_line_it.first()[1..];
887 const new_val = std.mem.trimEnd(u8, new_line_it.rest(), "\r");
888 if (new_val.len == 0) break;
889 if (!std.mem.eql(u8, new_key, "expect_compile_log")) break;
890
891 _ = it.next();
892 line_n += 1;
893 try compile_log_output.ensureUnusedCapacity(arena, new_val.len + 1);
894 compile_log_output.appendSliceAssumeCapacity(new_val);
895 compile_log_output.appendAssumeCapacity('\n');
896 }
897
898 last_update.outcome = .{ .compile_errors = .{
899 .errors = errors.items,
900 .compile_log_output = compile_log_output.items,
901 } };
902 } else if (std.mem.eql(u8, key, "expect_compile_log")) {
903 fatal("line {d}: 'expect_compile_log' must immediately follow 'expect_error'", .{line_n});
904 } else {
905 fatal("line {d}: unrecognized key '{s}'", .{ line_n, key });
906 }
907 }
908 }
909
910 if (changes.items.len > 0) {
911 const last_update = &updates.items[updates.items.len - 1];
912 last_update.changes = changes.items; // arena so no need for toOwnedSlice
913 last_update.deletes = deletes.items;
914 }
915
916 return .{
917 .updates = updates.items,
918 .root_source_file = root_source_file orelse fatal("missing root source file", .{}),
919 .skip_targets = skip_targets.items, // arena so no need for toOwnedSlice
920 .modules = modules.items,
921 };
922 }
923};
924
925fn requestExit(child: *std.process.Child, eval: *Eval) void {
926 if (child.stdin == null) return;
927 const io = eval.io;
928
929 var w = eval.child.stdin.?.writerStreaming(io, &.{});
930 var client: std.zig.Client = .{
931 .in = undefined,
932 .out = &w.interface,
933 };
934 client.serveBodylessMessage(.exit) catch |err| switch (err) {
935 error.WriteFailed => switch (w.err.?) {
936 error.BrokenPipe => {},
937 else => |e| eval.fatal("failed to send exit: {t}", .{e}),
938 },
939 };
940
941 // Send EOF to stdin.
942 child.stdin.?.close(io);
943 child.stdin = null;
944}
945
946fn waitChild(child: *std.process.Child, eval: *Eval) void {
947 const io = eval.io;
948 requestExit(child, eval);
949 const term = child.wait(io) catch |err| eval.fatal("child process failed: {t}", .{err});
950 switch (term) {
951 .exited => |code| if (code != 0) eval.fatal("compiler failed with code {d}", .{code}),
952 .signal => |sig| eval.fatal("compiler terminated with signal {t}", .{sig}),
953 .stopped => |sig| eval.fatal("compiler stopped unexpectedly with signal {t}", .{sig}),
954 .unknown => eval.fatal("compiler terminated unexpectedly", .{}),
955 }
956}
957
958fn parseExpectedError(str: []const u8, l: usize) Case.ExpectedError {
959 // #expect_error=foo.zig:1:2: error: the error message
960 // #expect_error=foo.zig:1:2: note: and a note
961
962 const fatal = std.process.fatal;
963
964 var it = std.mem.splitScalar(u8, str, ':');
965 const filename = it.first();
966 const line_str, const column_str = if (filename.len > 0) .{
967 it.next() orelse fatal("line {d}: incomplete error specification", .{l}),
968 it.next() orelse fatal("line {d}: incomplete error specification", .{l}),
969 } else .{ undefined, undefined };
970 const error_or_note_str = std.mem.trim(
971 u8,
972 it.next() orelse fatal("line {d}: incomplete error specification", .{l}),
973 " ",
974 );
975
976 const is_note = if (std.mem.eql(u8, error_or_note_str, "error"))
977 false
978 else if (std.mem.eql(u8, error_or_note_str, "note"))
979 true
980 else
981 fatal("line {d}: expeted 'error' or 'note', found '{s}'", .{ l, error_or_note_str });
982
983 const message = std.mem.trim(u8, it.rest(), " ");
984 if (message.len == 0) fatal("line {d}: empty error message", .{l});
985
986 return .{
987 .is_note = is_note,
988 .msg = message,
989 .src = if (filename.len == 0) null else .{
990 .filename = filename,
991 .line = std.fmt.parseInt(u32, line_str, 10) catch
992 fatal("line {d}: invalid line number '{s}'", .{ l, line_str }),
993 .column = std.fmt.parseInt(u32, column_str, 10) catch
994 fatal("line {d}: invalid column number '{s}'", .{ l, column_str }),
995 },
996 };
997}
998
999fn rand64(io: Io) u64 {
1000 var x: u64 = undefined;
1001 io.random(@ptrCast(&x));
1002 return x;
1003}
1004
1005/// Calls `std.process.fatal` on error. The error messages are prefixed with `err_prefix`.
1006fn parseTargetQueryAndBackend(input_str: []const u8, err_prefix: []const u8) struct { std.Target.Query, Backend } {
1007 const fatal = std.process.fatal;
1008
1009 const split_idx = std.mem.findScalarLast(u8, input_str, '-') orelse
1010 fatal("{s}target does not include backend", .{err_prefix});
1011
1012 const query = input_str[0..split_idx];
1013
1014 const backend_str = input_str[split_idx + 1 ..];
1015 const backend: Backend = std.meta.stringToEnum(Backend, backend_str) orelse
1016 fatal("{s}invalid backend '{s}'", .{ err_prefix, backend_str });
1017
1018 const parsed_query = std.Build.parseTargetQuery(.{
1019 .arch_os_abi = query,
1020 .object_format = switch (backend) {
1021 .sema, .selfhosted, .llvm => null,
1022 .cbe => "c",
1023 },
1024 }) catch fatal("{s}invalid target query '{s}'", .{ err_prefix, query });
1025
1026 return .{ parsed_query, backend };
1027}
1028
1029fn badUsage(comptime fmt: []const u8, args: anytype) noreturn {
1030 std.log.err(fmt ++ "\n{s}", args ++ .{usage});
1031 std.process.exit(1);
1032}