authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-10-16 20:29:55+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-10-16 20:29:55+01:00
log6201031e0581c54688fdf6071a250b80f892525b
treeb8fac5782647b26920756d6a805cd5d799f533ff
parentbdd3bc056ee998770ea48a93b4ec99521f069aed
parent3ba4f86198267fee0f6a8d50496908794e743cbd
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21722 from mlugg/incremental

incremental compilation progress

10 files changed, 181 insertions(+), 62 deletions(-)

src/Compilation.zig+29-35
...@@ -2901,6 +2901,7 @@ pub fn makeBinFileWritable(comp: *Compilation) !void {...@@ -2901,6 +2901,7 @@ pub fn makeBinFileWritable(comp: *Compilation) !void {
2901const Header = extern struct {2901const Header = extern struct {
2902 intern_pool: extern struct {2902 intern_pool: extern struct {
2903 thread_count: u32,2903 thread_count: u32,
2904 file_deps_len: u32,
2904 src_hash_deps_len: u32,2905 src_hash_deps_len: u32,
2905 nav_val_deps_len: u32,2906 nav_val_deps_len: u32,
2906 namespace_deps_len: u32,2907 namespace_deps_len: u32,
...@@ -2943,6 +2944,7 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2943,6 +2944,7 @@ pub fn saveState(comp: *Compilation) !void {
2943 const header: Header = .{2944 const header: Header = .{
2944 .intern_pool = .{2945 .intern_pool = .{
2945 .thread_count = @intCast(ip.locals.len),2946 .thread_count = @intCast(ip.locals.len),
2947 .file_deps_len = @intCast(ip.file_deps.count()),
2946 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),2948 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),
2947 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()),2949 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()),
2948 .namespace_deps_len = @intCast(ip.namespace_deps.count()),2950 .namespace_deps_len = @intCast(ip.namespace_deps.count()),
...@@ -2969,6 +2971,8 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2969,6 +2971,8 @@ pub fn saveState(comp: *Compilation) !void {
2969 addBuf(&bufs, mem.asBytes(&header));2971 addBuf(&bufs, mem.asBytes(&header));
2970 addBuf(&bufs, mem.sliceAsBytes(pt_headers.items));2972 addBuf(&bufs, mem.sliceAsBytes(pt_headers.items));
29712973
2974 addBuf(&bufs, mem.sliceAsBytes(ip.file_deps.keys()));
2975 addBuf(&bufs, mem.sliceAsBytes(ip.file_deps.values()));
2972 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.keys()));2976 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.keys()));
2973 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values()));2977 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values()));
2974 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys()));2978 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys()));
...@@ -3076,15 +3080,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3076,15 +3080,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3076 });3080 });
3077 }3081 }
30783082
3079 var all_references: ?std.AutoHashMapUnmanaged(InternPool.AnalUnit, ?Zcu.ResolvedReference) = null;
3080 defer if (all_references) |*a| a.deinit(gpa);
3081
3082 if (comp.zcu) |zcu| {3083 if (comp.zcu) |zcu| {
3083 const ip = &zcu.intern_pool;3084 const ip = &zcu.intern_pool;
30843085
3085 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {3086 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {
3086 if (error_msg) |msg| {3087 if (error_msg) |msg| {
3087 try addModuleErrorMsg(zcu, &bundle, msg.*, &all_references);3088 try addModuleErrorMsg(zcu, &bundle, msg.*);
3088 } else {3089 } else {
3089 // Must be ZIR errors. Note that this may include AST errors.3090 // Must be ZIR errors. Note that this may include AST errors.
3090 // addZirErrorMessages asserts that the tree is loaded.3091 // addZirErrorMessages asserts that the tree is loaded.
...@@ -3093,7 +3094,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3093,7 +3094,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3093 }3094 }
3094 }3095 }
3095 for (zcu.failed_embed_files.values()) |error_msg| {3096 for (zcu.failed_embed_files.values()) |error_msg| {
3096 try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);3097 try addModuleErrorMsg(zcu, &bundle, error_msg.*);
3097 }3098 }
3098 {3099 {
3099 const SortOrder = struct {3100 const SortOrder = struct {
...@@ -3136,10 +3137,8 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3136,10 +3137,8 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3136 }3137 }
3137 for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| {3138 for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| {
3138 if (comp.incremental) {3139 if (comp.incremental) {
3139 if (all_references == null) {3140 const refs = try zcu.resolveReferences();
3140 all_references = try zcu.resolveReferences();3141 if (!refs.contains(anal_unit)) continue;
3141 }
3142 if (!all_references.?.contains(anal_unit)) continue;
3143 }3142 }
31443143
3145 const file_index = switch (anal_unit.unwrap()) {3144 const file_index = switch (anal_unit.unwrap()) {
...@@ -3151,7 +3150,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3151,7 +3150,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3151 // We'll try again once parsing succeeds.3150 // We'll try again once parsing succeeds.
3152 if (!zcu.fileByIndex(file_index).okToReportErrors()) continue;3151 if (!zcu.fileByIndex(file_index).okToReportErrors()) continue;
31533152
3154 try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);3153 try addModuleErrorMsg(zcu, &bundle, error_msg.*);
3155 if (zcu.cimport_errors.get(anal_unit)) |errors| {3154 if (zcu.cimport_errors.get(anal_unit)) |errors| {
3156 for (errors.getMessages()) |err_msg_index| {3155 for (errors.getMessages()) |err_msg_index| {
3157 const err_msg = errors.getErrorMessage(err_msg_index);3156 const err_msg = errors.getErrorMessage(err_msg_index);
...@@ -3175,10 +3174,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3175,10 +3174,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3175 }3174 }
3176 for (zcu.failed_codegen.keys(), zcu.failed_codegen.values()) |nav, error_msg| {3175 for (zcu.failed_codegen.keys(), zcu.failed_codegen.values()) |nav, error_msg| {
3177 if (!zcu.navFileScope(nav).okToReportErrors()) continue;3176 if (!zcu.navFileScope(nav).okToReportErrors()) continue;
3178 try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);3177 try addModuleErrorMsg(zcu, &bundle, error_msg.*);
3179 }3178 }
3180 for (zcu.failed_exports.values()) |value| {3179 for (zcu.failed_exports.values()) |value| {
3181 try addModuleErrorMsg(zcu, &bundle, value.*, &all_references);3180 try addModuleErrorMsg(zcu, &bundle, value.*);
3182 }3181 }
31833182
3184 const actual_error_count = zcu.intern_pool.global_error_set.getNamesFromMainThread().len;3183 const actual_error_count = zcu.intern_pool.global_error_set.getNamesFromMainThread().len;
...@@ -3252,17 +3251,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3252,17 +3251,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3252 };3251 };
3253 }3252 }
32543253
3255 try addModuleErrorMsg(zcu, &bundle, err_msg, &all_references);3254 try addModuleErrorMsg(zcu, &bundle, err_msg);
3256 }3255 }
3257 }3256 }
32583257
3259 if (comp.zcu) |zcu| {3258 if (comp.zcu) |zcu| {
3260 if (comp.incremental and bundle.root_list.items.len == 0) {3259 if (comp.incremental and bundle.root_list.items.len == 0) {
3261 const should_have_error = for (zcu.transitive_failed_analysis.keys()) |failed_unit| {3260 const should_have_error = for (zcu.transitive_failed_analysis.keys()) |failed_unit| {
3262 if (all_references == null) {3261 const refs = try zcu.resolveReferences();
3263 all_references = try zcu.resolveReferences();3262 if (refs.contains(failed_unit)) break true;
3264 }
3265 if (all_references.?.contains(failed_unit)) break true;
3266 } else false;3263 } else false;
3267 if (should_have_error) {3264 if (should_have_error) {
3268 @panic("referenced transitive analysis errors, but none actually emitted");3265 @panic("referenced transitive analysis errors, but none actually emitted");
...@@ -3331,14 +3328,13 @@ pub const ErrorNoteHashContext = struct {...@@ -3331,14 +3328,13 @@ pub const ErrorNoteHashContext = struct {
3331};3328};
33323329
3333pub fn addModuleErrorMsg(3330pub fn addModuleErrorMsg(
3334 mod: *Zcu,3331 zcu: *Zcu,
3335 eb: *ErrorBundle.Wip,3332 eb: *ErrorBundle.Wip,
3336 module_err_msg: Zcu.ErrorMsg,3333 module_err_msg: Zcu.ErrorMsg,
3337 all_references: *?std.AutoHashMapUnmanaged(InternPool.AnalUnit, ?Zcu.ResolvedReference),
3338) !void {3334) !void {
3339 const gpa = eb.gpa;3335 const gpa = eb.gpa;
3340 const ip = &mod.intern_pool;3336 const ip = &zcu.intern_pool;
3341 const err_src_loc = module_err_msg.src_loc.upgrade(mod);3337 const err_src_loc = module_err_msg.src_loc.upgrade(zcu);
3342 const err_source = err_src_loc.file_scope.getSource(gpa) catch |err| {3338 const err_source = err_src_loc.file_scope.getSource(gpa) catch |err| {
3343 const file_path = try err_src_loc.file_scope.fullPath(gpa);3339 const file_path = try err_src_loc.file_scope.fullPath(gpa);
3344 defer gpa.free(file_path);3340 defer gpa.free(file_path);
...@@ -3358,22 +3354,20 @@ pub fn addModuleErrorMsg(...@@ -3358,22 +3354,20 @@ pub fn addModuleErrorMsg(
3358 defer ref_traces.deinit(gpa);3354 defer ref_traces.deinit(gpa);
33593355
3360 if (module_err_msg.reference_trace_root.unwrap()) |rt_root| {3356 if (module_err_msg.reference_trace_root.unwrap()) |rt_root| {
3361 if (all_references.* == null) {3357 const all_references = try zcu.resolveReferences();
3362 all_references.* = try mod.resolveReferences();
3363 }
33643358
3365 var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty;3359 var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty;
3366 defer seen.deinit(gpa);3360 defer seen.deinit(gpa);
33673361
3368 const max_references = mod.comp.reference_trace orelse Sema.default_reference_trace_len;3362 const max_references = zcu.comp.reference_trace orelse Sema.default_reference_trace_len;
33693363
3370 var referenced_by = rt_root;3364 var referenced_by = rt_root;
3371 while (all_references.*.?.get(referenced_by)) |maybe_ref| {3365 while (all_references.get(referenced_by)) |maybe_ref| {
3372 const ref = maybe_ref orelse break;3366 const ref = maybe_ref orelse break;
3373 const gop = try seen.getOrPut(gpa, ref.referencer);3367 const gop = try seen.getOrPut(gpa, ref.referencer);
3374 if (gop.found_existing) break;3368 if (gop.found_existing) break;
3375 if (ref_traces.items.len < max_references) {3369 if (ref_traces.items.len < max_references) {
3376 const src = ref.src.upgrade(mod);3370 const src = ref.src.upgrade(zcu);
3377 const source = try src.file_scope.getSource(gpa);3371 const source = try src.file_scope.getSource(gpa);
3378 const span = try src.span(gpa);3372 const span = try src.span(gpa);
3379 const loc = std.zig.findLineColumn(source.bytes, span.main);3373 const loc = std.zig.findLineColumn(source.bytes, span.main);
...@@ -3385,7 +3379,7 @@ pub fn addModuleErrorMsg(...@@ -3385,7 +3379,7 @@ pub fn addModuleErrorMsg(
3385 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),3379 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
3386 .none => "comptime",3380 .none => "comptime",
3387 },3381 },
3388 .func => |f| ip.getNav(mod.funcInfo(f).owner_nav).name.toSlice(ip),3382 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
3389 };3383 };
3390 try ref_traces.append(gpa, .{3384 try ref_traces.append(gpa, .{
3391 .decl_name = try eb.addString(name),3385 .decl_name = try eb.addString(name),
...@@ -3435,7 +3429,7 @@ pub fn addModuleErrorMsg(...@@ -3435,7 +3429,7 @@ pub fn addModuleErrorMsg(
3435 defer notes.deinit(gpa);3429 defer notes.deinit(gpa);
34363430
3437 for (module_err_msg.notes) |module_note| {3431 for (module_err_msg.notes) |module_note| {
3438 const note_src_loc = module_note.src_loc.upgrade(mod);3432 const note_src_loc = module_note.src_loc.upgrade(zcu);
3439 const source = try note_src_loc.file_scope.getSource(gpa);3433 const source = try note_src_loc.file_scope.getSource(gpa);
3440 const span = try note_src_loc.span(gpa);3434 const span = try note_src_loc.span(gpa);
3441 const loc = std.zig.findLineColumn(source.bytes, span.main);3435 const loc = std.zig.findLineColumn(source.bytes, span.main);
...@@ -3488,13 +3482,13 @@ pub fn performAllTheWork(...@@ -3488,13 +3482,13 @@ pub fn performAllTheWork(
3488 comp: *Compilation,3482 comp: *Compilation,
3489 main_progress_node: std.Progress.Node,3483 main_progress_node: std.Progress.Node,
3490) JobError!void {3484) JobError!void {
3491 defer if (comp.zcu) |mod| {3485 defer if (comp.zcu) |zcu| {
3492 mod.sema_prog_node.end();3486 zcu.sema_prog_node.end();
3493 mod.sema_prog_node = std.Progress.Node.none;3487 zcu.sema_prog_node = std.Progress.Node.none;
3494 mod.codegen_prog_node.end();3488 zcu.codegen_prog_node.end();
3495 mod.codegen_prog_node = std.Progress.Node.none;3489 zcu.codegen_prog_node = std.Progress.Node.none;
34963490
3497 mod.generation += 1;3491 zcu.generation += 1;
3498 };3492 };
3499 try comp.performAllTheWorkInner(main_progress_node);3493 try comp.performAllTheWorkInner(main_progress_node);
3500 if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error;3494 if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error;
src/InternPool.zig+12
...@@ -17,6 +17,13 @@ tid_shift_31: if (single_threaded) u0 else std.math.Log2Int(u32),...@@ -17,6 +17,13 @@ tid_shift_31: if (single_threaded) u0 else std.math.Log2Int(u32),
17/// Cached shift amount to put a `tid` in the top bits of a 32-bit value.17/// Cached shift amount to put a `tid` in the top bits of a 32-bit value.
18tid_shift_32: if (single_threaded) u0 else std.math.Log2Int(u32),18tid_shift_32: if (single_threaded) u0 else std.math.Log2Int(u32),
1919
20/// Dependencies on whether an entire file gets past AstGen.
21/// These are triggered by `@import`, so that:
22/// * if a file initially fails AstGen, triggering a transitive failure, when a future update
23/// causes it to succeed AstGen, the `@import` is re-analyzed, allowing analysis to proceed
24/// * if a file initially succeds AstGen, but a future update causes the file to fail it,
25/// the `@import` is re-analyzed, registering a transitive failure
26file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index),
20/// Dependencies on the source code hash associated with a ZIR instruction.27/// Dependencies on the source code hash associated with a ZIR instruction.
21/// * For a `declaration`, this is the entire declaration body.28/// * For a `declaration`, this is the entire declaration body.
22/// * For a `struct_decl`, `union_decl`, etc, this is the source of the fields (but not declarations).29/// * For a `struct_decl`, `union_decl`, etc, this is the source of the fields (but not declarations).
...@@ -70,6 +77,7 @@ pub const empty: InternPool = .{...@@ -70,6 +77,7 @@ pub const empty: InternPool = .{
70 .tid_shift_30 = if (single_threaded) 0 else 31,77 .tid_shift_30 = if (single_threaded) 0 else 31,
71 .tid_shift_31 = if (single_threaded) 0 else 31,78 .tid_shift_31 = if (single_threaded) 0 else 31,
72 .tid_shift_32 = if (single_threaded) 0 else 31,79 .tid_shift_32 = if (single_threaded) 0 else 31,
80 .file_deps = .empty,
73 .src_hash_deps = .empty,81 .src_hash_deps = .empty,
74 .nav_val_deps = .empty,82 .nav_val_deps = .empty,
75 .interned_deps = .empty,83 .interned_deps = .empty,
...@@ -656,6 +664,7 @@ pub const Nav = struct {...@@ -656,6 +664,7 @@ pub const Nav = struct {
656};664};
657665
658pub const Dependee = union(enum) {666pub const Dependee = union(enum) {
667 file: FileIndex,
659 src_hash: TrackedInst.Index,668 src_hash: TrackedInst.Index,
660 nav_val: Nav.Index,669 nav_val: Nav.Index,
661 interned: Index,670 interned: Index,
...@@ -704,6 +713,7 @@ pub const DependencyIterator = struct {...@@ -704,6 +713,7 @@ pub const DependencyIterator = struct {
704713
705pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyIterator {714pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyIterator {
706 const first_entry = switch (dependee) {715 const first_entry = switch (dependee) {
716 .file => |x| ip.file_deps.get(x),
707 .src_hash => |x| ip.src_hash_deps.get(x),717 .src_hash => |x| ip.src_hash_deps.get(x),
708 .nav_val => |x| ip.nav_val_deps.get(x),718 .nav_val => |x| ip.nav_val_deps.get(x),
709 .interned => |x| ip.interned_deps.get(x),719 .interned => |x| ip.interned_deps.get(x),
...@@ -740,6 +750,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend...@@ -740,6 +750,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
740 const new_index: DepEntry.Index = switch (dependee) {750 const new_index: DepEntry.Index = switch (dependee) {
741 inline else => |dependee_payload, tag| new_index: {751 inline else => |dependee_payload, tag| new_index: {
742 const gop = try switch (tag) {752 const gop = try switch (tag) {
753 .file => ip.file_deps,
743 .src_hash => ip.src_hash_deps,754 .src_hash => ip.src_hash_deps,
744 .nav_val => ip.nav_val_deps,755 .nav_val => ip.nav_val_deps,
745 .interned => ip.interned_deps,756 .interned => ip.interned_deps,
...@@ -6268,6 +6279,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {...@@ -6268,6 +6279,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
6268}6279}
62696280
6270pub fn deinit(ip: *InternPool, gpa: Allocator) void {6281pub fn deinit(ip: *InternPool, gpa: Allocator) void {
6282 ip.file_deps.deinit(gpa);
6271 ip.src_hash_deps.deinit(gpa);6283 ip.src_hash_deps.deinit(gpa);
6272 ip.nav_val_deps.deinit(gpa);6284 ip.nav_val_deps.deinit(gpa);
6273 ip.interned_deps.deinit(gpa);6285 ip.interned_deps.deinit(gpa);
src/Package/Module.zig+1
...@@ -454,6 +454,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {...@@ -454,6 +454,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
454 .tree = undefined,454 .tree = undefined,
455 .zir = undefined,455 .zir = undefined,
456 .status = .never_loaded,456 .status = .never_loaded,
457 .prev_status = .never_loaded,
457 .mod = new,458 .mod = new,
458 };459 };
459 break :b new;460 break :b new;
src/Sema.zig+3-8
...@@ -2559,10 +2559,9 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg...@@ -2559,10 +2559,9 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg
2559 const zcu = sema.pt.zcu;2559 const zcu = sema.pt.zcu;
25602560
2561 if (build_options.enable_debug_extensions and zcu.comp.debug_compile_errors) {2561 if (build_options.enable_debug_extensions and zcu.comp.debug_compile_errors) {
2562 var all_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?Zcu.ResolvedReference) = null;
2563 var wip_errors: std.zig.ErrorBundle.Wip = undefined;2562 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
2564 wip_errors.init(gpa) catch @panic("out of memory");2563 wip_errors.init(gpa) catch @panic("out of memory");
2565 Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*, &all_references) catch @panic("out of memory");2564 Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*) catch @panic("out of memory");
2566 std.debug.print("compile error during Sema:\n", .{});2565 std.debug.print("compile error during Sema:\n", .{});
2567 var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory");2566 var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory");
2568 error_bundle.renderToStdErr(.{ .ttyconf = .no_color });2567 error_bundle.renderToStdErr(.{ .ttyconf = .no_color });
...@@ -6025,9 +6024,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -6025,9 +6024,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
6025 pt.astGenFile(result.file, path_digest) catch |err|6024 pt.astGenFile(result.file, path_digest) catch |err|
6026 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});6025 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
60276026
6028 // TODO: register some kind of dependency on the file.6027 try sema.declareDependency(.{ .file = result.file_index });
6029 // That way, if this returns `error.AnalysisFail`, we have the dependency banked ready to
6030 // trigger re-analysis later.
6031 try pt.ensureFileAnalyzed(result.file_index);6028 try pt.ensureFileAnalyzed(result.file_index);
6032 const ty = zcu.fileRootType(result.file_index);6029 const ty = zcu.fileRootType(result.file_index);
6033 try sema.declareDependency(.{ .interned = ty });6030 try sema.declareDependency(.{ .interned = ty });
...@@ -14348,9 +14345,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -14348,9 +14345,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
14348 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });14345 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
14349 },14346 },
14350 };14347 };
14351 // TODO: register some kind of dependency on the file.14348 try sema.declareDependency(.{ .file = result.file_index });
14352 // That way, if this returns `error.AnalysisFail`, we have the dependency banked ready to
14353 // trigger re-analysis later.
14354 try pt.ensureFileAnalyzed(result.file_index);14349 try pt.ensureFileAnalyzed(result.file_index);
14355 const ty = zcu.fileRootType(result.file_index);14350 const ty = zcu.fileRootType(result.file_index);
14356 try sema.declareDependency(.{ .interned = ty });14351 try sema.declareDependency(.{ .interned = ty });
src/Zcu.zig+40-8
...@@ -173,6 +173,10 @@ retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .empty,...@@ -173,6 +173,10 @@ retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .empty,
173/// These are the modules which we initially queue for analysis in `Compilation.update`.173/// These are the modules which we initially queue for analysis in `Compilation.update`.
174/// `resolveReferences` will use these as the root of its reachability traversal.174/// `resolveReferences` will use these as the root of its reachability traversal.
175analysis_roots: std.BoundedArray(*Package.Module, 3) = .{},175analysis_roots: std.BoundedArray(*Package.Module, 3) = .{},
176/// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and
177/// reset to `null` when any semantic analysis occurs (since this invalidates the data).
178/// Allocated into `gpa`.
179resolved_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = null,
176180
177stage1_flags: packed struct {181stage1_flags: packed struct {
178 have_winmain: bool = false,182 have_winmain: bool = false,
...@@ -420,13 +424,8 @@ pub const Namespace = struct {...@@ -420,13 +424,8 @@ pub const Namespace = struct {
420};424};
421425
422pub const File = struct {426pub const File = struct {
423 status: enum {427 status: Status,
424 never_loaded,428 prev_status: Status,
425 retryable_failure,
426 parse_failure,
427 astgen_failure,
428 success_zir,
429 },
430 source_loaded: bool,429 source_loaded: bool,
431 tree_loaded: bool,430 tree_loaded: bool,
432 zir_loaded: bool,431 zir_loaded: bool,
...@@ -454,6 +453,14 @@ pub const File = struct {...@@ -454,6 +453,14 @@ pub const File = struct {
454 /// successful, this field is unloaded.453 /// successful, this field is unloaded.
455 prev_zir: ?*Zir = null,454 prev_zir: ?*Zir = null,
456455
456 pub const Status = enum {
457 never_loaded,
458 retryable_failure,
459 parse_failure,
460 astgen_failure,
461 success_zir,
462 };
463
457 /// A single reference to a file.464 /// A single reference to a file.
458 pub const Reference = union(enum) {465 pub const Reference = union(enum) {
459 /// The file is imported directly (i.e. not as a package) with @import.466 /// The file is imported directly (i.e. not as a package) with @import.
...@@ -2192,6 +2199,8 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2192,6 +2199,8 @@ pub fn deinit(zcu: *Zcu) void {
2192 zcu.all_type_references.deinit(gpa);2199 zcu.all_type_references.deinit(gpa);
2193 zcu.free_type_references.deinit(gpa);2200 zcu.free_type_references.deinit(gpa);
21942201
2202 if (zcu.resolved_references) |*r| r.deinit(gpa);
2203
2195 zcu.intern_pool.deinit(gpa);2204 zcu.intern_pool.deinit(gpa);
2196}2205}
21972206
...@@ -2760,6 +2769,8 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {...@@ -2760,6 +2769,8 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
2760pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {2769pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
2761 const gpa = zcu.gpa;2770 const gpa = zcu.gpa;
27622771
2772 zcu.clearCachedResolvedReferences();
2773
2763 unit_refs: {2774 unit_refs: {
2764 const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse break :unit_refs;2775 const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse break :unit_refs;
2765 var idx = kv.value;2776 var idx = kv.value;
...@@ -2792,6 +2803,8 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {...@@ -2792,6 +2803,8 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
2792pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void {2803pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void {
2793 const gpa = zcu.gpa;2804 const gpa = zcu.gpa;
27942805
2806 zcu.clearCachedResolvedReferences();
2807
2795 try zcu.reference_table.ensureUnusedCapacity(gpa, 1);2808 try zcu.reference_table.ensureUnusedCapacity(gpa, 1);
27962809
2797 const ref_idx = zcu.free_references.popOrNull() orelse idx: {2810 const ref_idx = zcu.free_references.popOrNull() orelse idx: {
...@@ -2815,6 +2828,8 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit...@@ -2815,6 +2828,8 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit
2815pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPool.Index, ref_src: LazySrcLoc) Allocator.Error!void {2828pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPool.Index, ref_src: LazySrcLoc) Allocator.Error!void {
2816 const gpa = zcu.gpa;2829 const gpa = zcu.gpa;
28172830
2831 zcu.clearCachedResolvedReferences();
2832
2818 try zcu.type_reference_table.ensureUnusedCapacity(gpa, 1);2833 try zcu.type_reference_table.ensureUnusedCapacity(gpa, 1);
28192834
2820 const ref_idx = zcu.free_type_references.popOrNull() orelse idx: {2835 const ref_idx = zcu.free_type_references.popOrNull() orelse idx: {
...@@ -2835,6 +2850,11 @@ pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPo...@@ -2835,6 +2850,11 @@ pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPo
2835 gop.value_ptr.* = @intCast(ref_idx);2850 gop.value_ptr.* = @intCast(ref_idx);
2836}2851}
28372852
2853fn clearCachedResolvedReferences(zcu: *Zcu) void {
2854 if (zcu.resolved_references) |*r| r.deinit(zcu.gpa);
2855 zcu.resolved_references = null;
2856}
2857
2838pub fn errorSetBits(zcu: *const Zcu) u16 {2858pub fn errorSetBits(zcu: *const Zcu) u16 {
2839 if (zcu.error_limit == 0) return 0;2859 if (zcu.error_limit == 0) return 0;
2840 return @as(u16, std.math.log2_int(ErrorInt, zcu.error_limit)) + 1;2860 return @as(u16, std.math.log2_int(ErrorInt, zcu.error_limit)) + 1;
...@@ -3138,7 +3158,15 @@ pub const ResolvedReference = struct {...@@ -3138,7 +3158,15 @@ pub const ResolvedReference = struct {
3138/// Returns a mapping from an `AnalUnit` to where it is referenced.3158/// Returns a mapping from an `AnalUnit` to where it is referenced.
3139/// If the value is `null`, the `AnalUnit` is a root of analysis.3159/// If the value is `null`, the `AnalUnit` is a root of analysis.
3140/// If an `AnalUnit` is not in the returned map, it is unreferenced.3160/// If an `AnalUnit` is not in the returned map, it is unreferenced.
3141pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) {3161/// The returned hashmap is owned by the `Zcu`, so should not be freed by the caller.
3162/// This hashmap is cached, so repeated calls to this function are cheap.
3163pub fn resolveReferences(zcu: *Zcu) !*const std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
3164 if (zcu.resolved_references == null) {
3165 zcu.resolved_references = try zcu.resolveReferencesInner();
3166 }
3167 return &zcu.resolved_references.?;
3168}
3169fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
3142 const gpa = zcu.gpa;3170 const gpa = zcu.gpa;
3143 const comp = zcu.comp;3171 const comp = zcu.comp;
3144 const ip = &zcu.intern_pool;3172 const ip = &zcu.intern_pool;
...@@ -3449,6 +3477,10 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com...@@ -3449,6 +3477,10 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
3449 const zcu = data.zcu;3477 const zcu = data.zcu;
3450 const ip = &zcu.intern_pool;3478 const ip = &zcu.intern_pool;
3451 switch (data.dependee) {3479 switch (data.dependee) {
3480 .file => |file| {
3481 const file_path = zcu.fileByIndex(file).sub_file_path;
3482 return writer.print("file('{s}')", .{file_path});
3483 },
3452 .src_hash => |ti| {3484 .src_hash => |ti| {
3453 const info = ti.resolveFull(ip) orelse {3485 const info = ti.resolveFull(ip) orelse {
3454 return writer.writeAll("inst(<lost>)");3486 return writer.writeAll("inst(<lost>)");
src/Zcu/PerThread.zig+26-10
...@@ -179,10 +179,10 @@ pub fn astGenFile(...@@ -179,10 +179,10 @@ pub fn astGenFile(
179 .inode = header.stat_inode,179 .inode = header.stat_inode,
180 .mtime = header.stat_mtime,180 .mtime = header.stat_mtime,
181 };181 };
182 file.prev_status = file.status;
182 file.status = .success_zir;183 file.status = .success_zir;
183 log.debug("AstGen cached success: {s}", .{file.sub_file_path});184 log.debug("AstGen cached success: {s}", .{file.sub_file_path});
184185
185 // TODO don't report compile errors until Sema @importFile
186 if (file.zir.hasCompileErrors()) {186 if (file.zir.hasCompileErrors()) {
187 {187 {
188 comp.mutex.lock();188 comp.mutex.lock();
...@@ -258,6 +258,7 @@ pub fn astGenFile(...@@ -258,6 +258,7 @@ pub fn astGenFile(
258 // Any potential AST errors are converted to ZIR errors here.258 // Any potential AST errors are converted to ZIR errors here.
259 file.zir = try AstGen.generate(gpa, file.tree);259 file.zir = try AstGen.generate(gpa, file.tree);
260 file.zir_loaded = true;260 file.zir_loaded = true;
261 file.prev_status = file.status;
261 file.status = .success_zir;262 file.status = .success_zir;
262 log.debug("AstGen fresh success: {s}", .{file.sub_file_path});263 log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
263264
...@@ -350,6 +351,9 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -350,6 +351,9 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
350 defer cleanupUpdatedFiles(gpa, &updated_files);351 defer cleanupUpdatedFiles(gpa, &updated_files);
351 for (zcu.import_table.values()) |file_index| {352 for (zcu.import_table.values()) |file_index| {
352 const file = zcu.fileByIndex(file_index);353 const file = zcu.fileByIndex(file_index);
354 if (file.prev_status != file.status and file.prev_status != .never_loaded) {
355 try zcu.markDependeeOutdated(.not_marked_po, .{ .file = file_index });
356 }
353 const old_zir = file.prev_zir orelse continue;357 const old_zir = file.prev_zir orelse continue;
354 const new_zir = file.zir;358 const new_zir = file.zir;
355 const gop = try updated_files.getOrPut(gpa, file_index);359 const gop = try updated_files.getOrPut(gpa, file_index);
...@@ -551,11 +555,13 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu...@@ -551,11 +555,13 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
551 const cau_outdated = zcu.outdated.swapRemove(anal_unit) or555 const cau_outdated = zcu.outdated.swapRemove(anal_unit) or
552 zcu.potentially_outdated.swapRemove(anal_unit);556 zcu.potentially_outdated.swapRemove(anal_unit);
553557
558 const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit);
559
554 if (cau_outdated) {560 if (cau_outdated) {
555 _ = zcu.outdated_ready.swapRemove(anal_unit);561 _ = zcu.outdated_ready.swapRemove(anal_unit);
556 } else {562 } else {
557 // We can trust the current information about this `Cau`.563 // We can trust the current information about this `Cau`.
558 if (zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit)) {564 if (prev_failed) {
559 return error.AnalysisFail;565 return error.AnalysisFail;
560 }566 }
561 // If it wasn't failed and wasn't marked outdated, then either...567 // If it wasn't failed and wasn't marked outdated, then either...
...@@ -578,9 +584,13 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu...@@ -578,9 +584,13 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
578 // Since it does not, this must be a transitive failure.584 // Since it does not, this must be a transitive failure.
579 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});585 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
580 }586 }
581 // We treat errors as up-to-date, since those uses would just trigger a transitive error.587 // We consider this `Cau` to be outdated if:
582 // The exception is types, since type declarations may require re-analysis if the type, e.g. its captures, changed.588 // * Previous analysis succeeded; in this case, we need to re-analyze dependants to ensure
583 const outdated = cau.owner.unwrap() == .type;589 // they hit a transitive error here, rather than reporting a different error later (which
590 // may now be invalid).
591 // * The `Cau` is a type; in this case, the declaration site may require re-analysis to
592 // construct a valid type.
593 const outdated = !prev_failed or cau.owner.unwrap() == .type;
584 break :res .{ .{594 break :res .{ .{
585 .invalidate_decl_val = outdated,595 .invalidate_decl_val = outdated,
586 .invalidate_decl_ref = outdated,596 .invalidate_decl_ref = outdated,
...@@ -597,10 +607,9 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu...@@ -597,10 +607,9 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
597 );607 );
598 zcu.retryable_failures.appendAssumeCapacity(anal_unit);608 zcu.retryable_failures.appendAssumeCapacity(anal_unit);
599 zcu.failed_analysis.putAssumeCapacityNoClobber(anal_unit, msg);609 zcu.failed_analysis.putAssumeCapacityNoClobber(anal_unit, msg);
600 // We treat errors as up-to-date, since those uses would just trigger a transitive error
601 break :res .{ .{610 break :res .{ .{
602 .invalidate_decl_val = false,611 .invalidate_decl_val = true,
603 .invalidate_decl_ref = false,612 .invalidate_decl_ref = true,
604 }, true };613 }, true };
605 },614 },
606 };615 };
...@@ -707,11 +716,13 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter...@@ -707,11 +716,13 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
707 const func_outdated = zcu.outdated.swapRemove(anal_unit) or716 const func_outdated = zcu.outdated.swapRemove(anal_unit) or
708 zcu.potentially_outdated.swapRemove(anal_unit);717 zcu.potentially_outdated.swapRemove(anal_unit);
709718
719 const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit);
720
710 if (func_outdated) {721 if (func_outdated) {
711 _ = zcu.outdated_ready.swapRemove(anal_unit);722 _ = zcu.outdated_ready.swapRemove(anal_unit);
712 } else {723 } else {
713 // We can trust the current information about this function.724 // We can trust the current information about this function.
714 if (zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit)) {725 if (prev_failed) {
715 return error.AnalysisFail;726 return error.AnalysisFail;
716 }727 }
717 switch (func.analysisUnordered(ip).state) {728 switch (func.analysisUnordered(ip).state) {
...@@ -730,7 +741,10 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter...@@ -730,7 +741,10 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
730 // Since it does not, this must be a transitive failure.741 // Since it does not, this must be a transitive failure.
731 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});742 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
732 }743 }
733 break :res .{ false, true }; // we treat errors as up-to-date IES, since those uses would just trigger a transitive error744 // We consider the IES to be outdated if the function previously succeeded analysis; in this case,
745 // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting
746 // a different error later (which may now be invalid).
747 break :res .{ !prev_failed, true };
734 },748 },
735 error.OutOfMemory => return error.OutOfMemory, // TODO: graceful handling like `ensureCauAnalyzed`749 error.OutOfMemory => return error.OutOfMemory, // TODO: graceful handling like `ensureCauAnalyzed`
736 };750 };
...@@ -1445,6 +1459,7 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {...@@ -1445,6 +1459,7 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {
1445 .tree = undefined,1459 .tree = undefined,
1446 .zir = undefined,1460 .zir = undefined,
1447 .status = .never_loaded,1461 .status = .never_loaded,
1462 .prev_status = .never_loaded,
1448 .mod = mod,1463 .mod = mod,
1449 };1464 };
14501465
...@@ -1555,6 +1570,7 @@ pub fn importFile(...@@ -1555,6 +1570,7 @@ pub fn importFile(
1555 .tree = undefined,1570 .tree = undefined,
1556 .zir = undefined,1571 .zir = undefined,
1557 .status = .never_loaded,1572 .status = .never_loaded,
1573 .prev_status = .never_loaded,
1558 .mod = mod,1574 .mod = mod,
1559 };1575 };
15601576
src/main.zig+3
...@@ -6118,6 +6118,7 @@ fn cmdAstCheck(...@@ -6118,6 +6118,7 @@ fn cmdAstCheck(
61186118
6119 var file: Zcu.File = .{6119 var file: Zcu.File = .{
6120 .status = .never_loaded,6120 .status = .never_loaded,
6121 .prev_status = .never_loaded,
6121 .source_loaded = false,6122 .source_loaded = false,
6122 .tree_loaded = false,6123 .tree_loaded = false,
6123 .zir_loaded = false,6124 .zir_loaded = false,
...@@ -6441,6 +6442,7 @@ fn cmdDumpZir(...@@ -6441,6 +6442,7 @@ fn cmdDumpZir(
64416442
6442 var file: Zcu.File = .{6443 var file: Zcu.File = .{
6443 .status = .never_loaded,6444 .status = .never_loaded,
6445 .prev_status = .never_loaded,
6444 .source_loaded = false,6446 .source_loaded = false,
6445 .tree_loaded = false,6447 .tree_loaded = false,
6446 .zir_loaded = true,6448 .zir_loaded = true,
...@@ -6508,6 +6510,7 @@ fn cmdChangelist(...@@ -6508,6 +6510,7 @@ fn cmdChangelist(
65086510
6509 var file: Zcu.File = .{6511 var file: Zcu.File = .{
6510 .status = .never_loaded,6512 .status = .never_loaded,
6513 .prev_status = .never_loaded,
6511 .source_loaded = false,6514 .source_loaded = false,
6512 .tree_loaded = false,6515 .tree_loaded = false,
6513 .zir_loaded = false,6516 .zir_loaded = false,
test/incremental/add_decl+2-1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1// Disabled on self-hosted due to linker crash
2// #target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#update=initial version5#update=initial version
test/incremental/fix_astgen_failure created+35
...@@ -0,0 +1,35 @@
1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe
4#update=initial version with error
5#file=main.zig
6pub fn main() !void {
7 try @import("foo.zig").hello();
8}
9#file=foo.zig
10pub fn hello() !void {
11 try std.io.getStdOut().writeAll("Hello, World!\n");
12}
13#expect_error=ignored
14#update=fix the error
15#file=foo.zig
16const std = @import("std");
17pub fn hello() !void {
18 try std.io.getStdOut().writeAll("Hello, World!\n");
19}
20#expect_stdout="Hello, World!\n"
21#update=add new error
22#file=foo.zig
23const std = @import("std");
24pub fn hello() !void {
25 try std.io.getStdOut().writeAll(hello_str);
26}
27#expect_error=ignored
28#update=fix the new error
29#file=foo.zig
30const std = @import("std");
31const hello_str = "Hello, World! Again!\n";
32pub fn hello() !void {
33 try std.io.getStdOut().writeAll(hello_str);
34}
35#expect_stdout="Hello, World! Again!\n"
test/incremental/remove_invalid_union_backing_enum created+30
...@@ -0,0 +1,30 @@
1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe
4#update=initial version
5#file=main.zig
6const E = enum { a, b, c };
7const U = union(E) {
8 a: i32,
9 b: f64,
10 c: f64,
11 d: f64,
12};
13pub fn main() void {
14 const u: U = .{ .a = 123 };
15 _ = u;
16}
17#expect_error=ignored
18#update=remove invalid backing enum
19#file=main.zig
20const U = union {
21 a: i32,
22 b: f64,
23 c: f64,
24 d: f64,
25};
26pub fn main() void {
27 const u: U = .{ .a = 123 };
28 _ = u;
29}
30#expect_stdout=""