authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-10-16 15:56:48+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-10-16 16:30:36+01:00
log22539783ad15be3028ed07983eb8e23910171f11
tree0ace6676df00397e4ca4df098013220f95e85bf7
parentc6842b58d488c236aca74dea82082eec365eb117
signaturelock-open Commit is signed but in an unrecognized format.

incremental: introduce `file` dependencies to handle AstGen failures

The re-analysis here is a little coarse; it'd be nice in the future to have a way for an AstGen failure to preserve *all* analysis which depends on the last success, and just hide the compile errors which depend on it somehow. But I'm not sure how we'd achieve that, so this works fine for now. Resolves: #21223

8 files changed, 97 insertions(+), 23 deletions(-)

src/Compilation.zig+4
...@@ -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()));
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+2-6
...@@ -6024,9 +6024,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -6024,9 +6024,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
6024 pt.astGenFile(result.file, path_digest) catch |err|6024 pt.astGenFile(result.file, path_digest) catch |err|
6025 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)});
60266026
6027 // TODO: register some kind of dependency on the file.6027 try sema.declareDependency(.{ .file = result.file_index });
6028 // That way, if this returns `error.AnalysisFail`, we have the dependency banked ready to
6029 // trigger re-analysis later.
6030 try pt.ensureFileAnalyzed(result.file_index);6028 try pt.ensureFileAnalyzed(result.file_index);
6031 const ty = zcu.fileRootType(result.file_index);6029 const ty = zcu.fileRootType(result.file_index);
6032 try sema.declareDependency(.{ .interned = ty });6030 try sema.declareDependency(.{ .interned = ty });
...@@ -14347,9 +14345,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -14347,9 +14345,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
14347 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) });
14348 },14346 },
14349 };14347 };
14350 // TODO: register some kind of dependency on the file.14348 try sema.declareDependency(.{ .file = result.file_index });
14351 // That way, if this returns `error.AnalysisFail`, we have the dependency banked ready to
14352 // trigger re-analysis later.
14353 try pt.ensureFileAnalyzed(result.file_index);14349 try pt.ensureFileAnalyzed(result.file_index);
14354 const ty = zcu.fileRootType(result.file_index);14350 const ty = zcu.fileRootType(result.file_index);
14355 try sema.declareDependency(.{ .interned = ty });14351 try sema.declareDependency(.{ .interned = ty });
src/Zcu.zig+14-7
...@@ -424,13 +424,8 @@ pub const Namespace = struct {...@@ -424,13 +424,8 @@ pub const Namespace = struct {
424};424};
425425
426pub const File = struct {426pub const File = struct {
427 status: enum {427 status: Status,
428 never_loaded,428 prev_status: Status,
429 retryable_failure,
430 parse_failure,
431 astgen_failure,
432 success_zir,
433 },
434 source_loaded: bool,429 source_loaded: bool,
435 tree_loaded: bool,430 tree_loaded: bool,
436 zir_loaded: bool,431 zir_loaded: bool,
...@@ -458,6 +453,14 @@ pub const File = struct {...@@ -458,6 +453,14 @@ pub const File = struct {
458 /// successful, this field is unloaded.453 /// successful, this field is unloaded.
459 prev_zir: ?*Zir = null,454 prev_zir: ?*Zir = null,
460455
456 pub const Status = enum {
457 never_loaded,
458 retryable_failure,
459 parse_failure,
460 astgen_failure,
461 success_zir,
462 };
463
461 /// A single reference to a file.464 /// A single reference to a file.
462 pub const Reference = union(enum) {465 pub const Reference = union(enum) {
463 /// 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.
...@@ -3474,6 +3477,10 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com...@@ -3474,6 +3477,10 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
3474 const zcu = data.zcu;3477 const zcu = data.zcu;
3475 const ip = &zcu.intern_pool;3478 const ip = &zcu.intern_pool;
3476 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 },
3477 .src_hash => |ti| {3484 .src_hash => |ti| {
3478 const info = ti.resolveFull(ip) orelse {3485 const info = ti.resolveFull(ip) orelse {
3479 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/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"