authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-02-05 12:17:13+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-02-05 12:17:13+00:00
logf01f1e33c96f0b00db8e036a654c1b3bf8531cd8
tree3daca71f83a02d73d4c93d973d7022776e476274
parentcf059ee08716300e924bced08ebdd5bd8f97d789
parentbebfa036ba52076cd03f9ef943f61da64ba6e97b
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22754 from mlugg/files-and-stuff

ZON and incremental bits

16 files changed, 788 insertions(+), 587 deletions(-)

lib/std/zig/Zoir.zig+25
...@@ -10,6 +10,31 @@ string_bytes: []u8,...@@ -10,6 +10,31 @@ string_bytes: []u8,
10compile_errors: []Zoir.CompileError,10compile_errors: []Zoir.CompileError,
11error_notes: []Zoir.CompileError.Note,11error_notes: []Zoir.CompileError.Note,
1212
13/// The data stored at byte offset 0 when ZOIR is stored in a file.
14pub const Header = extern struct {
15 nodes_len: u32,
16 extra_len: u32,
17 limbs_len: u32,
18 string_bytes_len: u32,
19 compile_errors_len: u32,
20 error_notes_len: u32,
21
22 /// We could leave this as padding, however it triggers a Valgrind warning because
23 /// we read and write undefined bytes to the file system. This is harmless, but
24 /// it's essentially free to have a zero field here and makes the warning go away,
25 /// making it more likely that following Valgrind warnings will be taken seriously.
26 unused: u64 = 0,
27
28 stat_inode: std.fs.File.INode,
29 stat_size: u64,
30 stat_mtime: i128,
31
32 comptime {
33 // Check that `unused` is working as expected
34 assert(std.meta.hasUniqueRepresentation(Header));
35 }
36};
37
13pub fn hasCompileErrors(zoir: Zoir) bool {38pub fn hasCompileErrors(zoir: Zoir) bool {
14 if (zoir.compile_errors.len > 0) {39 if (zoir.compile_errors.len > 0) {
15 assert(zoir.nodes.len == 0);40 assert(zoir.nodes.len == 0);
src/Builtin.zig+10-14
...@@ -264,14 +264,12 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {...@@ -264,14 +264,12 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
264}264}
265265
266pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void {266pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void {
267 assert(file.source_loaded == true);
268
269 if (mod.root.statFile(mod.root_src_path)) |stat| {267 if (mod.root.statFile(mod.root_src_path)) |stat| {
270 if (stat.size != file.source.len) {268 if (stat.size != file.source.?.len) {
271 std.log.warn(269 std.log.warn(
272 "the cached file '{}{s}' had the wrong size. Expected {d}, found {d}. " ++270 "the cached file '{}{s}' had the wrong size. Expected {d}, found {d}. " ++
273 "Overwriting with correct file contents now",271 "Overwriting with correct file contents now",
274 .{ mod.root, mod.root_src_path, file.source.len, stat.size },272 .{ mod.root, mod.root_src_path, file.source.?.len, stat.size },
275 );273 );
276274
277 try writeFile(file, mod);275 try writeFile(file, mod);
...@@ -296,15 +294,13 @@ pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void {...@@ -296,15 +294,13 @@ pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void {
296294
297 log.debug("parsing and generating '{s}'", .{mod.root_src_path});295 log.debug("parsing and generating '{s}'", .{mod.root_src_path});
298296
299 file.tree = try std.zig.Ast.parse(comp.gpa, file.source, .zig);297 file.tree = try std.zig.Ast.parse(comp.gpa, file.source.?, .zig);
300 assert(file.tree.errors.len == 0); // builtin.zig must parse298 assert(file.tree.?.errors.len == 0); // builtin.zig must parse
301 file.tree_loaded = true;
302299
303 file.zir = try AstGen.generate(comp.gpa, file.tree);300 file.zir = try AstGen.generate(comp.gpa, file.tree.?);
304 assert(!file.zir.hasCompileErrors()); // builtin.zig must not have astgen errors301 assert(!file.zir.?.hasCompileErrors()); // builtin.zig must not have astgen errors
305 file.zir_loaded = true;302 file.status = .success;
306 file.status = .success_zir;303 // Note that whilst we set `zir` here, we populated `path_digest`
307 // Note that whilst we set `zir_loaded` here, we populated `path_digest`
308 // all the way back in `Package.Module.create`.304 // all the way back in `Package.Module.create`.
309}305}
310306
...@@ -312,7 +308,7 @@ fn writeFile(file: *File, mod: *Module) !void {...@@ -312,7 +308,7 @@ fn writeFile(file: *File, mod: *Module) !void {
312 var buf: [std.fs.max_path_bytes]u8 = undefined;308 var buf: [std.fs.max_path_bytes]u8 = undefined;
313 var af = try mod.root.atomicFile(mod.root_src_path, .{ .make_path = true }, &buf);309 var af = try mod.root.atomicFile(mod.root_src_path, .{ .make_path = true }, &buf);
314 defer af.deinit();310 defer af.deinit();
315 try af.file.writeAll(file.source);311 try af.file.writeAll(file.source.?);
316 af.finish() catch |err| switch (err) {312 af.finish() catch |err| switch (err) {
317 error.AccessDenied => switch (builtin.os.tag) {313 error.AccessDenied => switch (builtin.os.tag) {
318 .windows => {314 .windows => {
...@@ -326,7 +322,7 @@ fn writeFile(file: *File, mod: *Module) !void {...@@ -326,7 +322,7 @@ fn writeFile(file: *File, mod: *Module) !void {
326 };322 };
327323
328 file.stat = .{324 file.stat = .{
329 .size = file.source.len,325 .size = file.source.?.len,
330 .inode = 0, // dummy value326 .inode = 0, // dummy value
331 .mtime = 0, // dummy value327 .mtime = 0, // dummy value
332 };328 };
src/Compilation.zig+92-54
...@@ -2220,10 +2220,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2220,10 +2220,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
2220 try comp.astgen_work_queue.ensureUnusedCapacity(zcu.import_table.count());2220 try comp.astgen_work_queue.ensureUnusedCapacity(zcu.import_table.count());
2221 for (zcu.import_table.values()) |file_index| {2221 for (zcu.import_table.values()) |file_index| {
2222 if (zcu.fileByIndex(file_index).mod.isBuiltin()) continue;2222 if (zcu.fileByIndex(file_index).mod.isBuiltin()) continue;
2223 const file = zcu.fileByIndex(file_index);2223 comp.astgen_work_queue.writeItemAssumeCapacity(file_index);
2224 if (file.getMode() == .zig) {
2225 comp.astgen_work_queue.writeItemAssumeCapacity(file_index);
2226 }
2227 }2224 }
2228 if (comp.file_system_inputs) |fsi| {2225 if (comp.file_system_inputs) |fsi| {
2229 for (zcu.import_table.values()) |file_index| {2226 for (zcu.import_table.values()) |file_index| {
...@@ -2906,10 +2903,12 @@ pub fn makeBinFileWritable(comp: *Compilation) !void {...@@ -2906,10 +2903,12 @@ pub fn makeBinFileWritable(comp: *Compilation) !void {
2906const Header = extern struct {2903const Header = extern struct {
2907 intern_pool: extern struct {2904 intern_pool: extern struct {
2908 thread_count: u32,2905 thread_count: u32,
2909 file_deps_len: u32,
2910 src_hash_deps_len: u32,2906 src_hash_deps_len: u32,
2911 nav_val_deps_len: u32,2907 nav_val_deps_len: u32,
2912 nav_ty_deps_len: u32,2908 nav_ty_deps_len: u32,
2909 interned_deps_len: u32,
2910 zon_file_deps_len: u32,
2911 embed_file_deps_len: u32,
2913 namespace_deps_len: u32,2912 namespace_deps_len: u32,
2914 namespace_name_deps_len: u32,2913 namespace_name_deps_len: u32,
2915 first_dependency_len: u32,2914 first_dependency_len: u32,
...@@ -2950,10 +2949,12 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2950,10 +2949,12 @@ pub fn saveState(comp: *Compilation) !void {
2950 const header: Header = .{2949 const header: Header = .{
2951 .intern_pool = .{2950 .intern_pool = .{
2952 .thread_count = @intCast(ip.locals.len),2951 .thread_count = @intCast(ip.locals.len),
2953 .file_deps_len = @intCast(ip.file_deps.count()),
2954 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),2952 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),
2955 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()),2953 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()),
2956 .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()),2954 .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()),
2955 .interned_deps_len = @intCast(ip.interned_deps.count()),
2956 .zon_file_deps_len = @intCast(ip.zon_file_deps.count()),
2957 .embed_file_deps_len = @intCast(ip.embed_file_deps.count()),
2957 .namespace_deps_len = @intCast(ip.namespace_deps.count()),2958 .namespace_deps_len = @intCast(ip.namespace_deps.count()),
2958 .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()),2959 .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()),
2959 .first_dependency_len = @intCast(ip.first_dependency.count()),2960 .first_dependency_len = @intCast(ip.first_dependency.count()),
...@@ -2978,14 +2979,18 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2978,14 +2979,18 @@ pub fn saveState(comp: *Compilation) !void {
2978 addBuf(&bufs, mem.asBytes(&header));2979 addBuf(&bufs, mem.asBytes(&header));
2979 addBuf(&bufs, mem.sliceAsBytes(pt_headers.items));2980 addBuf(&bufs, mem.sliceAsBytes(pt_headers.items));
29802981
2981 addBuf(&bufs, mem.sliceAsBytes(ip.file_deps.keys()));
2982 addBuf(&bufs, mem.sliceAsBytes(ip.file_deps.values()));
2983 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.keys()));2982 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.keys()));
2984 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values()));2983 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values()));
2985 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys()));2984 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys()));
2986 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.values()));2985 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.values()));
2987 addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.keys()));2986 addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.keys()));
2988 addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.values()));2987 addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.values()));
2988 addBuf(&bufs, mem.sliceAsBytes(ip.interned_deps.keys()));
2989 addBuf(&bufs, mem.sliceAsBytes(ip.interned_deps.values()));
2990 addBuf(&bufs, mem.sliceAsBytes(ip.zon_file_deps.keys()));
2991 addBuf(&bufs, mem.sliceAsBytes(ip.zon_file_deps.values()));
2992 addBuf(&bufs, mem.sliceAsBytes(ip.embed_file_deps.keys()));
2993 addBuf(&bufs, mem.sliceAsBytes(ip.embed_file_deps.values()));
2989 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys()));2994 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys()));
2990 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values()));2995 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values()));
2991 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys()));2996 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys()));
...@@ -3203,15 +3208,13 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3203,15 +3208,13 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3203 }3208 }
32043209
3205 if (comp.zcu) |zcu| {3210 if (comp.zcu) |zcu| {
3206 const ip = &zcu.intern_pool;
3207
3208 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {3211 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {
3209 if (error_msg) |msg| {3212 if (error_msg) |msg| {
3210 try addModuleErrorMsg(zcu, &bundle, msg.*);3213 try addModuleErrorMsg(zcu, &bundle, msg.*);
3211 } else {3214 } else {
3212 // Must be ZIR or Zoir errors. Note that this may include AST errors.3215 // Must be ZIR or Zoir errors. Note that this may include AST errors.
3213 _ = try file.getTree(gpa); // Tree must be loaded.3216 _ = try file.getTree(gpa); // Tree must be loaded.
3214 if (file.zir_loaded) {3217 if (file.zir != null) {
3215 try addZirErrorMessages(&bundle, file);3218 try addZirErrorMessages(&bundle, file);
3216 } else if (file.zoir != null) {3219 } else if (file.zoir != null) {
3217 try addZoirErrorMessages(&bundle, file);3220 try addZoirErrorMessages(&bundle, file);
...@@ -3277,20 +3280,6 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3277,20 +3280,6 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3277 if (!refs.contains(anal_unit)) continue;3280 if (!refs.contains(anal_unit)) continue;
3278 }3281 }
32793282
3280 report_ok: {
3281 const file_index = switch (anal_unit.unwrap()) {
3282 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index.resolveFile(ip),
3283 .nav_val, .nav_ty => |nav| ip.getNav(nav).analysis.?.zir_index.resolveFile(ip),
3284 .type => |ty| Type.fromInterned(ty).typeDeclInst(zcu).?.resolveFile(ip),
3285 .func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFile(ip),
3286 .memoized_state => break :report_ok, // always report std.builtin errors
3287 };
3288
3289 // Skip errors for AnalUnits within files that had a parse failure.
3290 // We'll try again once parsing succeeds.
3291 if (!zcu.fileByIndex(file_index).okToReportErrors()) continue;
3292 }
3293
3294 std.log.scoped(.zcu).debug("analysis error '{s}' reported from unit '{}'", .{3283 std.log.scoped(.zcu).debug("analysis error '{s}' reported from unit '{}'", .{
3295 error_msg.msg,3284 error_msg.msg,
3296 zcu.fmtAnalUnit(anal_unit),3285 zcu.fmtAnalUnit(anal_unit),
...@@ -3318,12 +3307,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3318,12 +3307,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3318 }3307 }
3319 }3308 }
3320 }3309 }
3321 for (zcu.failed_codegen.keys(), zcu.failed_codegen.values()) |nav, error_msg| {3310 for (zcu.failed_codegen.values()) |error_msg| {
3322 if (!zcu.navFileScope(nav).okToReportErrors()) continue;
3323 try addModuleErrorMsg(zcu, &bundle, error_msg.*);3311 try addModuleErrorMsg(zcu, &bundle, error_msg.*);
3324 }3312 }
3325 for (zcu.failed_types.keys(), zcu.failed_types.values()) |ty_index, error_msg| {3313 for (zcu.failed_types.values()) |error_msg| {
3326 if (!zcu.typeFileScope(ty_index).okToReportErrors()) continue;
3327 try addModuleErrorMsg(zcu, &bundle, error_msg.*);3314 try addModuleErrorMsg(zcu, &bundle, error_msg.*);
3328 }3315 }
3329 for (zcu.failed_exports.values()) |value| {3316 for (zcu.failed_exports.values()) |value| {
...@@ -3623,22 +3610,17 @@ pub fn addModuleErrorMsg(...@@ -3623,22 +3610,17 @@ pub fn addModuleErrorMsg(
3623}3610}
36243611
3625pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {3612pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
3626 assert(file.zir_loaded);
3627 assert(file.tree_loaded);
3628 assert(file.source_loaded);
3629 const gpa = eb.gpa;3613 const gpa = eb.gpa;
3630 const src_path = try file.fullPath(gpa);3614 const src_path = try file.fullPath(gpa);
3631 defer gpa.free(src_path);3615 defer gpa.free(src_path);
3632 return eb.addZirErrorMessages(file.zir, file.tree, file.source, src_path);3616 return eb.addZirErrorMessages(file.zir.?, file.tree.?, file.source.?, src_path);
3633}3617}
36343618
3635pub fn addZoirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {3619pub fn addZoirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
3636 assert(file.source_loaded);
3637 assert(file.tree_loaded);
3638 const gpa = eb.gpa;3620 const gpa = eb.gpa;
3639 const src_path = try file.fullPath(gpa);3621 const src_path = try file.fullPath(gpa);
3640 defer gpa.free(src_path);3622 defer gpa.free(src_path);
3641 return eb.addZoirErrorMessages(file.zoir.?, file.tree, file.source, src_path);3623 return eb.addZoirErrorMessages(file.zoir.?, file.tree.?, file.source.?, src_path);
3642}3624}
36433625
3644pub fn performAllTheWork(3626pub fn performAllTheWork(
...@@ -3802,7 +3784,7 @@ fn performAllTheWorkInner(...@@ -3802,7 +3784,7 @@ fn performAllTheWorkInner(
3802 // will be needed by the worker threads.3784 // will be needed by the worker threads.
3803 const path_digest = zcu.filePathDigest(file_index);3785 const path_digest = zcu.filePathDigest(file_index);
3804 const file = zcu.fileByIndex(file_index);3786 const file = zcu.fileByIndex(file_index);
3805 comp.thread_pool.spawnWgId(&astgen_wait_group, workerAstGenFile, .{3787 comp.thread_pool.spawnWgId(&astgen_wait_group, workerUpdateFile, .{
3806 comp, file, file_index, path_digest, zir_prog_node, &astgen_wait_group, .root,3788 comp, file, file_index, path_digest, zir_prog_node, &astgen_wait_group, .root,
3807 });3789 });
3808 }3790 }
...@@ -3810,7 +3792,7 @@ fn performAllTheWorkInner(...@@ -3810,7 +3792,7 @@ fn performAllTheWorkInner(
38103792
3811 for (0.., zcu.embed_table.values()) |ef_index_usize, ef| {3793 for (0.., zcu.embed_table.values()) |ef_index_usize, ef| {
3812 const ef_index: Zcu.EmbedFile.Index = @enumFromInt(ef_index_usize);3794 const ef_index: Zcu.EmbedFile.Index = @enumFromInt(ef_index_usize);
3813 comp.thread_pool.spawnWgId(&astgen_wait_group, workerCheckEmbedFile, .{3795 comp.thread_pool.spawnWgId(&astgen_wait_group, workerUpdateEmbedFile, .{
3814 comp, ef_index, ef,3796 comp, ef_index, ef,
3815 });3797 });
3816 }3798 }
...@@ -3832,12 +3814,64 @@ fn performAllTheWorkInner(...@@ -3832,12 +3814,64 @@ fn performAllTheWorkInner(
3832 if (comp.zcu) |zcu| {3814 if (comp.zcu) |zcu| {
3833 const pt: Zcu.PerThread = .activate(zcu, .main);3815 const pt: Zcu.PerThread = .activate(zcu, .main);
3834 defer pt.deactivate();3816 defer pt.deactivate();
3817
3818 // If the cache mode is `whole`, then add every source file to the cache manifest.
3819 switch (comp.cache_use) {
3820 .whole => |whole| if (whole.cache_manifest) |man| {
3821 const gpa = zcu.gpa;
3822 for (zcu.import_table.values()) |file_index| {
3823 const file = zcu.fileByIndex(file_index);
3824 const source = file.getSource(gpa) catch |err| {
3825 try pt.reportRetryableFileError(file_index, "unable to load source: {s}", .{@errorName(err)});
3826 continue;
3827 };
3828 const resolved_path = try std.fs.path.resolve(gpa, &.{
3829 file.mod.root.root_dir.path orelse ".",
3830 file.mod.root.sub_path,
3831 file.sub_file_path,
3832 });
3833 errdefer gpa.free(resolved_path);
3834 whole.cache_manifest_mutex.lock();
3835 defer whole.cache_manifest_mutex.unlock();
3836 man.addFilePostContents(resolved_path, source.bytes, source.stat) catch |err| switch (err) {
3837 error.OutOfMemory => |e| return e,
3838 else => {
3839 try pt.reportRetryableFileError(file_index, "unable to update cache: {s}", .{@errorName(err)});
3840 continue;
3841 },
3842 };
3843 }
3844 },
3845 .incremental => {},
3846 }
3847
3848 try reportMultiModuleErrors(pt);
3849
3850 const any_fatal_files = for (zcu.import_table.values()) |file_index| {
3851 const file = zcu.fileByIndex(file_index);
3852 switch (file.status) {
3853 .never_loaded => unreachable, // everything is loaded by the workers
3854 .retryable_failure, .astgen_failure => break true,
3855 .success => {},
3856 }
3857 } else false;
3858
3859 if (any_fatal_files or comp.alloc_failure_occurred) {
3860 // We give up right now! No updating of ZIR refs, no nothing. The idea is that this prevents
3861 // us from invalidating lots of incremental dependencies due to files with e.g. parse errors.
3862 // However, this means our analysis data is invalid, so we want to omit all analysis errors.
3863 // To do that, let's just clear the analysis roots!
3864
3865 assert(zcu.failed_files.count() > 0); // we will get an error
3866 zcu.analysis_roots.clear(); // no analysis happened
3867 return;
3868 }
3869
3835 if (comp.incremental) {3870 if (comp.incremental) {
3836 const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);3871 const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);
3837 defer update_zir_refs_node.end();3872 defer update_zir_refs_node.end();
3838 try pt.updateZirRefs();3873 try pt.updateZirRefs();
3839 }3874 }
3840 try reportMultiModuleErrors(pt);
3841 try zcu.flushRetryableFailures();3875 try zcu.flushRetryableFailures();
38423876
3843 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);3877 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
...@@ -4280,7 +4314,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -4280,7 +4314,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
4280 };4314 };
4281}4315}
42824316
4283fn workerAstGenFile(4317fn workerUpdateFile(
4284 tid: usize,4318 tid: usize,
4285 comp: *Compilation,4319 comp: *Compilation,
4286 file: *Zcu.File,4320 file: *Zcu.File,
...@@ -4290,40 +4324,44 @@ fn workerAstGenFile(...@@ -4290,40 +4324,44 @@ fn workerAstGenFile(
4290 wg: *WaitGroup,4324 wg: *WaitGroup,
4291 src: Zcu.AstGenSrc,4325 src: Zcu.AstGenSrc,
4292) void {4326) void {
4293 assert(file.getMode() == .zig);
4294 const child_prog_node = prog_node.start(file.sub_file_path, 0);4327 const child_prog_node = prog_node.start(file.sub_file_path, 0);
4295 defer child_prog_node.end();4328 defer child_prog_node.end();
42964329
4297 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));4330 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
4298 defer pt.deactivate();4331 defer pt.deactivate();
4299 pt.astGenFile(file, path_digest) catch |err| switch (err) {4332 pt.updateFile(file, path_digest) catch |err| switch (err) {
4300 error.AnalysisFail => return,4333 error.AnalysisFail => return,
4301 else => {4334 else => {
4302 file.status = .retryable_failure;
4303 pt.reportRetryableAstGenError(src, file_index, err) catch |oom| switch (oom) {4335 pt.reportRetryableAstGenError(src, file_index, err) catch |oom| switch (oom) {
4304 // Swallowing this error is OK because it's implied to be OOM when4336 error.OutOfMemory => {
4305 // there is a missing `failed_files` error message.4337 comp.mutex.lock();
4306 error.OutOfMemory => {},4338 defer comp.mutex.unlock();
4339 comp.setAllocFailure();
4340 },
4307 };4341 };
4308 return;4342 return;
4309 },4343 },
4310 };4344 };
43114345
4346 switch (file.getMode()) {
4347 .zig => {}, // continue to logic below
4348 .zon => return, // ZON can't import anything so we're done
4349 }
4350
4312 // Pre-emptively look for `@import` paths and queue them up.4351 // Pre-emptively look for `@import` paths and queue them up.
4313 // If we experience an error preemptively fetching the4352 // If we experience an error preemptively fetching the
4314 // file, just ignore it and let it happen again later during Sema.4353 // file, just ignore it and let it happen again later during Sema.
4315 assert(file.zir_loaded);4354 const imports_index = file.zir.?.extra[@intFromEnum(Zir.ExtraIndex.imports)];
4316 const imports_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.imports)];
4317 if (imports_index != 0) {4355 if (imports_index != 0) {
4318 const extra = file.zir.extraData(Zir.Inst.Imports, imports_index);4356 const extra = file.zir.?.extraData(Zir.Inst.Imports, imports_index);
4319 var import_i: u32 = 0;4357 var import_i: u32 = 0;
4320 var extra_index = extra.end;4358 var extra_index = extra.end;
43214359
4322 while (import_i < extra.data.imports_len) : (import_i += 1) {4360 while (import_i < extra.data.imports_len) : (import_i += 1) {
4323 const item = file.zir.extraData(Zir.Inst.Imports.Item, extra_index);4361 const item = file.zir.?.extraData(Zir.Inst.Imports.Item, extra_index);
4324 extra_index = item.end;4362 extra_index = item.end;
43254363
4326 const import_path = file.zir.nullTerminatedString(item.data.name);4364 const import_path = file.zir.?.nullTerminatedString(item.data.name);
4327 // `@import("builtin")` is handled specially.4365 // `@import("builtin")` is handled specially.
4328 if (mem.eql(u8, import_path, "builtin")) continue;4366 if (mem.eql(u8, import_path, "builtin")) continue;
43294367
...@@ -4344,7 +4382,7 @@ fn workerAstGenFile(...@@ -4344,7 +4382,7 @@ fn workerAstGenFile(
4344 const imported_path_digest = pt.zcu.filePathDigest(res.file_index);4382 const imported_path_digest = pt.zcu.filePathDigest(res.file_index);
4345 break :blk .{ res, imported_path_digest };4383 break :blk .{ res, imported_path_digest };
4346 };4384 };
4347 if (import_result.is_new and import_result.file.getMode() == .zig) {4385 if (import_result.is_new) {
4348 log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{4386 log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
4349 file.sub_file_path, import_path, import_result.file.sub_file_path,4387 file.sub_file_path, import_path, import_result.file.sub_file_path,
4350 });4388 });
...@@ -4352,7 +4390,7 @@ fn workerAstGenFile(...@@ -4352,7 +4390,7 @@ fn workerAstGenFile(
4352 .importing_file = file_index,4390 .importing_file = file_index,
4353 .import_tok = item.data.token,4391 .import_tok = item.data.token,
4354 } };4392 } };
4355 comp.thread_pool.spawnWgId(wg, workerAstGenFile, .{4393 comp.thread_pool.spawnWgId(wg, workerUpdateFile, .{
4356 comp, import_result.file, import_result.file_index, imported_path_digest, prog_node, wg, sub_src,4394 comp, import_result.file, import_result.file_index, imported_path_digest, prog_node, wg, sub_src,
4357 });4395 });
4358 }4396 }
...@@ -4375,7 +4413,7 @@ fn workerUpdateBuiltinZigFile(...@@ -4375,7 +4413,7 @@ fn workerUpdateBuiltinZigFile(
4375 };4413 };
4376}4414}
43774415
4378fn workerCheckEmbedFile(tid: usize, comp: *Compilation, ef_index: Zcu.EmbedFile.Index, ef: *Zcu.EmbedFile) void {4416fn workerUpdateEmbedFile(tid: usize, comp: *Compilation, ef_index: Zcu.EmbedFile.Index, ef: *Zcu.EmbedFile) void {
4379 comp.detectEmbedFileUpdate(@enumFromInt(tid), ef_index, ef) catch |err| switch (err) {4417 comp.detectEmbedFileUpdate(@enumFromInt(tid), ef_index, ef) catch |err| switch (err) {
4380 error.OutOfMemory => {4418 error.OutOfMemory => {
4381 comp.mutex.lock();4419 comp.mutex.lock();
src/InternPool.zig+8-12
...@@ -17,13 +17,6 @@ tid_shift_31: if (single_threaded) u0 else std.math.Log2Int(u32),...@@ -17,13 +17,6 @@ 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),
27/// Dependencies on the source code hash associated with a ZIR instruction.20/// Dependencies on the source code hash associated with a ZIR instruction.
28/// * For a `declaration`, this is the entire declaration body.21/// * For a `declaration`, this is the entire declaration body.
29/// * For a `struct_decl`, `union_decl`, etc, this is the source of the fields (but not declarations).22/// * For a `struct_decl`, `union_decl`, etc, this is the source of the fields (but not declarations).
...@@ -42,6 +35,9 @@ nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),...@@ -42,6 +35,9 @@ nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),
42/// * a container type requiring resolution (invalidated when the type must be recreated at a new index)35/// * a container type requiring resolution (invalidated when the type must be recreated at a new index)
43/// Value is index into `dep_entries` of the first dependency on this interned value.36/// Value is index into `dep_entries` of the first dependency on this interned value.
44interned_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),37interned_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),
38/// Dependencies on a ZON file. Triggered by `@import` of ZON.
39/// Value is index into `dep_entries` of the first dependency on this ZON file.
40zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index),
45/// Dependencies on an embedded file.41/// Dependencies on an embedded file.
46/// Introduced by `@embedFile`; invalidated when the file changes.42/// Introduced by `@embedFile`; invalidated when the file changes.
47/// Value is index into `dep_entries` of the first dependency on this `Zcu.EmbedFile`.43/// Value is index into `dep_entries` of the first dependency on this `Zcu.EmbedFile`.
...@@ -89,11 +85,11 @@ pub const empty: InternPool = .{...@@ -89,11 +85,11 @@ pub const empty: InternPool = .{
89 .tid_shift_30 = if (single_threaded) 0 else 31,85 .tid_shift_30 = if (single_threaded) 0 else 31,
90 .tid_shift_31 = if (single_threaded) 0 else 31,86 .tid_shift_31 = if (single_threaded) 0 else 31,
91 .tid_shift_32 = if (single_threaded) 0 else 31,87 .tid_shift_32 = if (single_threaded) 0 else 31,
92 .file_deps = .empty,
93 .src_hash_deps = .empty,88 .src_hash_deps = .empty,
94 .nav_val_deps = .empty,89 .nav_val_deps = .empty,
95 .nav_ty_deps = .empty,90 .nav_ty_deps = .empty,
96 .interned_deps = .empty,91 .interned_deps = .empty,
92 .zon_file_deps = .empty,
97 .embed_file_deps = .empty,93 .embed_file_deps = .empty,
98 .namespace_deps = .empty,94 .namespace_deps = .empty,
99 .namespace_name_deps = .empty,95 .namespace_name_deps = .empty,
...@@ -824,11 +820,11 @@ pub const Nav = struct {...@@ -824,11 +820,11 @@ pub const Nav = struct {
824};820};
825821
826pub const Dependee = union(enum) {822pub const Dependee = union(enum) {
827 file: FileIndex,
828 src_hash: TrackedInst.Index,823 src_hash: TrackedInst.Index,
829 nav_val: Nav.Index,824 nav_val: Nav.Index,
830 nav_ty: Nav.Index,825 nav_ty: Nav.Index,
831 interned: Index,826 interned: Index,
827 zon_file: FileIndex,
832 embed_file: Zcu.EmbedFile.Index,828 embed_file: Zcu.EmbedFile.Index,
833 namespace: TrackedInst.Index,829 namespace: TrackedInst.Index,
834 namespace_name: NamespaceNameKey,830 namespace_name: NamespaceNameKey,
...@@ -876,11 +872,11 @@ pub const DependencyIterator = struct {...@@ -876,11 +872,11 @@ pub const DependencyIterator = struct {
876872
877pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyIterator {873pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyIterator {
878 const first_entry = switch (dependee) {874 const first_entry = switch (dependee) {
879 .file => |x| ip.file_deps.get(x),
880 .src_hash => |x| ip.src_hash_deps.get(x),875 .src_hash => |x| ip.src_hash_deps.get(x),
881 .nav_val => |x| ip.nav_val_deps.get(x),876 .nav_val => |x| ip.nav_val_deps.get(x),
882 .nav_ty => |x| ip.nav_ty_deps.get(x),877 .nav_ty => |x| ip.nav_ty_deps.get(x),
883 .interned => |x| ip.interned_deps.get(x),878 .interned => |x| ip.interned_deps.get(x),
879 .zon_file => |x| ip.zon_file_deps.get(x),
884 .embed_file => |x| ip.embed_file_deps.get(x),880 .embed_file => |x| ip.embed_file_deps.get(x),
885 .namespace => |x| ip.namespace_deps.get(x),881 .namespace => |x| ip.namespace_deps.get(x),
886 .namespace_name => |x| ip.namespace_name_deps.get(x),882 .namespace_name => |x| ip.namespace_name_deps.get(x),
...@@ -947,11 +943,11 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend...@@ -947,11 +943,11 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
947 },943 },
948 inline else => |dependee_payload, tag| new_index: {944 inline else => |dependee_payload, tag| new_index: {
949 const gop = try switch (tag) {945 const gop = try switch (tag) {
950 .file => ip.file_deps,
951 .src_hash => ip.src_hash_deps,946 .src_hash => ip.src_hash_deps,
952 .nav_val => ip.nav_val_deps,947 .nav_val => ip.nav_val_deps,
953 .nav_ty => ip.nav_ty_deps,948 .nav_ty => ip.nav_ty_deps,
954 .interned => ip.interned_deps,949 .interned => ip.interned_deps,
950 .zon_file => ip.zon_file_deps,
955 .embed_file => ip.embed_file_deps,951 .embed_file => ip.embed_file_deps,
956 .namespace => ip.namespace_deps,952 .namespace => ip.namespace_deps,
957 .namespace_name => ip.namespace_name_deps,953 .namespace_name => ip.namespace_name_deps,
...@@ -6688,11 +6684,11 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {...@@ -6688,11 +6684,11 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
6688pub fn deinit(ip: *InternPool, gpa: Allocator) void {6684pub fn deinit(ip: *InternPool, gpa: Allocator) void {
6689 if (debug_state.enable_checks) std.debug.assert(debug_state.intern_pool == null);6685 if (debug_state.enable_checks) std.debug.assert(debug_state.intern_pool == null);
66906686
6691 ip.file_deps.deinit(gpa);
6692 ip.src_hash_deps.deinit(gpa);6687 ip.src_hash_deps.deinit(gpa);
6693 ip.nav_val_deps.deinit(gpa);6688 ip.nav_val_deps.deinit(gpa);
6694 ip.nav_ty_deps.deinit(gpa);6689 ip.nav_ty_deps.deinit(gpa);
6695 ip.interned_deps.deinit(gpa);6690 ip.interned_deps.deinit(gpa);
6691 ip.zon_file_deps.deinit(gpa);
6696 ip.embed_file_deps.deinit(gpa);6692 ip.embed_file_deps.deinit(gpa);
6697 ip.namespace_deps.deinit(gpa);6693 ip.namespace_deps.deinit(gpa);
6698 ip.namespace_name_deps.deinit(gpa);6694 ip.namespace_name_deps.deinit(gpa);
src/Package/Module.zig+4-7
...@@ -482,15 +482,12 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {...@@ -482,15 +482,12 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
482 };482 };
483 new_file.* = .{483 new_file.* = .{
484 .sub_file_path = "builtin.zig",484 .sub_file_path = "builtin.zig",
485 .source = generated_builtin_source,
486 .source_loaded = true,
487 .tree_loaded = false,
488 .zir_loaded = false,
489 .stat = undefined,485 .stat = undefined,
490 .tree = undefined,486 .source = generated_builtin_source,
491 .zir = undefined,487 .tree = null,
488 .zir = null,
489 .zoir = null,
492 .status = .never_loaded,490 .status = .never_loaded,
493 .prev_status = .never_loaded,
494 .mod = new,491 .mod = new,
495 };492 };
496 break :b new;493 break :b new;
src/Sema.zig+8-16
...@@ -6140,10 +6140,9 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -6140,10 +6140,9 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
6140 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});6140 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
61416141
6142 const path_digest = zcu.filePathDigest(result.file_index);6142 const path_digest = zcu.filePathDigest(result.file_index);
6143 pt.astGenFile(result.file, path_digest) catch |err|6143 pt.updateFile(result.file, path_digest) catch |err|
6144 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});6144 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
61456145
6146 try sema.declareDependency(.{ .file = result.file_index });
6147 try pt.ensureFileAnalyzed(result.file_index);6146 try pt.ensureFileAnalyzed(result.file_index);
6148 const ty = zcu.fileRootType(result.file_index);6147 const ty = zcu.fileRootType(result.file_index);
6149 try sema.declareDependency(.{ .interned = ty });6148 try sema.declareDependency(.{ .interned = ty });
...@@ -7649,9 +7648,8 @@ fn analyzeCall(...@@ -7649,9 +7648,8 @@ fn analyzeCall(
7649 const nav = ip.getNav(info.owner_nav);7648 const nav = ip.getNav(info.owner_nav);
7650 const resolved_func_inst = info.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail;7649 const resolved_func_inst = info.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail;
7651 const file = zcu.fileByIndex(resolved_func_inst.file);7650 const file = zcu.fileByIndex(resolved_func_inst.file);
7652 assert(file.zir_loaded);7651 const zir_info = file.zir.?.getFnInfo(resolved_func_inst.inst);
7653 const zir_info = file.zir.getFnInfo(resolved_func_inst.inst);7652 break :b .{ nav, file.zir.?, info.zir_body_inst, resolved_func_inst.inst, zir_info };
7654 break :b .{ nav, file.zir, info.zir_body_inst, resolved_func_inst.inst, zir_info };
7655 } else .{ undefined, undefined, undefined, undefined, undefined };7653 } else .{ undefined, undefined, undefined, undefined, undefined };
76567654
7657 // This is the `inst_map` used when evaluating generic parameters and return types.7655 // This is the `inst_map` used when evaluating generic parameters and return types.
...@@ -13987,7 +13985,6 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -13987,7 +13985,6 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
13987 };13985 };
13988 switch (result.file.getMode()) {13986 switch (result.file.getMode()) {
13989 .zig => {13987 .zig => {
13990 try sema.declareDependency(.{ .file = result.file_index });
13991 try pt.ensureFileAnalyzed(result.file_index);13988 try pt.ensureFileAnalyzed(result.file_index);
13992 const ty = zcu.fileRootType(result.file_index);13989 const ty = zcu.fileRootType(result.file_index);
13993 try sema.declareDependency(.{ .interned = ty });13990 try sema.declareDependency(.{ .interned = ty });
...@@ -13995,12 +13992,6 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -13995,12 +13992,6 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
13995 return Air.internedToRef(ty);13992 return Air.internedToRef(ty);
13996 },13993 },
13997 .zon => {13994 .zon => {
13998 _ = result.file.getTree(zcu.gpa) catch |err| {
13999 // TODO: these errors are file system errors; make sure an update() will
14000 // retry this and not cache the file system error, which may be transient.
14001 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ result.file.sub_file_path, @errorName(err) });
14002 };
14003
14004 if (extra.res_ty == .none) {13995 if (extra.res_ty == .none) {
14005 return sema.fail(block, operand_src, "'@import' of ZON must have a known result type", .{});13996 return sema.fail(block, operand_src, "'@import' of ZON must have a known result type", .{});
14006 }13997 }
...@@ -14010,6 +14001,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -14010,6 +14001,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
14010 return sema.fail(block, operand_src, "'@import' of ZON must have a known result type", .{});14001 return sema.fail(block, operand_src, "'@import' of ZON must have a known result type", .{});
14011 }14002 }
1401214003
14004 try sema.declareDependency(.{ .zon_file = result.file_index });
14013 const interned = try LowerZon.run(14005 const interned = try LowerZon.run(
14014 sema,14006 sema,
14015 result.file,14007 result.file,
...@@ -35328,7 +35320,7 @@ fn backingIntType(...@@ -35328,7 +35320,7 @@ fn backingIntType(
35328 break :blk accumulator;35320 break :blk accumulator;
35329 };35321 };
3533035322
35331 const zir = zcu.namespacePtr(struct_type.namespace).fileScope(zcu).zir;35323 const zir = zcu.namespacePtr(struct_type.namespace).fileScope(zcu).zir.?;
35332 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;35324 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
35333 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;35325 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
35334 assert(extended.opcode == .struct_decl);35326 assert(extended.opcode == .struct_decl);
...@@ -35948,7 +35940,7 @@ fn structFields(...@@ -35948,7 +35940,7 @@ fn structFields(
35948 const gpa = zcu.gpa;35940 const gpa = zcu.gpa;
35949 const ip = &zcu.intern_pool;35941 const ip = &zcu.intern_pool;
35950 const namespace_index = struct_type.namespace;35942 const namespace_index = struct_type.namespace;
35951 const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir;35943 const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir.?;
35952 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;35944 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
3595335945
35954 const fields_len, _, var extra_index = structZirInfo(zir, zir_index);35946 const fields_len, _, var extra_index = structZirInfo(zir, zir_index);
...@@ -36149,7 +36141,7 @@ fn structFieldInits(...@@ -36149,7 +36141,7 @@ fn structFieldInits(
36149 assert(!struct_type.haveFieldInits(ip));36141 assert(!struct_type.haveFieldInits(ip));
3615036142
36151 const namespace_index = struct_type.namespace;36143 const namespace_index = struct_type.namespace;
36152 const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir;36144 const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir.?;
36153 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;36145 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
36154 const fields_len, _, var extra_index = structZirInfo(zir, zir_index);36146 const fields_len, _, var extra_index = structZirInfo(zir, zir_index);
3615536147
...@@ -36268,7 +36260,7 @@ fn unionFields(...@@ -36268,7 +36260,7 @@ fn unionFields(
36268 const zcu = pt.zcu;36260 const zcu = pt.zcu;
36269 const gpa = zcu.gpa;36261 const gpa = zcu.gpa;
36270 const ip = &zcu.intern_pool;36262 const ip = &zcu.intern_pool;
36271 const zir = zcu.namespacePtr(union_type.namespace).fileScope(zcu).zir;36263 const zir = zcu.namespacePtr(union_type.namespace).fileScope(zcu).zir.?;
36272 const zir_index = union_type.zir_index.resolve(ip) orelse return error.AnalysisFail;36264 const zir_index = union_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
36273 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;36265 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
36274 assert(extended.opcode == .union_decl);36266 assert(extended.opcode == .union_decl);
src/Sema/LowerZon.zig-2
...@@ -39,8 +39,6 @@ pub fn run(...@@ -39,8 +39,6 @@ pub fn run(
39) CompileError!InternPool.Index {39) CompileError!InternPool.Index {
40 const pt = sema.pt;40 const pt = sema.pt;
4141
42 _ = try file.getZoir(pt.zcu);
43
44 const tracked_inst = try pt.zcu.intern_pool.trackZir(pt.zcu.gpa, pt.tid, .{42 const tracked_inst = try pt.zcu.intern_pool.trackZir(pt.zcu.gpa, pt.tid, .{
45 .file = file_index,43 .file = file_index,
46 .inst = .main_struct_inst, // this is the only trackable instruction in a ZON file44 .inst = .main_struct_inst, // this is the only trackable instruction in a ZON file
src/Type.zig+3-4
...@@ -3587,8 +3587,7 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {...@@ -3587,8 +3587,7 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
3587 };3587 };
3588 const info = tracked.resolveFull(&zcu.intern_pool) orelse return null;3588 const info = tracked.resolveFull(&zcu.intern_pool) orelse return null;
3589 const file = zcu.fileByIndex(info.file);3589 const file = zcu.fileByIndex(info.file);
3590 assert(file.zir_loaded);3590 const zir = file.zir.?;
3591 const zir = file.zir;
3592 const inst = zir.instructions.get(@intFromEnum(info.inst));3591 const inst = zir.instructions.get(@intFromEnum(info.inst));
3593 return switch (inst.tag) {3592 return switch (inst.tag) {
3594 .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_line,3593 .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_line,
...@@ -3905,7 +3904,7 @@ fn resolveStructInner(...@@ -3905,7 +3904,7 @@ fn resolveStructInner(
3905 var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa);3904 var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa);
3906 defer comptime_err_ret_trace.deinit();3905 defer comptime_err_ret_trace.deinit();
39073906
3908 const zir = zcu.namespacePtr(struct_obj.namespace).fileScope(zcu).zir;3907 const zir = zcu.namespacePtr(struct_obj.namespace).fileScope(zcu).zir.?;
3909 var sema: Sema = .{3908 var sema: Sema = .{
3910 .pt = pt,3909 .pt = pt,
3911 .gpa = gpa,3910 .gpa = gpa,
...@@ -3959,7 +3958,7 @@ fn resolveUnionInner(...@@ -3959,7 +3958,7 @@ fn resolveUnionInner(
3959 var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa);3958 var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa);
3960 defer comptime_err_ret_trace.deinit();3959 defer comptime_err_ret_trace.deinit();
39613960
3962 const zir = zcu.namespacePtr(union_obj.namespace).fileScope(zcu).zir;3961 const zir = zcu.namespacePtr(union_obj.namespace).fileScope(zcu).zir.?;
3963 var sema: Sema = .{3962 var sema: Sema = .{
3964 .pt = pt,3963 .pt = pt,
3965 .gpa = gpa,3964 .gpa = gpa,
src/Zcu.zig+262-90
...@@ -658,24 +658,35 @@ pub const Namespace = struct {...@@ -658,24 +658,35 @@ pub const Namespace = struct {
658};658};
659659
660pub const File = struct {660pub const File = struct {
661 status: Status,
662 prev_status: Status,
663 source_loaded: bool,
664 tree_loaded: bool,
665 zir_loaded: bool,
666 /// Relative to the owning package's root source directory.661 /// Relative to the owning package's root source directory.
667 /// Memory is stored in gpa, owned by File.662 /// Memory is stored in gpa, owned by File.
668 sub_file_path: []const u8,663 sub_file_path: []const u8,
669 /// Whether this is populated depends on `source_loaded`.664
670 source: [:0]const u8,665 status: enum {
666 /// We have not yet attempted to load this file.
667 /// `stat` is not populated and may be `undefined`.
668 never_loaded,
669 /// A filesystem access failed. It should be retried on the next update.
670 /// There is a `failed_files` entry containing a non-`null` message.
671 /// `stat` is not populated and may be `undefined`.
672 retryable_failure,
673 /// Parsing/AstGen/ZonGen of this file has failed.
674 /// There is an error in `zir` or `zoir`.
675 /// There is a `failed_files` entry (with a `null` message).
676 /// `stat` is populated.
677 astgen_failure,
678 /// Parsing and AstGen/ZonGen of this file has succeeded.
679 /// `stat` is populated.
680 success,
681 },
671 /// Whether this is populated depends on `status`.682 /// Whether this is populated depends on `status`.
672 stat: Cache.File.Stat,683 stat: Cache.File.Stat,
673 /// Whether this is populated or not depends on `tree_loaded`.684
674 tree: Ast,685 source: ?[:0]const u8,
675 /// Whether this is populated or not depends on `zir_loaded`.686 tree: ?Ast,
676 zir: Zir,687 zir: ?Zir,
677 /// Cached Zoir, generated lazily.688 zoir: ?Zoir,
678 zoir: ?Zoir = null,689
679 /// Module that this file is a part of, managed externally.690 /// Module that this file is a part of, managed externally.
680 mod: *Package.Module,691 mod: *Package.Module,
681 /// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen.692 /// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen.
...@@ -683,19 +694,24 @@ pub const File = struct {...@@ -683,19 +694,24 @@ pub const File = struct {
683 /// List of references to this file, used for multi-package errors.694 /// List of references to this file, used for multi-package errors.
684 references: std.ArrayListUnmanaged(File.Reference) = .empty,695 references: std.ArrayListUnmanaged(File.Reference) = .empty,
685696
686 /// The most recent successful ZIR for this file, with no errors.697 /// The ZIR for this file from the last update with no file failures. As such, this ZIR is never
687 /// This is only populated when a previously successful ZIR698 /// failed (although it may have compile errors).
688 /// newly introduces compile errors during an update. When ZIR is699 ///
689 /// successful, this field is unloaded.700 /// Because updates with file failures do not perform ZIR mapping or semantic analysis, we keep
701 /// this around so we have the "old" ZIR to map when an update is ready to do so. Once such an
702 /// update occurs, this field is unloaded, since it is no longer necessary.
703 ///
704 /// In other words, if `TrackedInst`s are tied to ZIR other than what's in the `zir` field, this
705 /// field is populated with that old ZIR.
690 prev_zir: ?*Zir = null,706 prev_zir: ?*Zir = null,
691707
692 pub const Status = enum {708 /// This field serves a similar purpose to `prev_zir`, but for ZOIR. However, since we do not
693 never_loaded,709 /// need to map old ZOIR to new ZOIR -- instead only invalidating dependencies if the ZOIR
694 retryable_failure,710 /// changed -- this field is just a simple boolean.
695 parse_failure,711 ///
696 astgen_failure,712 /// When `zoir` is updated, this field is set to `true`. In `updateZirRefs`, if this is `true`,
697 success_zir,713 /// we invalidate the corresponding `zon_file` dependency, and reset it to `false`.
698 };714 zoir_invalidated: bool = false,
699715
700 /// A single reference to a file.716 /// A single reference to a file.
701 pub const Reference = union(enum) {717 pub const Reference = union(enum) {
...@@ -727,23 +743,23 @@ pub const File = struct {...@@ -727,23 +743,23 @@ pub const File = struct {
727 }743 }
728744
729 pub fn unloadTree(file: *File, gpa: Allocator) void {745 pub fn unloadTree(file: *File, gpa: Allocator) void {
730 if (file.tree_loaded) {746 if (file.tree) |*tree| {
731 file.tree_loaded = false;747 tree.deinit(gpa);
732 file.tree.deinit(gpa);748 file.tree = null;
733 }749 }
734 }750 }
735751
736 pub fn unloadSource(file: *File, gpa: Allocator) void {752 pub fn unloadSource(file: *File, gpa: Allocator) void {
737 if (file.source_loaded) {753 if (file.source) |source| {
738 file.source_loaded = false;754 gpa.free(source);
739 gpa.free(file.source);755 file.source = null;
740 }756 }
741 }757 }
742758
743 pub fn unloadZir(file: *File, gpa: Allocator) void {759 pub fn unloadZir(file: *File, gpa: Allocator) void {
744 if (file.zir_loaded) {760 if (file.zir) |*zir| {
745 file.zir_loaded = false;761 zir.deinit(gpa);
746 file.zir.deinit(gpa);762 file.zir = null;
747 }763 }
748 }764 }
749765
...@@ -753,8 +769,8 @@ pub const File = struct {...@@ -753,8 +769,8 @@ pub const File = struct {
753 };769 };
754770
755 pub fn getSource(file: *File, gpa: Allocator) !Source {771 pub fn getSource(file: *File, gpa: Allocator) !Source {
756 if (file.source_loaded) return Source{772 if (file.source) |source| return .{
757 .bytes = file.source,773 .bytes = source,
758 .stat = file.stat,774 .stat = file.stat,
759 };775 };
760776
...@@ -769,18 +785,20 @@ pub const File = struct {...@@ -769,18 +785,20 @@ pub const File = struct {
769 return error.FileTooBig;785 return error.FileTooBig;
770786
771 const source = try gpa.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);787 const source = try gpa.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
772 defer if (!file.source_loaded) gpa.free(source);788 errdefer gpa.free(source);
789
773 const amt = try f.readAll(source);790 const amt = try f.readAll(source);
774 if (amt != stat.size)791 if (amt != stat.size)
775 return error.UnexpectedEndOfFile;792 return error.UnexpectedEndOfFile;
776793
777 // Here we do not modify stat fields because this function is the one794 // Here we do not modify stat fields because this function is the one
778 // used for error reporting. We need to keep the stat fields stale so that795 // used for error reporting. We need to keep the stat fields stale so that
779 // astGenFile can know to regenerate ZIR.796 // updateFile can know to regenerate ZIR.
780797
781 file.source = source;798 file.source = source;
782 file.source_loaded = true;799 errdefer comptime unreachable; // don't error after populating `source`
783 return Source{800
801 return .{
784 .bytes = source,802 .bytes = source,
785 .stat = .{803 .stat = .{
786 .size = stat.size,804 .size = stat.size,
...@@ -791,20 +809,20 @@ pub const File = struct {...@@ -791,20 +809,20 @@ pub const File = struct {
791 }809 }
792810
793 pub fn getTree(file: *File, gpa: Allocator) !*const Ast {811 pub fn getTree(file: *File, gpa: Allocator) !*const Ast {
794 if (file.tree_loaded) return &file.tree;812 if (file.tree) |*tree| return tree;
795813
796 const source = try file.getSource(gpa);814 const source = try file.getSource(gpa);
797 file.tree = try Ast.parse(gpa, source.bytes, file.getMode());815 file.tree = try .parse(gpa, source.bytes, file.getMode());
798 file.tree_loaded = true;816 return &file.tree.?;
799 return &file.tree;
800 }817 }
801818
802 pub fn getZoir(file: *File, zcu: *Zcu) !*const Zoir {819 pub fn getZoir(file: *File, zcu: *Zcu) !*const Zoir {
803 if (file.zoir) |*zoir| return zoir;820 if (file.zoir) |*zoir| return zoir;
804821
805 assert(file.tree_loaded);822 const tree = file.tree.?;
806 assert(file.tree.mode == .zon);823 assert(tree.mode == .zon);
807 file.zoir = try ZonGen.generate(zcu.gpa, file.tree, .{});824
825 file.zoir = try ZonGen.generate(zcu.gpa, tree, .{});
808 if (file.zoir.?.hasCompileErrors()) {826 if (file.zoir.?.hasCompileErrors()) {
809 try zcu.failed_files.putNoClobber(zcu.gpa, file, null);827 try zcu.failed_files.putNoClobber(zcu.gpa, file, null);
810 return error.AnalysisFail;828 return error.AnalysisFail;
...@@ -854,13 +872,6 @@ pub const File = struct {...@@ -854,13 +872,6 @@ pub const File = struct {
854 std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });872 std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
855 }873 }
856874
857 pub fn okToReportErrors(file: File) bool {
858 return switch (file.status) {
859 .parse_failure, .astgen_failure => false,
860 else => true,
861 };
862 }
863
864 /// Add a reference to this file during AstGen.875 /// Add a reference to this file during AstGen.
865 pub fn addReference(file: *File, zcu: *Zcu, ref: File.Reference) !void {876 pub fn addReference(file: *File, zcu: *Zcu, ref: File.Reference) !void {
866 // Don't add the same module root twice. Note that since we always add module roots at the877 // Don't add the same module root twice. Note that since we always add module roots at the
...@@ -900,18 +911,18 @@ pub const File = struct {...@@ -900,18 +911,18 @@ pub const File = struct {
900911
901 // We can only mark children as failed if the ZIR is loaded, which may not912 // We can only mark children as failed if the ZIR is loaded, which may not
902 // be the case if there were other astgen failures in this file913 // be the case if there were other astgen failures in this file
903 if (!file.zir_loaded) return;914 if (file.zir == null) return;
904915
905 const imports_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.imports)];916 const imports_index = file.zir.?.extra[@intFromEnum(Zir.ExtraIndex.imports)];
906 if (imports_index == 0) return;917 if (imports_index == 0) return;
907 const extra = file.zir.extraData(Zir.Inst.Imports, imports_index);918 const extra = file.zir.?.extraData(Zir.Inst.Imports, imports_index);
908919
909 var extra_index = extra.end;920 var extra_index = extra.end;
910 for (0..extra.data.imports_len) |_| {921 for (0..extra.data.imports_len) |_| {
911 const item = file.zir.extraData(Zir.Inst.Imports.Item, extra_index);922 const item = file.zir.?.extraData(Zir.Inst.Imports.Item, extra_index);
912 extra_index = item.end;923 extra_index = item.end;
913924
914 const import_path = file.zir.nullTerminatedString(item.data.name);925 const import_path = file.zir.?.nullTerminatedString(item.data.name);
915 if (mem.eql(u8, import_path, "builtin")) continue;926 if (mem.eql(u8, import_path, "builtin")) continue;
916927
917 const res = pt.importFile(file, import_path) catch continue;928 const res = pt.importFile(file, import_path) catch continue;
...@@ -1012,7 +1023,7 @@ pub const SrcLoc = struct {...@@ -1012,7 +1023,7 @@ pub const SrcLoc = struct {
1012 lazy: LazySrcLoc.Offset,1023 lazy: LazySrcLoc.Offset,
10131024
1014 pub fn baseSrcToken(src_loc: SrcLoc) Ast.TokenIndex {1025 pub fn baseSrcToken(src_loc: SrcLoc) Ast.TokenIndex {
1015 const tree = src_loc.file_scope.tree;1026 const tree = src_loc.file_scope.tree.?;
1016 return tree.firstToken(src_loc.base_node);1027 return tree.firstToken(src_loc.base_node);
1017 }1028 }
10181029
...@@ -1057,7 +1068,6 @@ pub const SrcLoc = struct {...@@ -1057,7 +1068,6 @@ pub const SrcLoc = struct {
1057 const node_off = traced_off.x;1068 const node_off = traced_off.x;
1058 const tree = try src_loc.file_scope.getTree(gpa);1069 const tree = try src_loc.file_scope.getTree(gpa);
1059 const node = src_loc.relativeToNodeIndex(node_off);1070 const node = src_loc.relativeToNodeIndex(node_off);
1060 assert(src_loc.file_scope.tree_loaded);
1061 return tree.nodeToSpan(node);1071 return tree.nodeToSpan(node);
1062 },1072 },
1063 .node_offset_main_token => |node_off| {1073 .node_offset_main_token => |node_off| {
...@@ -1069,7 +1079,6 @@ pub const SrcLoc = struct {...@@ -1069,7 +1079,6 @@ pub const SrcLoc = struct {
1069 .node_offset_bin_op => |node_off| {1079 .node_offset_bin_op => |node_off| {
1070 const tree = try src_loc.file_scope.getTree(gpa);1080 const tree = try src_loc.file_scope.getTree(gpa);
1071 const node = src_loc.relativeToNodeIndex(node_off);1081 const node = src_loc.relativeToNodeIndex(node_off);
1072 assert(src_loc.file_scope.tree_loaded);
1073 return tree.nodeToSpan(node);1082 return tree.nodeToSpan(node);
1074 },1083 },
1075 .node_offset_initializer => |node_off| {1084 .node_offset_initializer => |node_off| {
...@@ -2408,9 +2417,8 @@ pub const LazySrcLoc = struct {...@@ -2408,9 +2417,8 @@ pub const LazySrcLoc = struct {
2408 if (zir_inst == .main_struct_inst) return .{ file, 0 };2417 if (zir_inst == .main_struct_inst) return .{ file, 0 };
24092418
2410 // Otherwise, make sure ZIR is loaded.2419 // Otherwise, make sure ZIR is loaded.
2411 assert(file.zir_loaded);2420 const zir = file.zir.?;
24122421
2413 const zir = file.zir;
2414 const inst = zir.instructions.get(@intFromEnum(zir_inst));2422 const inst = zir.instructions.get(@intFromEnum(zir_inst));
2415 const base_node: Ast.Node.Index = switch (inst.tag) {2423 const base_node: Ast.Node.Index = switch (inst.tag) {
2416 .declaration => inst.data.declaration.src_node,2424 .declaration => inst.data.declaration.src_node,
...@@ -2643,6 +2651,189 @@ pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.F...@@ -2643,6 +2651,189 @@ pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.F
2643 return zir;2651 return zir;
2644}2652}
26452653
2654pub fn saveZirCache(gpa: Allocator, cache_file: std.fs.File, stat: std.fs.File.Stat, zir: Zir) (std.fs.File.WriteError || Allocator.Error)!void {
2655 const safety_buffer = if (data_has_safety_tag)
2656 try gpa.alloc([8]u8, zir.instructions.len)
2657 else
2658 undefined;
2659 defer if (data_has_safety_tag) gpa.free(safety_buffer);
2660
2661 const data_ptr: [*]const u8 = if (data_has_safety_tag)
2662 if (zir.instructions.len == 0)
2663 undefined
2664 else
2665 @ptrCast(safety_buffer.ptr)
2666 else
2667 @ptrCast(zir.instructions.items(.data).ptr);
2668
2669 if (data_has_safety_tag) {
2670 // The `Data` union has a safety tag but in the file format we store it without.
2671 for (zir.instructions.items(.data), 0..) |*data, i| {
2672 const as_struct: *const HackDataLayout = @ptrCast(data);
2673 safety_buffer[i] = as_struct.data;
2674 }
2675 }
2676
2677 const header: Zir.Header = .{
2678 .instructions_len = @intCast(zir.instructions.len),
2679 .string_bytes_len = @intCast(zir.string_bytes.len),
2680 .extra_len = @intCast(zir.extra.len),
2681
2682 .stat_size = stat.size,
2683 .stat_inode = stat.inode,
2684 .stat_mtime = stat.mtime,
2685 };
2686 var iovecs: [5]std.posix.iovec_const = .{
2687 .{
2688 .base = @ptrCast(&header),
2689 .len = @sizeOf(Zir.Header),
2690 },
2691 .{
2692 .base = @ptrCast(zir.instructions.items(.tag).ptr),
2693 .len = zir.instructions.len,
2694 },
2695 .{
2696 .base = data_ptr,
2697 .len = zir.instructions.len * 8,
2698 },
2699 .{
2700 .base = zir.string_bytes.ptr,
2701 .len = zir.string_bytes.len,
2702 },
2703 .{
2704 .base = @ptrCast(zir.extra.ptr),
2705 .len = zir.extra.len * 4,
2706 },
2707 };
2708 try cache_file.writevAll(&iovecs);
2709}
2710
2711pub fn saveZoirCache(cache_file: std.fs.File, stat: std.fs.File.Stat, zoir: Zoir) std.fs.File.WriteError!void {
2712 const header: Zoir.Header = .{
2713 .nodes_len = @intCast(zoir.nodes.len),
2714 .extra_len = @intCast(zoir.extra.len),
2715 .limbs_len = @intCast(zoir.limbs.len),
2716 .string_bytes_len = @intCast(zoir.string_bytes.len),
2717 .compile_errors_len = @intCast(zoir.compile_errors.len),
2718 .error_notes_len = @intCast(zoir.error_notes.len),
2719
2720 .stat_size = stat.size,
2721 .stat_inode = stat.inode,
2722 .stat_mtime = stat.mtime,
2723 };
2724 var iovecs: [9]std.posix.iovec_const = .{
2725 .{
2726 .base = @ptrCast(&header),
2727 .len = @sizeOf(Zoir.Header),
2728 },
2729 .{
2730 .base = @ptrCast(zoir.nodes.items(.tag)),
2731 .len = zoir.nodes.len * @sizeOf(Zoir.Node.Repr.Tag),
2732 },
2733 .{
2734 .base = @ptrCast(zoir.nodes.items(.data)),
2735 .len = zoir.nodes.len * 4,
2736 },
2737 .{
2738 .base = @ptrCast(zoir.nodes.items(.ast_node)),
2739 .len = zoir.nodes.len * 4,
2740 },
2741 .{
2742 .base = @ptrCast(zoir.extra),
2743 .len = zoir.extra.len * 4,
2744 },
2745 .{
2746 .base = @ptrCast(zoir.limbs),
2747 .len = zoir.limbs.len * 4,
2748 },
2749 .{
2750 .base = zoir.string_bytes.ptr,
2751 .len = zoir.string_bytes.len,
2752 },
2753 .{
2754 .base = @ptrCast(zoir.compile_errors),
2755 .len = zoir.compile_errors.len * @sizeOf(Zoir.CompileError),
2756 },
2757 .{
2758 .base = @ptrCast(zoir.error_notes),
2759 .len = zoir.error_notes.len * @sizeOf(Zoir.CompileError.Note),
2760 },
2761 };
2762 try cache_file.writevAll(&iovecs);
2763}
2764
2765pub fn loadZoirCacheBody(gpa: Allocator, header: Zoir.Header, cache_file: std.fs.File) !Zoir {
2766 var zoir: Zoir = .{
2767 .nodes = .empty,
2768 .extra = &.{},
2769 .limbs = &.{},
2770 .string_bytes = &.{},
2771 .compile_errors = &.{},
2772 .error_notes = &.{},
2773 };
2774 errdefer zoir.deinit(gpa);
2775
2776 zoir.nodes = nodes: {
2777 var nodes: std.MultiArrayList(Zoir.Node.Repr) = .empty;
2778 defer nodes.deinit(gpa);
2779 try nodes.setCapacity(gpa, header.nodes_len);
2780 nodes.len = header.nodes_len;
2781 break :nodes nodes.toOwnedSlice();
2782 };
2783
2784 zoir.extra = try gpa.alloc(u32, header.extra_len);
2785 zoir.limbs = try gpa.alloc(std.math.big.Limb, header.limbs_len);
2786 zoir.string_bytes = try gpa.alloc(u8, header.string_bytes_len);
2787
2788 zoir.compile_errors = try gpa.alloc(Zoir.CompileError, header.compile_errors_len);
2789 zoir.error_notes = try gpa.alloc(Zoir.CompileError.Note, header.error_notes_len);
2790
2791 var iovecs: [8]std.posix.iovec = .{
2792 .{
2793 .base = @ptrCast(zoir.nodes.items(.tag)),
2794 .len = header.nodes_len * @sizeOf(Zoir.Node.Repr.Tag),
2795 },
2796 .{
2797 .base = @ptrCast(zoir.nodes.items(.data)),
2798 .len = header.nodes_len * 4,
2799 },
2800 .{
2801 .base = @ptrCast(zoir.nodes.items(.ast_node)),
2802 .len = header.nodes_len * 4,
2803 },
2804 .{
2805 .base = @ptrCast(zoir.extra),
2806 .len = header.extra_len * 4,
2807 },
2808 .{
2809 .base = @ptrCast(zoir.limbs),
2810 .len = header.limbs_len * @sizeOf(std.math.big.Limb),
2811 },
2812 .{
2813 .base = zoir.string_bytes.ptr,
2814 .len = header.string_bytes_len,
2815 },
2816 .{
2817 .base = @ptrCast(zoir.compile_errors),
2818 .len = header.compile_errors_len * @sizeOf(Zoir.CompileError),
2819 },
2820 .{
2821 .base = @ptrCast(zoir.error_notes),
2822 .len = header.error_notes_len * @sizeOf(Zoir.CompileError.Note),
2823 },
2824 };
2825
2826 const bytes_expected = expected: {
2827 var n: usize = 0;
2828 for (iovecs) |v| n += v.len;
2829 break :expected n;
2830 };
2831
2832 const bytes_read = try cache_file.readvAll(&iovecs);
2833 if (bytes_read != bytes_expected) return error.UnexpectedFileSize;
2834 return zoir;
2835}
2836
2646pub fn markDependeeOutdated(2837pub fn markDependeeOutdated(
2647 zcu: *Zcu,2838 zcu: *Zcu,
2648 /// When we are diffing ZIR and marking things as outdated, we won't yet have marked the dependencies as PO.2839 /// When we are diffing ZIR and marking things as outdated, we won't yet have marked the dependencies as PO.
...@@ -3303,19 +3494,6 @@ pub fn optimizeMode(zcu: *const Zcu) std.builtin.OptimizeMode {...@@ -3303,19 +3494,6 @@ pub fn optimizeMode(zcu: *const Zcu) std.builtin.OptimizeMode {
3303 return zcu.root_mod.optimize_mode;3494 return zcu.root_mod.optimize_mode;
3304}3495}
33053496
3306fn lockAndClearFileCompileError(zcu: *Zcu, file: *File) void {
3307 switch (file.status) {
3308 .success_zir, .retryable_failure => {},
3309 .never_loaded, .parse_failure, .astgen_failure => {
3310 zcu.comp.mutex.lock();
3311 defer zcu.comp.mutex.unlock();
3312 if (zcu.failed_files.fetchSwapRemove(file)) |kv| {
3313 if (kv.value) |msg| msg.destroy(zcu.gpa); // Delete previous error message.
3314 }
3315 },
3316 }
3317}
3318
3319pub fn handleUpdateExports(3497pub fn handleUpdateExports(
3320 zcu: *Zcu,3498 zcu: *Zcu,
3321 export_indices: []const Export.Index,3499 export_indices: []const Export.Index,
...@@ -3670,9 +3848,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv...@@ -3670,9 +3848,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
3670 // `test` declarations are analyzed depending on the test filter.3848 // `test` declarations are analyzed depending on the test filter.
3671 const inst_info = nav.analysis.?.zir_index.resolveFull(ip) orelse continue;3849 const inst_info = nav.analysis.?.zir_index.resolveFull(ip) orelse continue;
3672 const file = zcu.fileByIndex(inst_info.file);3850 const file = zcu.fileByIndex(inst_info.file);
3673 // If the file failed AstGen, the TrackedInst refers to the old ZIR.3851 const decl = file.zir.?.getDeclaration(inst_info.inst);
3674 const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*;
3675 const decl = zir.getDeclaration(inst_info.inst);
36763852
3677 if (!comp.config.is_test or file.mod != zcu.main_mod) continue;3853 if (!comp.config.is_test or file.mod != zcu.main_mod) continue;
36783854
...@@ -3702,9 +3878,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv...@@ -3702,9 +3878,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
3702 // These are named declarations. They are analyzed only if marked `export`.3878 // These are named declarations. They are analyzed only if marked `export`.
3703 const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;3879 const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;
3704 const file = zcu.fileByIndex(inst_info.file);3880 const file = zcu.fileByIndex(inst_info.file);
3705 // If the file failed AstGen, the TrackedInst refers to the old ZIR.3881 const decl = file.zir.?.getDeclaration(inst_info.inst);
3706 const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*;
3707 const decl = zir.getDeclaration(inst_info.inst);
3708 if (decl.linkage == .@"export") {3882 if (decl.linkage == .@"export") {
3709 const unit: AnalUnit = .wrap(.{ .nav_val = nav });3883 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
3710 if (!result.contains(unit)) {3884 if (!result.contains(unit)) {
...@@ -3720,9 +3894,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv...@@ -3720,9 +3894,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
3720 // These are named declarations. They are analyzed only if marked `export`.3894 // These are named declarations. They are analyzed only if marked `export`.
3721 const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;3895 const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;
3722 const file = zcu.fileByIndex(inst_info.file);3896 const file = zcu.fileByIndex(inst_info.file);
3723 // If the file failed AstGen, the TrackedInst refers to the old ZIR.3897 const decl = file.zir.?.getDeclaration(inst_info.inst);
3724 const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*;
3725 const decl = zir.getDeclaration(inst_info.inst);
3726 if (decl.linkage == .@"export") {3898 if (decl.linkage == .@"export") {
3727 const unit: AnalUnit = .wrap(.{ .nav_val = nav });3899 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
3728 if (!result.contains(unit)) {3900 if (!result.contains(unit)) {
...@@ -3858,7 +4030,7 @@ pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 {...@@ -3858,7 +4030,7 @@ pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 {
3858 const ip = &zcu.intern_pool;4030 const ip = &zcu.intern_pool;
3859 const inst_info = ip.getNav(nav_index).srcInst(ip).resolveFull(ip).?;4031 const inst_info = ip.getNav(nav_index).srcInst(ip).resolveFull(ip).?;
3860 const zir = zcu.fileByIndex(inst_info.file).zir;4032 const zir = zcu.fileByIndex(inst_info.file).zir;
3861 return zir.getDeclaration(inst_info.inst).src_line;4033 return zir.?.getDeclaration(inst_info.inst).src_line;
3862}4034}
38634035
3864pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value {4036pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value {
...@@ -3910,10 +4082,6 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com...@@ -3910,10 +4082,6 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
3910 const zcu = data.zcu;4082 const zcu = data.zcu;
3911 const ip = &zcu.intern_pool;4083 const ip = &zcu.intern_pool;
3912 switch (data.dependee) {4084 switch (data.dependee) {
3913 .file => |file| {
3914 const file_path = zcu.fileByIndex(file).sub_file_path;
3915 return writer.print("file('{s}')", .{file_path});
3916 },
3917 .src_hash => |ti| {4085 .src_hash => |ti| {
3918 const info = ti.resolveFull(ip) orelse {4086 const info = ti.resolveFull(ip) orelse {
3919 return writer.writeAll("inst(<lost>)");4087 return writer.writeAll("inst(<lost>)");
...@@ -3934,6 +4102,10 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com...@@ -3934,6 +4102,10 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
3934 .func => |f| return writer.print("ies('{}')", .{ip.getNav(f.owner_nav).fqn.fmt(ip)}),4102 .func => |f| return writer.print("ies('{}')", .{ip.getNav(f.owner_nav).fqn.fmt(ip)}),
3935 else => unreachable,4103 else => unreachable,
3936 },4104 },
4105 .zon_file => |file| {
4106 const file_path = zcu.fileByIndex(file).sub_file_path;
4107 return writer.print("zon_file('{s}')", .{file_path});
4108 },
3937 .embed_file => |ef_idx| {4109 .embed_file => |ef_idx| {
3938 const ef = ef_idx.get(zcu);4110 const ef = ef_idx.get(zcu);
3939 return writer.print("embed_file('{s}')", .{std.fs.path.fmtJoin(&.{4111 return writer.print("embed_file('{s}')", .{std.fs.path.fmtJoin(&.{
src/Zcu/PerThread.zig+263-288
...@@ -26,6 +26,8 @@ const Type = @import("../Type.zig");...@@ -26,6 +26,8 @@ const Type = @import("../Type.zig");
26const Value = @import("../Value.zig");26const Value = @import("../Value.zig");
27const Zcu = @import("../Zcu.zig");27const Zcu = @import("../Zcu.zig");
28const Zir = std.zig.Zir;28const Zir = std.zig.Zir;
29const Zoir = std.zig.Zoir;
30const ZonGen = std.zig.ZonGen;
2931
30zcu: *Zcu,32zcu: *Zcu,
3133
...@@ -73,7 +75,9 @@ pub fn destroyFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void {...@@ -73,7 +75,9 @@ pub fn destroyFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void {
73 if (!is_builtin) gpa.destroy(file);75 if (!is_builtin) gpa.destroy(file);
74}76}
7577
76pub fn astGenFile(78/// Ensures that `file` has up-to-date ZIR. If not, loads the ZIR cache or runs
79/// AstGen as needed. Also updates `file.status`.
80pub fn updateFile(
77 pt: Zcu.PerThread,81 pt: Zcu.PerThread,
78 file: *Zcu.File,82 file: *Zcu.File,
79 path_digest: Cache.BinDigest,83 path_digest: Cache.BinDigest,
...@@ -109,7 +113,7 @@ pub fn astGenFile(...@@ -109,7 +113,7 @@ pub fn astGenFile(
109113
110 break :lock .shared;114 break :lock .shared;
111 },115 },
112 .parse_failure, .astgen_failure, .success_zir => lock: {116 .astgen_failure, .success => lock: {
113 const unchanged_metadata =117 const unchanged_metadata =
114 stat.size == file.stat.size and118 stat.size == file.stat.size and
115 stat.mtime == file.stat.mtime and119 stat.mtime == file.stat.mtime and
...@@ -126,6 +130,27 @@ pub fn astGenFile(...@@ -126,6 +130,27 @@ pub fn astGenFile(
126 },130 },
127 };131 };
128132
133 // The old compile error, if any, is no longer relevant.
134 pt.lockAndClearFileCompileError(file);
135
136 // If `zir` is not null, and `prev_zir` is null, then `TrackedInst`s are associated with `zir`.
137 // We need to keep it around!
138 // As an optimization, also check `loweringFailed`; if true, but `prev_zir == null`, then this
139 // file has never passed AstGen, so we actually need not cache the old ZIR.
140 if (file.zir != null and file.prev_zir == null and !file.zir.?.loweringFailed()) {
141 assert(file.prev_zir == null);
142 const prev_zir_ptr = try gpa.create(Zir);
143 file.prev_zir = prev_zir_ptr;
144 prev_zir_ptr.* = file.zir.?;
145 file.zir = null;
146 }
147
148 // If ZOIR is changing, then we need to invalidate dependencies on it
149 if (file.zoir != null) file.zoir_invalidated = true;
150
151 // We're going to re-load everything, so unload source, AST, ZIR, ZOIR.
152 file.unload(gpa);
153
129 // We ask for a lock in order to coordinate with other zig processes.154 // We ask for a lock in order to coordinate with other zig processes.
130 // If another process is already working on this file, we will get the cached155 // If another process is already working on this file, we will get the cached
131 // version. Likewise if we're working on AstGen and another process asks for156 // version. Likewise if we're working on AstGen and another process asks for
...@@ -180,190 +205,164 @@ pub fn astGenFile(...@@ -180,190 +205,164 @@ pub fn astGenFile(
180 };205 };
181 defer cache_file.close();206 defer cache_file.close();
182207
183 while (true) {208 const need_update = while (true) {
184 update: {209 const result = switch (file.getMode()) {
185 // First we read the header to determine the lengths of arrays.210 inline else => |mode| try loadZirZoirCache(zcu, cache_file, stat, file, mode),
186 const header = cache_file.reader().readStruct(Zir.Header) catch |err| switch (err) {211 };
187 // This can happen if Zig bails out of this function between creating212 switch (result) {
188 // the cached file and writing it.213 .success => {
189 error.EndOfStream => break :update,214 log.debug("AstGen cached success: {s}", .{file.sub_file_path});
190 else => |e| return e,215 break false;
191 };216 },
192 const unchanged_metadata =217 .invalid => {},
193 stat.size == header.stat_size and218 .truncated => log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path}),
194 stat.mtime == header.stat_mtime and219 .stale => log.debug("AstGen cache stale: {s}", .{file.sub_file_path}),
195 stat.inode == header.stat_inode;
196
197 if (!unchanged_metadata) {
198 log.debug("AstGen cache stale: {s}", .{file.sub_file_path});
199 break :update;
200 }
201 log.debug("AstGen cache hit: {s} instructions_len={d}", .{
202 file.sub_file_path, header.instructions_len,
203 });
204
205 file.zir = Zcu.loadZirCacheBody(gpa, header, cache_file) catch |err| switch (err) {
206 error.UnexpectedFileSize => {
207 log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path});
208 break :update;
209 },
210 else => |e| return e,
211 };
212 file.zir_loaded = true;
213 file.stat = .{
214 .size = header.stat_size,
215 .inode = header.stat_inode,
216 .mtime = header.stat_mtime,
217 };
218 file.prev_status = file.status;
219 file.status = .success_zir;
220 log.debug("AstGen cached success: {s}", .{file.sub_file_path});
221
222 if (file.zir.hasCompileErrors()) {
223 comp.mutex.lock();
224 defer comp.mutex.unlock();
225 try zcu.failed_files.putNoClobber(gpa, file, null);
226 }
227 if (file.zir.loweringFailed()) {
228 file.status = .astgen_failure;
229 return error.AnalysisFail;
230 }
231 return;
232 }220 }
233221
234 // If we already have the exclusive lock then it is our job to update.222 // If we already have the exclusive lock then it is our job to update.
235 if (builtin.os.tag == .wasi or lock == .exclusive) break;223 if (builtin.os.tag == .wasi or lock == .exclusive) break true;
236 // Otherwise, unlock to give someone a chance to get the exclusive lock224 // Otherwise, unlock to give someone a chance to get the exclusive lock
237 // and then upgrade to an exclusive lock.225 // and then upgrade to an exclusive lock.
238 cache_file.unlock();226 cache_file.unlock();
239 lock = .exclusive;227 lock = .exclusive;
240 try cache_file.lock(lock);228 try cache_file.lock(lock);
241 }229 };
242230
243 // The cache is definitely stale so delete the contents to avoid an underwrite later.231 if (need_update) {
244 cache_file.setEndPos(0) catch |err| switch (err) {232 // The cache is definitely stale so delete the contents to avoid an underwrite later.
245 error.FileTooBig => unreachable, // 0 is not too big233 cache_file.setEndPos(0) catch |err| switch (err) {
234 error.FileTooBig => unreachable, // 0 is not too big
235 else => |e| return e,
236 };
246237
247 else => |e| return e,238 if (stat.size > std.math.maxInt(u32))
248 };239 return error.FileTooBig;
249240
250 pt.lockAndClearFileCompileError(file);241 const source = try gpa.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
242 defer if (file.source == null) gpa.free(source);
243 const amt = try source_file.readAll(source);
244 if (amt != stat.size)
245 return error.UnexpectedEndOfFile;
251246
252 // Previous ZIR is kept for two reasons:247 file.source = source;
253 //248
254 // 1. In case an update to the file causes a Parse or AstGen failure, we249 // Any potential AST errors are converted to ZIR errors when we run AstGen/ZonGen.
255 // need to compare two successful ZIR files in order to proceed with an250 file.tree = try Ast.parse(gpa, source, file.getMode());
256 // incremental update. This avoids needlessly tossing out semantic
257 // analysis work when an error is temporarily introduced.
258 //
259 // 2. In order to detect updates, we need to iterate over the intern pool
260 // values while comparing old ZIR to new ZIR. This is better done in a
261 // single-threaded context, so we need to keep both versions around
262 // until that point in the pipeline. Previous ZIR data is freed after
263 // that.
264 if (file.zir_loaded and !file.zir.loweringFailed()) {
265 assert(file.prev_zir == null);
266 const prev_zir_ptr = try gpa.create(Zir);
267 file.prev_zir = prev_zir_ptr;
268 prev_zir_ptr.* = file.zir;
269 file.zir = undefined;
270 file.zir_loaded = false;
271 }
272 file.unload(gpa);
273251
274 if (stat.size > std.math.maxInt(u32))252 switch (file.getMode()) {
275 return error.FileTooBig;253 .zig => {
254 file.zir = try AstGen.generate(gpa, file.tree.?);
255 Zcu.saveZirCache(gpa, cache_file, stat, file.zir.?) catch |err| switch (err) {
256 error.OutOfMemory => |e| return e,
257 else => log.warn("unable to write cached ZIR code for {}{s} to {}{s}: {s}", .{
258 file.mod.root, file.sub_file_path, cache_directory, &hex_digest, @errorName(err),
259 }),
260 };
261 },
262 .zon => {
263 file.zoir = try ZonGen.generate(gpa, file.tree.?, .{});
264 Zcu.saveZoirCache(cache_file, stat, file.zoir.?) catch |err| {
265 log.warn("unable to write cached ZOIR code for {}{s} to {}{s}: {s}", .{
266 file.mod.root, file.sub_file_path, cache_directory, &hex_digest, @errorName(err),
267 });
268 };
269 },
270 }
276271
277 const source = try gpa.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);272 log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
278 defer if (!file.source_loaded) gpa.free(source);273 }
279 const amt = try source_file.readAll(source);
280 if (amt != stat.size)
281 return error.UnexpectedEndOfFile;
282274
283 file.stat = .{275 file.stat = .{
284 .size = stat.size,276 .size = stat.size,
285 .inode = stat.inode,277 .inode = stat.inode,
286 .mtime = stat.mtime,278 .mtime = stat.mtime,
287 };279 };
288 file.source = source;
289 file.source_loaded = true;
290280
291 file.tree = try Ast.parse(gpa, source, .zig);281 // Now, `zir` or `zoir` is definitely populated and up-to-date.
292 file.tree_loaded = true;282 // Mark file successes/failures as needed.
293283
294 // Any potential AST errors are converted to ZIR errors here.284 switch (file.getMode()) {
295 file.zir = try AstGen.generate(gpa, file.tree);285 .zig => {
296 file.zir_loaded = true;286 if (file.zir.?.hasCompileErrors()) {
297 file.prev_status = file.status;287 comp.mutex.lock();
298 file.status = .success_zir;288 defer comp.mutex.unlock();
299 log.debug("AstGen fresh success: {s}", .{file.sub_file_path});289 try zcu.failed_files.putNoClobber(gpa, file, null);
290 }
291 if (file.zir.?.loweringFailed()) {
292 file.status = .astgen_failure;
293 } else {
294 file.status = .success;
295 }
296 },
297 .zon => {
298 if (file.zoir.?.hasCompileErrors()) {
299 file.status = .astgen_failure;
300 comp.mutex.lock();
301 defer comp.mutex.unlock();
302 try zcu.failed_files.putNoClobber(gpa, file, null);
303 } else {
304 file.status = .success;
305 }
306 },
307 }
300308
301 const safety_buffer = if (Zcu.data_has_safety_tag)309 switch (file.status) {
302 try gpa.alloc([8]u8, file.zir.instructions.len)310 .never_loaded => unreachable,
303 else311 .retryable_failure => unreachable,
304 undefined;312 .astgen_failure => return error.AnalysisFail,
305 defer if (Zcu.data_has_safety_tag) gpa.free(safety_buffer);313 .success => return,
306 const data_ptr = if (Zcu.data_has_safety_tag)
307 if (file.zir.instructions.len == 0)
308 @as([*]const u8, undefined)
309 else
310 @as([*]const u8, @ptrCast(safety_buffer.ptr))
311 else
312 @as([*]const u8, @ptrCast(file.zir.instructions.items(.data).ptr));
313 if (Zcu.data_has_safety_tag) {
314 // The `Data` union has a safety tag but in the file format we store it without.
315 for (file.zir.instructions.items(.data), 0..) |*data, i| {
316 const as_struct: *const Zcu.HackDataLayout = @ptrCast(data);
317 safety_buffer[i] = as_struct.data;
318 }
319 }314 }
315}
320316
321 const header: Zir.Header = .{317fn loadZirZoirCache(
322 .instructions_len = @as(u32, @intCast(file.zir.instructions.len)),318 zcu: *Zcu,
323 .string_bytes_len = @as(u32, @intCast(file.zir.string_bytes.len)),319 cache_file: std.fs.File,
324 .extra_len = @as(u32, @intCast(file.zir.extra.len)),320 stat: std.fs.File.Stat,
321 file: *Zcu.File,
322 comptime mode: Ast.Mode,
323) !enum { success, invalid, truncated, stale } {
324 assert(file.getMode() == mode);
325325
326 .stat_size = stat.size,326 const gpa = zcu.gpa;
327 .stat_inode = stat.inode,327
328 .stat_mtime = stat.mtime,328 const Header = switch (mode) {
329 };329 .zig => Zir.Header,
330 var iovecs = [_]std.posix.iovec_const{330 .zon => Zoir.Header,
331 .{
332 .base = @as([*]const u8, @ptrCast(&header)),
333 .len = @sizeOf(Zir.Header),
334 },
335 .{
336 .base = @as([*]const u8, @ptrCast(file.zir.instructions.items(.tag).ptr)),
337 .len = file.zir.instructions.len,
338 },
339 .{
340 .base = data_ptr,
341 .len = file.zir.instructions.len * 8,
342 },
343 .{
344 .base = file.zir.string_bytes.ptr,
345 .len = file.zir.string_bytes.len,
346 },
347 .{
348 .base = @as([*]const u8, @ptrCast(file.zir.extra.ptr)),
349 .len = file.zir.extra.len * 4,
350 },
351 };331 };
352 cache_file.writevAll(&iovecs) catch |err| {332
353 log.warn("unable to write cached ZIR code for {}{s} to {}{s}: {s}", .{333 // First we read the header to determine the lengths of arrays.
354 file.mod.root, file.sub_file_path, cache_directory, &hex_digest, @errorName(err),334 const header = cache_file.reader().readStruct(Header) catch |err| switch (err) {
355 });335 // This can happen if Zig bails out of this function between creating
336 // the cached file and writing it.
337 error.EndOfStream => return .invalid,
338 else => |e| return e,
356 };339 };
357340
358 if (file.zir.hasCompileErrors()) {341 const unchanged_metadata =
359 comp.mutex.lock();342 stat.size == header.stat_size and
360 defer comp.mutex.unlock();343 stat.mtime == header.stat_mtime and
361 try zcu.failed_files.putNoClobber(gpa, file, null);344 stat.inode == header.stat_inode;
345
346 if (!unchanged_metadata) {
347 return .stale;
362 }348 }
363 if (file.zir.loweringFailed()) {349
364 file.status = .astgen_failure;350 switch (mode) {
365 return error.AnalysisFail;351 .zig => {
352 file.zir = Zcu.loadZirCacheBody(gpa, header, cache_file) catch |err| switch (err) {
353 error.UnexpectedFileSize => return .truncated,
354 else => |e| return e,
355 };
356 },
357 .zon => {
358 file.zoir = Zcu.loadZoirCacheBody(gpa, header, cache_file) catch |err| switch (err) {
359 error.UnexpectedFileSize => return .truncated,
360 else => |e| return e,
361 };
362 },
366 }363 }
364
365 return .success;
367}366}
368367
369const UpdatedFile = struct {368const UpdatedFile = struct {
...@@ -384,24 +383,32 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -384,24 +383,32 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
384 const gpa = zcu.gpa;383 const gpa = zcu.gpa;
385384
386 // We need to visit every updated File for every TrackedInst in InternPool.385 // We need to visit every updated File for every TrackedInst in InternPool.
386 // This only includes Zig files; ZON files are omitted.
387 var updated_files: std.AutoArrayHashMapUnmanaged(Zcu.File.Index, UpdatedFile) = .empty;387 var updated_files: std.AutoArrayHashMapUnmanaged(Zcu.File.Index, UpdatedFile) = .empty;
388 defer cleanupUpdatedFiles(gpa, &updated_files);388 defer cleanupUpdatedFiles(gpa, &updated_files);
389
389 for (zcu.import_table.values()) |file_index| {390 for (zcu.import_table.values()) |file_index| {
390 const file = zcu.fileByIndex(file_index);391 const file = zcu.fileByIndex(file_index);
391 if (file.prev_status != file.status and file.prev_status != .never_loaded) {392 assert(file.status == .success);
392 try zcu.markDependeeOutdated(.not_marked_po, .{ .file = file_index });393 switch (file.getMode()) {
394 .zig => {}, // logic below
395 .zon => {
396 if (file.zoir_invalidated) {
397 try zcu.markDependeeOutdated(.not_marked_po, .{ .zon_file = file_index });
398 file.zoir_invalidated = false;
399 }
400 continue;
401 },
393 }402 }
394 const old_zir = file.prev_zir orelse continue;403 const old_zir = file.prev_zir orelse continue;
395 const new_zir = file.zir;404 const new_zir = file.zir.?;
396 const gop = try updated_files.getOrPut(gpa, file_index);405 const gop = try updated_files.getOrPut(gpa, file_index);
397 assert(!gop.found_existing);406 assert(!gop.found_existing);
398 gop.value_ptr.* = .{407 gop.value_ptr.* = .{
399 .file = file,408 .file = file,
400 .inst_map = .{},409 .inst_map = .{},
401 };410 };
402 if (!new_zir.loweringFailed()) {411 try Zcu.mapOldZirToNew(gpa, old_zir.*, new_zir, &gop.value_ptr.inst_map);
403 try Zcu.mapOldZirToNew(gpa, old_zir.*, file.zir, &gop.value_ptr.inst_map);
404 }
405 }412 }
406413
407 if (updated_files.count() == 0)414 if (updated_files.count() == 0)
...@@ -421,13 +428,9 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -421,13 +428,9 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
421 .index = @intCast(tracked_inst_unwrapped_index),428 .index = @intCast(tracked_inst_unwrapped_index),
422 }).wrap(ip);429 }).wrap(ip);
423 const new_inst = updated_file.inst_map.get(old_inst) orelse {430 const new_inst = updated_file.inst_map.get(old_inst) orelse {
424 // Tracking failed for this instruction.431 // Tracking failed for this instruction due to changes in the ZIR.
425 // This may be due to changes in the ZIR, or AstGen might have failed due to a very broken file.432 // Invalidate associated `src_hash` deps.
426 // Either way, invalidate associated `src_hash` deps.433 log.debug("tracking failed for %{d}", .{old_inst});
427 log.debug("tracking failed for %{d}{s}", .{
428 old_inst,
429 if (file.zir.loweringFailed()) " due to AstGen failure" else "",
430 });
431 tracked_inst.inst = .lost;434 tracked_inst.inst = .lost;
432 try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index });435 try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index });
433 continue;436 continue;
...@@ -435,7 +438,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -435,7 +438,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
435 tracked_inst.inst = InternPool.TrackedInst.MaybeLost.ZirIndex.wrap(new_inst);438 tracked_inst.inst = InternPool.TrackedInst.MaybeLost.ZirIndex.wrap(new_inst);
436439
437 const old_zir = file.prev_zir.?.*;440 const old_zir = file.prev_zir.?.*;
438 const new_zir = file.zir;441 const new_zir = file.zir.?;
439 const old_tag = old_zir.instructions.items(.tag)[@intFromEnum(old_inst)];442 const old_tag = old_zir.instructions.items(.tag)[@intFromEnum(old_inst)];
440 const old_data = old_zir.instructions.items(.data)[@intFromEnum(old_inst)];443 const old_data = old_zir.instructions.items(.data)[@intFromEnum(old_inst)];
441444
...@@ -532,23 +535,19 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -532,23 +535,19 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
532535
533 for (updated_files.keys(), updated_files.values()) |file_index, updated_file| {536 for (updated_files.keys(), updated_files.values()) |file_index, updated_file| {
534 const file = updated_file.file;537 const file = updated_file.file;
535 if (file.zir.loweringFailed()) {538
536 // Keep `prev_zir` around: it's the last usable ZIR.539 const prev_zir = file.prev_zir.?;
537 // Don't update the namespace, as we have no new data to update *to*.540 file.prev_zir = null;
538 } else {541 prev_zir.deinit(gpa);
539 const prev_zir = file.prev_zir.?;542 gpa.destroy(prev_zir);
540 file.prev_zir = null;543
541 prev_zir.deinit(gpa);544 // For every file which has changed, re-scan the namespace of the file's root struct type.
542 gpa.destroy(prev_zir);545 // These types are special-cased because they don't have an enclosing declaration which will
543546 // be re-analyzed (causing the struct's namespace to be re-scanned). It's fine to do this
544 // For every file which has changed, re-scan the namespace of the file's root struct type.547 // now because this work is fast (no actual Sema work is happening, we're just updating the
545 // These types are special-cased because they don't have an enclosing declaration which will548 // namespace contents). We must do this after updating ZIR refs above, since `scanNamespace`
546 // be re-analyzed (causing the struct's namespace to be re-scanned). It's fine to do this549 // will track some instructions.
547 // now because this work is fast (no actual Sema work is happening, we're just updating the550 try pt.updateFileNamespace(file_index);
548 // namespace contents). We must do this after updating ZIR refs above, since `scanNamespace`
549 // will track some instructions.
550 try pt.updateFileNamespace(file_index);
551 }
552 }551 }
553}552}
554553
...@@ -750,6 +749,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU...@@ -750,6 +749,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU
750 kv.value.destroy(gpa);749 kv.value.destroy(gpa);
751 }750 }
752 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);751 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
752 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
753 }753 }
754 } else {754 } else {
755 // We can trust the current information about this unit.755 // We can trust the current information about this unit.
...@@ -801,14 +801,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu...@@ -801,14 +801,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
801801
802 const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse return error.AnalysisFail;802 const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
803 const file = zcu.fileByIndex(inst_resolved.file);803 const file = zcu.fileByIndex(inst_resolved.file);
804 // TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is804 const zir = file.zir.?;
805 // unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends
806 // in `ensureComptimeUnitUpToDate`.
807 if (file.status != .success_zir) return error.AnalysisFail;
808 const zir = file.zir;
809
810 // We are about to re-analyze this unit; drop its depenndencies.
811 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
812805
813 try zcu.analysis_in_progress.put(gpa, anal_unit, {});806 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
814 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));807 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
...@@ -928,6 +921,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu...@@ -928,6 +921,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
928 kv.value.destroy(gpa);921 kv.value.destroy(gpa);
929 }922 }
930 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);923 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
924 ip.removeDependenciesForDepender(gpa, anal_unit);
931 } else {925 } else {
932 // We can trust the current information about this unit.926 // We can trust the current information about this unit.
933 if (prev_failed) return error.AnalysisFail;927 if (prev_failed) return error.AnalysisFail;
...@@ -998,14 +992,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -998,14 +992,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
998992
999 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;993 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
1000 const file = zcu.fileByIndex(inst_resolved.file);994 const file = zcu.fileByIndex(inst_resolved.file);
1001 // TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is995 const zir = file.zir.?;
1002 // unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends
1003 // in `ensureComptimeUnitUpToDate`.
1004 if (file.status != .success_zir) return error.AnalysisFail;
1005 const zir = file.zir;
1006
1007 // We are about to re-analyze this unit; drop its depenndencies.
1008 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
1009996
1010 try zcu.analysis_in_progress.put(gpa, anal_unit, {});997 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
1011 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);998 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
...@@ -1306,6 +1293,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc...@@ -1306,6 +1293,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
1306 kv.value.destroy(gpa);1293 kv.value.destroy(gpa);
1307 }1294 }
1308 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);1295 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
1296 ip.removeDependenciesForDepender(gpa, anal_unit);
1309 } else {1297 } else {
1310 // We can trust the current information about this unit.1298 // We can trust the current information about this unit.
1311 if (prev_failed) return error.AnalysisFail;1299 if (prev_failed) return error.AnalysisFail;
...@@ -1376,14 +1364,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr...@@ -1376,14 +1364,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
13761364
1377 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;1365 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
1378 const file = zcu.fileByIndex(inst_resolved.file);1366 const file = zcu.fileByIndex(inst_resolved.file);
1379 // TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is1367 const zir = file.zir.?;
1380 // unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends
1381 // in `ensureComptimeUnitUpToDate`.
1382 if (file.status != .success_zir) return error.AnalysisFail;
1383 const zir = file.zir;
1384
1385 // We are about to re-analyze this unit; drop its depenndencies.
1386 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
13871368
1388 try zcu.analysis_in_progress.put(gpa, anal_unit, {});1369 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
1389 defer _ = zcu.analysis_in_progress.swapRemove(anal_unit);1370 defer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
...@@ -1758,7 +1739,7 @@ fn createFileRootStruct(...@@ -1758,7 +1739,7 @@ fn createFileRootStruct(
1758 const gpa = zcu.gpa;1739 const gpa = zcu.gpa;
1759 const ip = &zcu.intern_pool;1740 const ip = &zcu.intern_pool;
1760 const file = zcu.fileByIndex(file_index);1741 const file = zcu.fileByIndex(file_index);
1761 const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;1742 const extended = file.zir.?.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
1762 assert(extended.opcode == .struct_decl);1743 assert(extended.opcode == .struct_decl);
1763 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);1744 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
1764 assert(!small.has_captures_len);1745 assert(!small.has_captures_len);
...@@ -1766,16 +1747,16 @@ fn createFileRootStruct(...@@ -1766,16 +1747,16 @@ fn createFileRootStruct(
1766 assert(small.layout == .auto);1747 assert(small.layout == .auto);
1767 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;1748 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
1768 const fields_len = if (small.has_fields_len) blk: {1749 const fields_len = if (small.has_fields_len) blk: {
1769 const fields_len = file.zir.extra[extra_index];1750 const fields_len = file.zir.?.extra[extra_index];
1770 extra_index += 1;1751 extra_index += 1;
1771 break :blk fields_len;1752 break :blk fields_len;
1772 } else 0;1753 } else 0;
1773 const decls_len = if (small.has_decls_len) blk: {1754 const decls_len = if (small.has_decls_len) blk: {
1774 const decls_len = file.zir.extra[extra_index];1755 const decls_len = file.zir.?.extra[extra_index];
1775 extra_index += 1;1756 extra_index += 1;
1776 break :blk decls_len;1757 break :blk decls_len;
1777 } else 0;1758 } else 0;
1778 const decls = file.zir.bodySlice(extra_index, decls_len);1759 const decls = file.zir.?.bodySlice(extra_index, decls_len);
1779 extra_index += decls_len;1760 extra_index += decls_len;
17801761
1781 const tracked_inst = try ip.trackZir(gpa, pt.tid, .{1762 const tracked_inst = try ip.trackZir(gpa, pt.tid, .{
...@@ -1833,7 +1814,6 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator....@@ -1833,7 +1814,6 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.
1833 const zcu = pt.zcu;1814 const zcu = pt.zcu;
18341815
1835 const file = zcu.fileByIndex(file_index);1816 const file = zcu.fileByIndex(file_index);
1836 assert(file.status == .success_zir);
1837 const file_root_type = zcu.fileRootType(file_index);1817 const file_root_type = zcu.fileRootType(file_index);
1838 if (file_root_type == .none) return;1818 if (file_root_type == .none) return;
18391819
...@@ -1844,17 +1824,17 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator....@@ -1844,17 +1824,17 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.
18441824
1845 const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu);1825 const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu);
1846 const decls = decls: {1826 const decls = decls: {
1847 const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;1827 const extended = file.zir.?.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
1848 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);1828 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
18491829
1850 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;1830 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
1851 extra_index += @intFromBool(small.has_fields_len);1831 extra_index += @intFromBool(small.has_fields_len);
1852 const decls_len = if (small.has_decls_len) blk: {1832 const decls_len = if (small.has_decls_len) blk: {
1853 const decls_len = file.zir.extra[extra_index];1833 const decls_len = file.zir.?.extra[extra_index];
1854 extra_index += 1;1834 extra_index += 1;
1855 break :blk decls_len;1835 break :blk decls_len;
1856 } else 0;1836 } else 0;
1857 break :decls file.zir.bodySlice(extra_index, decls_len);1837 break :decls file.zir.?.bodySlice(extra_index, decls_len);
1858 };1838 };
1859 try pt.scanNamespace(namespace_index, decls);1839 try pt.scanNamespace(namespace_index, decls);
1860 zcu.namespacePtr(namespace_index).generation = zcu.generation;1840 zcu.namespacePtr(namespace_index).generation = zcu.generation;
...@@ -1865,15 +1845,11 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {...@@ -1865,15 +1845,11 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
1865 defer tracy.end();1845 defer tracy.end();
18661846
1867 const zcu = pt.zcu;1847 const zcu = pt.zcu;
1868 const gpa = zcu.gpa;
1869 const file = zcu.fileByIndex(file_index);1848 const file = zcu.fileByIndex(file_index);
1870 assert(file.getMode() == .zig);1849 assert(file.getMode() == .zig);
1871 assert(zcu.fileRootType(file_index) == .none);1850 assert(zcu.fileRootType(file_index) == .none);
18721851
1873 if (file.status != .success_zir) {1852 assert(file.zir != null);
1874 return error.AnalysisFail;
1875 }
1876 assert(file.zir_loaded);
18771853
1878 const new_namespace_index = try pt.createNamespace(.{1854 const new_namespace_index = try pt.createNamespace(.{
1879 .parent = .none,1855 .parent = .none,
...@@ -1883,39 +1859,9 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {...@@ -1883,39 +1859,9 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
1883 });1859 });
1884 const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index, false);1860 const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index, false);
1885 errdefer zcu.intern_pool.remove(pt.tid, struct_ty);1861 errdefer zcu.intern_pool.remove(pt.tid, struct_ty);
1886
1887 switch (zcu.comp.cache_use) {
1888 .whole => |whole| if (whole.cache_manifest) |man| {
1889 const source = file.getSource(gpa) catch |err| {
1890 try pt.reportRetryableFileError(file_index, "unable to load source: {s}", .{@errorName(err)});
1891 return error.AnalysisFail;
1892 };
1893
1894 const resolved_path = std.fs.path.resolve(gpa, &.{
1895 file.mod.root.root_dir.path orelse ".",
1896 file.mod.root.sub_path,
1897 file.sub_file_path,
1898 }) catch |err| {
1899 try pt.reportRetryableFileError(file_index, "unable to resolve path: {s}", .{@errorName(err)});
1900 return error.AnalysisFail;
1901 };
1902 errdefer gpa.free(resolved_path);
1903
1904 whole.cache_manifest_mutex.lock();
1905 defer whole.cache_manifest_mutex.unlock();
1906 man.addFilePostContents(resolved_path, source.bytes, source.stat) catch |err| switch (err) {
1907 error.OutOfMemory => |e| return e,
1908 else => {
1909 try pt.reportRetryableFileError(file_index, "unable to update cache: {s}", .{@errorName(err)});
1910 return error.AnalysisFail;
1911 },
1912 };
1913 },
1914 .incremental => {},
1915 }
1916}1862}
19171863
1918pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {1864pub fn importPkg(pt: Zcu.PerThread, mod: *Module) Allocator.Error!Zcu.ImportFileResult {
1919 const zcu = pt.zcu;1865 const zcu = pt.zcu;
1920 const gpa = zcu.gpa;1866 const gpa = zcu.gpa;
19211867
...@@ -1983,15 +1929,12 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {...@@ -1983,15 +1929,12 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {
1983 gop.value_ptr.* = new_file_index;1929 gop.value_ptr.* = new_file_index;
1984 new_file.* = .{1930 new_file.* = .{
1985 .sub_file_path = sub_file_path,1931 .sub_file_path = sub_file_path,
1986 .source = undefined,
1987 .source_loaded = false,
1988 .tree_loaded = false,
1989 .zir_loaded = false,
1990 .stat = undefined,1932 .stat = undefined,
1991 .tree = undefined,1933 .source = null,
1992 .zir = undefined,1934 .tree = null,
1935 .zir = null,
1936 .zoir = null,
1993 .status = .never_loaded,1937 .status = .never_loaded,
1994 .prev_status = .never_loaded,
1995 .mod = mod,1938 .mod = mod,
1996 };1939 };
19971940
...@@ -2004,13 +1947,19 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {...@@ -2004,13 +1947,19 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {
2004 };1947 };
2005}1948}
20061949
2007/// Called from a worker thread during AstGen.1950/// Called from a worker thread during AstGen (with the Compilation mutex held).
2008/// Also called from Sema during semantic analysis.1951/// Also called from Sema during semantic analysis.
1952/// Does not attempt to load the file from disk; just returns a corresponding `*Zcu.File`.
2009pub fn importFile(1953pub fn importFile(
2010 pt: Zcu.PerThread,1954 pt: Zcu.PerThread,
2011 cur_file: *Zcu.File,1955 cur_file: *Zcu.File,
2012 import_string: []const u8,1956 import_string: []const u8,
2013) !Zcu.ImportFileResult {1957) error{
1958 OutOfMemory,
1959 ModuleNotFound,
1960 ImportOutsideModulePath,
1961 CurrentWorkingDirectoryUnlinked,
1962}!Zcu.ImportFileResult {
2014 const zcu = pt.zcu;1963 const zcu = pt.zcu;
2015 const mod = cur_file.mod;1964 const mod = cur_file.mod;
20161965
...@@ -2068,7 +2017,10 @@ pub fn importFile(...@@ -2068,7 +2017,10 @@ pub fn importFile(
2068 defer gpa.free(resolved_root_path);2017 defer gpa.free(resolved_root_path);
20692018
2070 const sub_file_path = p: {2019 const sub_file_path = p: {
2071 const relative = try std.fs.path.relative(gpa, resolved_root_path, resolved_path);2020 const relative = std.fs.path.relative(gpa, resolved_root_path, resolved_path) catch |err| switch (err) {
2021 error.Unexpected => unreachable,
2022 else => |e| return e,
2023 };
2072 errdefer gpa.free(relative);2024 errdefer gpa.free(relative);
20732025
2074 if (!isUpDir(relative) and !std.fs.path.isAbsolute(relative)) {2026 if (!isUpDir(relative) and !std.fs.path.isAbsolute(relative)) {
...@@ -2096,15 +2048,15 @@ pub fn importFile(...@@ -2096,15 +2048,15 @@ pub fn importFile(
2096 gop.value_ptr.* = new_file_index;2048 gop.value_ptr.* = new_file_index;
2097 new_file.* = .{2049 new_file.* = .{
2098 .sub_file_path = sub_file_path,2050 .sub_file_path = sub_file_path,
2099 .source = undefined,2051
2100 .source_loaded = false,
2101 .tree_loaded = false,
2102 .zir_loaded = false,
2103 .stat = undefined,
2104 .tree = undefined,
2105 .zir = undefined,
2106 .status = .never_loaded,2052 .status = .never_loaded,
2107 .prev_status = .never_loaded,2053 .stat = undefined,
2054
2055 .source = null,
2056 .tree = null,
2057 .zir = null,
2058 .zoir = null,
2059
2108 .mod = mod,2060 .mod = mod,
2109 };2061 };
21102062
...@@ -2441,7 +2393,7 @@ const ScanDeclIter = struct {...@@ -2441,7 +2393,7 @@ const ScanDeclIter = struct {
2441 const namespace = zcu.namespacePtr(namespace_index);2393 const namespace = zcu.namespacePtr(namespace_index);
2442 const gpa = zcu.gpa;2394 const gpa = zcu.gpa;
2443 const file = namespace.fileScope(zcu);2395 const file = namespace.fileScope(zcu);
2444 const zir = file.zir;2396 const zir = file.zir.?;
2445 const ip = &zcu.intern_pool;2397 const ip = &zcu.intern_pool;
24462398
2447 const decl = zir.getDeclaration(decl_inst);2399 const decl = zir.getDeclaration(decl_inst);
...@@ -2591,7 +2543,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE...@@ -2591,7 +2543,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
2591 const func = zcu.funcInfo(func_index);2543 const func = zcu.funcInfo(func_index);
2592 const inst_info = func.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail;2544 const inst_info = func.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail;
2593 const file = zcu.fileByIndex(inst_info.file);2545 const file = zcu.fileByIndex(inst_info.file);
2594 const zir = file.zir;2546 const zir = file.zir.?;
25952547
2596 try zcu.analysis_in_progress.put(gpa, anal_unit, {});2548 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
2597 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);2549 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
...@@ -2843,11 +2795,32 @@ pub fn getErrorValueFromSlice(pt: Zcu.PerThread, name: []const u8) Allocator.Err...@@ -2843,11 +2795,32 @@ pub fn getErrorValueFromSlice(pt: Zcu.PerThread, name: []const u8) Allocator.Err
2843/// Removes any entry from `Zcu.failed_files` associated with `file`. Acquires `Compilation.mutex` as needed.2795/// Removes any entry from `Zcu.failed_files` associated with `file`. Acquires `Compilation.mutex` as needed.
2844/// `file.zir` must be unchanged from the last update, as it is used to determine if there is such an entry.2796/// `file.zir` must be unchanged from the last update, as it is used to determine if there is such an entry.
2845fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void {2797fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void {
2846 if (!file.zir_loaded or !file.zir.hasCompileErrors()) return;2798 const maybe_has_error = switch (file.status) {
2799 .never_loaded => false,
2800 .retryable_failure => true,
2801 .astgen_failure => true,
2802 .success => switch (file.getMode()) {
2803 .zig => has_error: {
2804 const zir = file.zir orelse break :has_error false;
2805 break :has_error zir.hasCompileErrors();
2806 },
2807 .zon => has_error: {
2808 const zoir = file.zoir orelse break :has_error false;
2809 break :has_error zoir.hasCompileErrors();
2810 },
2811 },
2812 };
2813
2814 // If runtime safety is on, let's quickly lock the mutex and check anyway.
2815 if (!maybe_has_error and !std.debug.runtime_safety) {
2816 return;
2817 }
2818
2847 pt.zcu.comp.mutex.lock();2819 pt.zcu.comp.mutex.lock();
2848 defer pt.zcu.comp.mutex.unlock();2820 defer pt.zcu.comp.mutex.unlock();
2849 if (pt.zcu.failed_files.fetchSwapRemove(file)) |kv| {2821 if (pt.zcu.failed_files.fetchSwapRemove(file)) |kv| {
2850 if (kv.value) |msg| msg.destroy(pt.zcu.gpa); // Delete previous error message.2822 assert(maybe_has_error); // the runtime safety case above
2823 if (kv.value) |msg| msg.destroy(pt.zcu.gpa); // delete previous error message
2851 }2824 }
2852}2825}
28532826
...@@ -3203,6 +3176,7 @@ pub fn linkerUpdateLineNumber(pt: Zcu.PerThread, ti: InternPool.TrackedInst.Inde...@@ -3203,6 +3176,7 @@ pub fn linkerUpdateLineNumber(pt: Zcu.PerThread, ti: InternPool.TrackedInst.Inde
3203 }3176 }
3204}3177}
32053178
3179/// Sets `File.status` of `file_index` to `retryable_failure`, and stores an error in `pt.zcu.failed_files`.
3206pub fn reportRetryableAstGenError(3180pub fn reportRetryableAstGenError(
3207 pt: Zcu.PerThread,3181 pt: Zcu.PerThread,
3208 src: Zcu.AstGenSrc,3182 src: Zcu.AstGenSrc,
...@@ -3238,13 +3212,18 @@ pub fn reportRetryableAstGenError(...@@ -3238,13 +3212,18 @@ pub fn reportRetryableAstGenError(
3238 });3212 });
3239 errdefer err_msg.destroy(gpa);3213 errdefer err_msg.destroy(gpa);
32403214
3241 {3215 zcu.comp.mutex.lock();
3242 zcu.comp.mutex.lock();3216 defer zcu.comp.mutex.unlock();
3243 defer zcu.comp.mutex.unlock();3217 const gop = try zcu.failed_files.getOrPut(gpa, file);
3244 try zcu.failed_files.putNoClobber(gpa, file, err_msg);3218 if (gop.found_existing) {
3219 if (gop.value_ptr.*) |old_err_msg| {
3220 old_err_msg.destroy(gpa);
3221 }
3245 }3222 }
3223 gop.value_ptr.* = err_msg;
3246}3224}
32473225
3226/// Sets `File.status` of `file_index` to `retryable_failure`, and stores an error in `pt.zcu.failed_files`.
3248pub fn reportRetryableFileError(3227pub fn reportRetryableFileError(
3249 pt: Zcu.PerThread,3228 pt: Zcu.PerThread,
3250 file_index: Zcu.File.Index,3229 file_index: Zcu.File.Index,
...@@ -3778,8 +3757,7 @@ fn recreateStructType(...@@ -3778,8 +3757,7 @@ fn recreateStructType(
37783757
3779 const inst_info = key.zir_index.resolveFull(ip).?;3758 const inst_info = key.zir_index.resolveFull(ip).?;
3780 const file = zcu.fileByIndex(inst_info.file);3759 const file = zcu.fileByIndex(inst_info.file);
3781 assert(file.status == .success_zir); // otherwise inst tracking failed3760 const zir = file.zir.?;
3782 const zir = file.zir;
37833761
3784 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);3762 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
3785 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;3763 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
...@@ -3851,8 +3829,7 @@ fn recreateUnionType(...@@ -3851,8 +3829,7 @@ fn recreateUnionType(
38513829
3852 const inst_info = key.zir_index.resolveFull(ip).?;3830 const inst_info = key.zir_index.resolveFull(ip).?;
3853 const file = zcu.fileByIndex(inst_info.file);3831 const file = zcu.fileByIndex(inst_info.file);
3854 assert(file.status == .success_zir); // otherwise inst tracking failed3832 const zir = file.zir.?;
3855 const zir = file.zir;
38563833
3857 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);3834 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
3858 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;3835 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
...@@ -3938,8 +3915,7 @@ fn recreateEnumType(...@@ -3938,8 +3915,7 @@ fn recreateEnumType(
39383915
3939 const inst_info = key.zir_index.resolveFull(ip).?;3916 const inst_info = key.zir_index.resolveFull(ip).?;
3940 const file = zcu.fileByIndex(inst_info.file);3917 const file = zcu.fileByIndex(inst_info.file);
3941 assert(file.status == .success_zir); // otherwise inst tracking failed3918 const zir = file.zir.?;
3942 const zir = file.zir;
39433919
3944 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);3920 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
3945 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;3921 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
...@@ -4082,8 +4058,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace...@@ -4082,8 +4058,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
40824058
4083 const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail;4059 const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
4084 const file = zcu.fileByIndex(inst_info.file);4060 const file = zcu.fileByIndex(inst_info.file);
4085 if (file.status != .success_zir) return error.AnalysisFail;4061 const zir = file.zir.?;
4086 const zir = file.zir;
40874062
4088 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);4063 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
4089 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;4064 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
src/link.zig+1-2
...@@ -750,8 +750,7 @@ pub const File = struct {...@@ -750,8 +750,7 @@ pub const File = struct {
750 {750 {
751 const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?;751 const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?;
752 const file = pt.zcu.fileByIndex(ti.file);752 const file = pt.zcu.fileByIndex(ti.file);
753 assert(file.zir_loaded);753 const inst = file.zir.?.instructions.get(@intFromEnum(ti.inst));
754 const inst = file.zir.instructions.get(@intFromEnum(ti.inst));
755 assert(inst.tag == .declaration);754 assert(inst.tag == .declaration);
756 }755 }
757756
src/link/Dwarf.zig+7-10
...@@ -2358,8 +2358,7 @@ fn initWipNavInner(...@@ -2358,8 +2358,7 @@ fn initWipNavInner(
2358 const nav = ip.getNav(nav_index);2358 const nav = ip.getNav(nav_index);
2359 const inst_info = nav.srcInst(ip).resolveFull(ip).?;2359 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
2360 const file = zcu.fileByIndex(inst_info.file);2360 const file = zcu.fileByIndex(inst_info.file);
2361 assert(file.zir_loaded);2361 const decl = file.zir.?.getDeclaration(inst_info.inst);
2362 const decl = file.zir.getDeclaration(inst_info.inst);
2363 log.debug("initWipNav({s}:{d}:{d} %{d} = {})", .{2362 log.debug("initWipNav({s}:{d}:{d} %{d} = {})", .{
2364 file.sub_file_path,2363 file.sub_file_path,
2365 decl.src_line + 1,2364 decl.src_line + 1,
...@@ -2373,7 +2372,7 @@ fn initWipNavInner(...@@ -2373,7 +2372,7 @@ fn initWipNavInner(
2373 switch (nav_key) {2372 switch (nav_key) {
2374 // Ignore @extern2373 // Ignore @extern
2375 .@"extern" => |@"extern"| if (decl.linkage != .@"extern" or2374 .@"extern" => |@"extern"| if (decl.linkage != .@"extern" or
2376 !@"extern".name.eqlSlice(file.zir.nullTerminatedString(decl.name), ip)) return null,2375 !@"extern".name.eqlSlice(file.zir.?.nullTerminatedString(decl.name), ip)) return null,
2377 else => {},2376 else => {},
2378 }2377 }
23792378
...@@ -2696,8 +2695,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -2696,8 +2695,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
2696 const nav = ip.getNav(nav_index);2695 const nav = ip.getNav(nav_index);
2697 const inst_info = nav.srcInst(ip).resolveFull(ip).?;2696 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
2698 const file = zcu.fileByIndex(inst_info.file);2697 const file = zcu.fileByIndex(inst_info.file);
2699 assert(file.zir_loaded);2698 const decl = file.zir.?.getDeclaration(inst_info.inst);
2700 const decl = file.zir.getDeclaration(inst_info.inst);
2701 log.debug("updateComptimeNav({s}:{d}:{d} %{d} = {})", .{2699 log.debug("updateComptimeNav({s}:{d}:{d} %{d} = {})", .{
2702 file.sub_file_path,2700 file.sub_file_path,
2703 decl.src_line + 1,2701 decl.src_line + 1,
...@@ -4097,7 +4095,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP...@@ -4097,7 +4095,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
4097 // if a newly-tracked instruction can be a type's owner `zir_index`.4095 // if a newly-tracked instruction can be a type's owner `zir_index`.
4098 comptime assert(Zir.inst_tracking_version == 0);4096 comptime assert(Zir.inst_tracking_version == 0);
40994097
4100 const decl_inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));4098 const decl_inst = file.zir.?.instructions.get(@intFromEnum(inst_info.inst));
4101 const name_strat: Zir.Inst.NameStrategy = switch (decl_inst.tag) {4099 const name_strat: Zir.Inst.NameStrategy = switch (decl_inst.tag) {
4102 .struct_init, .struct_init_ref, .struct_init_anon => .anon,4100 .struct_init, .struct_init_ref, .struct_init_anon => .anon,
4103 .extended => switch (decl_inst.data.extended.opcode) {4101 .extended => switch (decl_inst.data.extended.opcode) {
...@@ -4301,14 +4299,13 @@ pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedI...@@ -4301,14 +4299,13 @@ pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedI
4301 const inst_info = zir_index.resolveFull(ip).?;4299 const inst_info = zir_index.resolveFull(ip).?;
4302 assert(inst_info.inst != .main_struct_inst);4300 assert(inst_info.inst != .main_struct_inst);
4303 const file = zcu.fileByIndex(inst_info.file);4301 const file = zcu.fileByIndex(inst_info.file);
4304 assert(file.zir_loaded);4302 const decl = file.zir.?.getDeclaration(inst_info.inst);
4305 const decl = file.zir.getDeclaration(inst_info.inst);
4306 log.debug("updateLineNumber({s}:{d}:{d} %{d} = {s})", .{4303 log.debug("updateLineNumber({s}:{d}:{d} %{d} = {s})", .{
4307 file.sub_file_path,4304 file.sub_file_path,
4308 decl.src_line + 1,4305 decl.src_line + 1,
4309 decl.src_column + 1,4306 decl.src_column + 1,
4310 @intFromEnum(inst_info.inst),4307 @intFromEnum(inst_info.inst),
4311 file.zir.nullTerminatedString(decl.name),4308 file.zir.?.nullTerminatedString(decl.name),
4312 });4309 });
43134310
4314 var line_buf: [4]u8 = undefined;4311 var line_buf: [4]u8 = undefined;
...@@ -4661,7 +4658,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -4661,7 +4658,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
4661 .target_unit = StringSection.unit,4658 .target_unit = StringSection.unit,
4662 .target_entry = (try dwarf.debug_line_str.addString(4659 .target_entry = (try dwarf.debug_line_str.addString(
4663 dwarf,4660 dwarf,
4664 if (file.mod.builtin_file == file) file.source else "",4661 if (file.mod.builtin_file == file) file.source.? else "",
4665 )).toOptional(),4662 )).toOptional(),
4666 });4663 });
4667 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());4664 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
src/main.zig+49-66
...@@ -3636,7 +3636,7 @@ fn buildOutputType(...@@ -3636,7 +3636,7 @@ fn buildOutputType(
36363636
3637 if (show_builtin) {3637 if (show_builtin) {
3638 const builtin_mod = comp.root_mod.getBuiltinDependency();3638 const builtin_mod = comp.root_mod.getBuiltinDependency();
3639 const source = builtin_mod.builtin_file.?.source;3639 const source = builtin_mod.builtin_file.?.source.?;
3640 return std.io.getStdOut().writeAll(source);3640 return std.io.getStdOut().writeAll(source);
3641 }3641 }
3642 switch (listen) {3642 switch (listen) {
...@@ -6134,15 +6134,12 @@ fn cmdAstCheck(...@@ -6134,15 +6134,12 @@ fn cmdAstCheck(
61346134
6135 var file: Zcu.File = .{6135 var file: Zcu.File = .{
6136 .status = .never_loaded,6136 .status = .never_loaded,
6137 .prev_status = .never_loaded,
6138 .source_loaded = false,
6139 .tree_loaded = false,
6140 .zir_loaded = false,
6141 .sub_file_path = undefined,6137 .sub_file_path = undefined,
6142 .source = undefined,
6143 .stat = undefined,6138 .stat = undefined,
6144 .tree = undefined,6139 .source = null,
6145 .zir = undefined,6140 .tree = null,
6141 .zir = null,
6142 .zoir = null,
6146 .mod = undefined,6143 .mod = undefined,
6147 };6144 };
6148 if (zig_source_file) |file_name| {6145 if (zig_source_file) |file_name| {
...@@ -6163,7 +6160,6 @@ fn cmdAstCheck(...@@ -6163,7 +6160,6 @@ fn cmdAstCheck(
61636160
6164 file.sub_file_path = file_name;6161 file.sub_file_path = file_name;
6165 file.source = source;6162 file.source = source;
6166 file.source_loaded = true;
6167 file.stat = .{6163 file.stat = .{
6168 .size = stat.size,6164 .size = stat.size,
6169 .inode = stat.inode,6165 .inode = stat.inode,
...@@ -6176,7 +6172,6 @@ fn cmdAstCheck(...@@ -6176,7 +6172,6 @@ fn cmdAstCheck(
6176 };6172 };
6177 file.sub_file_path = "<stdin>";6173 file.sub_file_path = "<stdin>";
6178 file.source = source;6174 file.source = source;
6179 file.source_loaded = true;
6180 file.stat.size = source.len;6175 file.stat.size = source.len;
6181 }6176 }
61826177
...@@ -6196,17 +6191,15 @@ fn cmdAstCheck(...@@ -6196,17 +6191,15 @@ fn cmdAstCheck(
6196 .fully_qualified_name = "root",6191 .fully_qualified_name = "root",
6197 });6192 });
61986193
6199 file.tree = try Ast.parse(gpa, file.source, mode);6194 file.tree = try Ast.parse(gpa, file.source.?, mode);
6200 file.tree_loaded = true;6195 defer file.tree.?.deinit(gpa);
6201 defer file.tree.deinit(gpa);
62026196
6203 switch (mode) {6197 switch (mode) {
6204 .zig => {6198 .zig => {
6205 file.zir = try AstGen.generate(gpa, file.tree);6199 file.zir = try AstGen.generate(gpa, file.tree.?);
6206 file.zir_loaded = true;6200 defer file.zir.?.deinit(gpa);
6207 defer file.zir.deinit(gpa);
62086201
6209 if (file.zir.hasCompileErrors()) {6202 if (file.zir.?.hasCompileErrors()) {
6210 var wip_errors: std.zig.ErrorBundle.Wip = undefined;6203 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
6211 try wip_errors.init(gpa);6204 try wip_errors.init(gpa);
6212 defer wip_errors.deinit();6205 defer wip_errors.deinit();
...@@ -6215,13 +6208,13 @@ fn cmdAstCheck(...@@ -6215,13 +6208,13 @@ fn cmdAstCheck(
6215 defer error_bundle.deinit(gpa);6208 defer error_bundle.deinit(gpa);
6216 error_bundle.renderToStdErr(color.renderOptions());6209 error_bundle.renderToStdErr(color.renderOptions());
62176210
6218 if (file.zir.loweringFailed()) {6211 if (file.zir.?.loweringFailed()) {
6219 process.exit(1);6212 process.exit(1);
6220 }6213 }
6221 }6214 }
62226215
6223 if (!want_output_text) {6216 if (!want_output_text) {
6224 if (file.zir.hasCompileErrors()) {6217 if (file.zir.?.hasCompileErrors()) {
6225 process.exit(1);6218 process.exit(1);
6226 } else {6219 } else {
6227 return cleanExit();6220 return cleanExit();
...@@ -6233,18 +6226,18 @@ fn cmdAstCheck(...@@ -6233,18 +6226,18 @@ fn cmdAstCheck(
62336226
6234 {6227 {
6235 const token_bytes = @sizeOf(Ast.TokenList) +6228 const token_bytes = @sizeOf(Ast.TokenList) +
6236 file.tree.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(Ast.ByteOffset));6229 file.tree.?.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(Ast.ByteOffset));
6237 const tree_bytes = @sizeOf(Ast) + file.tree.nodes.len *6230 const tree_bytes = @sizeOf(Ast) + file.tree.?.nodes.len *
6238 (@sizeOf(Ast.Node.Tag) +6231 (@sizeOf(Ast.Node.Tag) +
6239 @sizeOf(Ast.Node.Data) +6232 @sizeOf(Ast.Node.Data) +
6240 @sizeOf(Ast.TokenIndex));6233 @sizeOf(Ast.TokenIndex));
6241 const instruction_bytes = file.zir.instructions.len *6234 const instruction_bytes = file.zir.?.instructions.len *
6242 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include6235 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include
6243 // the debug safety tag but we want to measure release size.6236 // the debug safety tag but we want to measure release size.
6244 (@sizeOf(Zir.Inst.Tag) + 8);6237 (@sizeOf(Zir.Inst.Tag) + 8);
6245 const extra_bytes = file.zir.extra.len * @sizeOf(u32);6238 const extra_bytes = file.zir.?.extra.len * @sizeOf(u32);
6246 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +6239 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +
6247 file.zir.string_bytes.len * @sizeOf(u8);6240 file.zir.?.string_bytes.len * @sizeOf(u8);
6248 const stdout = io.getStdOut();6241 const stdout = io.getStdOut();
6249 const fmtIntSizeBin = std.fmt.fmtIntSizeBin;6242 const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
6250 // zig fmt: off6243 // zig fmt: off
...@@ -6258,27 +6251,27 @@ fn cmdAstCheck(...@@ -6258,27 +6251,27 @@ fn cmdAstCheck(
6258 \\# Extra Data Items: {d} ({})6251 \\# Extra Data Items: {d} ({})
6259 \\6252 \\
6260 , .{6253 , .{
6261 fmtIntSizeBin(file.source.len),6254 fmtIntSizeBin(file.source.?.len),
6262 file.tree.tokens.len, fmtIntSizeBin(token_bytes),6255 file.tree.?.tokens.len, fmtIntSizeBin(token_bytes),
6263 file.tree.nodes.len, fmtIntSizeBin(tree_bytes),6256 file.tree.?.nodes.len, fmtIntSizeBin(tree_bytes),
6264 fmtIntSizeBin(total_bytes),6257 fmtIntSizeBin(total_bytes),
6265 file.zir.instructions.len, fmtIntSizeBin(instruction_bytes),6258 file.zir.?.instructions.len, fmtIntSizeBin(instruction_bytes),
6266 fmtIntSizeBin(file.zir.string_bytes.len),6259 fmtIntSizeBin(file.zir.?.string_bytes.len),
6267 file.zir.extra.len, fmtIntSizeBin(extra_bytes),6260 file.zir.?.extra.len, fmtIntSizeBin(extra_bytes),
6268 });6261 });
6269 // zig fmt: on6262 // zig fmt: on
6270 }6263 }
62716264
6272 try @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut());6265 try @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut());
62736266
6274 if (file.zir.hasCompileErrors()) {6267 if (file.zir.?.hasCompileErrors()) {
6275 process.exit(1);6268 process.exit(1);
6276 } else {6269 } else {
6277 return cleanExit();6270 return cleanExit();
6278 }6271 }
6279 },6272 },
6280 .zon => {6273 .zon => {
6281 const zoir = try ZonGen.generate(gpa, file.tree, .{});6274 const zoir = try ZonGen.generate(gpa, file.tree.?, .{});
6282 defer zoir.deinit(gpa);6275 defer zoir.deinit(gpa);
62836276
6284 if (zoir.hasCompileErrors()) {6277 if (zoir.hasCompileErrors()) {
...@@ -6289,7 +6282,7 @@ fn cmdAstCheck(...@@ -6289,7 +6282,7 @@ fn cmdAstCheck(
6289 {6282 {
6290 const src_path = try file.fullPath(gpa);6283 const src_path = try file.fullPath(gpa);
6291 defer gpa.free(src_path);6284 defer gpa.free(src_path);
6292 try wip_errors.addZoirErrorMessages(zoir, file.tree, file.source, src_path);6285 try wip_errors.addZoirErrorMessages(zoir, file.tree.?, file.source.?, src_path);
6293 }6286 }
62946287
6295 var error_bundle = try wip_errors.toOwnedBundle("");6288 var error_bundle = try wip_errors.toOwnedBundle("");
...@@ -6518,27 +6511,24 @@ fn cmdDumpZir(...@@ -6518,27 +6511,24 @@ fn cmdDumpZir(
65186511
6519 var file: Zcu.File = .{6512 var file: Zcu.File = .{
6520 .status = .never_loaded,6513 .status = .never_loaded,
6521 .prev_status = .never_loaded,
6522 .source_loaded = false,
6523 .tree_loaded = false,
6524 .zir_loaded = true,
6525 .sub_file_path = undefined,6514 .sub_file_path = undefined,
6526 .source = undefined,
6527 .stat = undefined,6515 .stat = undefined,
6528 .tree = undefined,6516 .source = null,
6517 .tree = null,
6529 .zir = try Zcu.loadZirCache(gpa, f),6518 .zir = try Zcu.loadZirCache(gpa, f),
6519 .zoir = null,
6530 .mod = undefined,6520 .mod = undefined,
6531 };6521 };
6532 defer file.zir.deinit(gpa);6522 defer file.zir.?.deinit(gpa);
65336523
6534 {6524 {
6535 const instruction_bytes = file.zir.instructions.len *6525 const instruction_bytes = file.zir.?.instructions.len *
6536 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include6526 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include
6537 // the debug safety tag but we want to measure release size.6527 // the debug safety tag but we want to measure release size.
6538 (@sizeOf(Zir.Inst.Tag) + 8);6528 (@sizeOf(Zir.Inst.Tag) + 8);
6539 const extra_bytes = file.zir.extra.len * @sizeOf(u32);6529 const extra_bytes = file.zir.?.extra.len * @sizeOf(u32);
6540 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +6530 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +
6541 file.zir.string_bytes.len * @sizeOf(u8);6531 file.zir.?.string_bytes.len * @sizeOf(u8);
6542 const stdout = io.getStdOut();6532 const stdout = io.getStdOut();
6543 const fmtIntSizeBin = std.fmt.fmtIntSizeBin;6533 const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
6544 // zig fmt: off6534 // zig fmt: off
...@@ -6550,9 +6540,9 @@ fn cmdDumpZir(...@@ -6550,9 +6540,9 @@ fn cmdDumpZir(
6550 \\6540 \\
6551 , .{6541 , .{
6552 fmtIntSizeBin(total_bytes),6542 fmtIntSizeBin(total_bytes),
6553 file.zir.instructions.len, fmtIntSizeBin(instruction_bytes),6543 file.zir.?.instructions.len, fmtIntSizeBin(instruction_bytes),
6554 fmtIntSizeBin(file.zir.string_bytes.len),6544 fmtIntSizeBin(file.zir.?.string_bytes.len),
6555 file.zir.extra.len, fmtIntSizeBin(extra_bytes),6545 file.zir.?.extra.len, fmtIntSizeBin(extra_bytes),
6556 });6546 });
6557 // zig fmt: on6547 // zig fmt: on
6558 }6548 }
...@@ -6586,19 +6576,16 @@ fn cmdChangelist(...@@ -6586,19 +6576,16 @@ fn cmdChangelist(
65866576
6587 var file: Zcu.File = .{6577 var file: Zcu.File = .{
6588 .status = .never_loaded,6578 .status = .never_loaded,
6589 .prev_status = .never_loaded,
6590 .source_loaded = false,
6591 .tree_loaded = false,
6592 .zir_loaded = false,
6593 .sub_file_path = old_source_file,6579 .sub_file_path = old_source_file,
6594 .source = undefined,
6595 .stat = .{6580 .stat = .{
6596 .size = stat.size,6581 .size = stat.size,
6597 .inode = stat.inode,6582 .inode = stat.inode,
6598 .mtime = stat.mtime,6583 .mtime = stat.mtime,
6599 },6584 },
6600 .tree = undefined,6585 .source = null,
6601 .zir = undefined,6586 .tree = null,
6587 .zir = null,
6588 .zoir = null,
6602 .mod = undefined,6589 .mod = undefined,
6603 };6590 };
66046591
...@@ -6613,17 +6600,14 @@ fn cmdChangelist(...@@ -6613,17 +6600,14 @@ fn cmdChangelist(
6613 if (amt != stat.size)6600 if (amt != stat.size)
6614 return error.UnexpectedEndOfFile;6601 return error.UnexpectedEndOfFile;
6615 file.source = source;6602 file.source = source;
6616 file.source_loaded = true;
66176603
6618 file.tree = try Ast.parse(gpa, file.source, .zig);6604 file.tree = try Ast.parse(gpa, file.source.?, .zig);
6619 file.tree_loaded = true;6605 defer file.tree.?.deinit(gpa);
6620 defer file.tree.deinit(gpa);
66216606
6622 file.zir = try AstGen.generate(gpa, file.tree);6607 file.zir = try AstGen.generate(gpa, file.tree.?);
6623 file.zir_loaded = true;6608 defer file.zir.?.deinit(gpa);
6624 defer file.zir.deinit(gpa);
66256609
6626 if (file.zir.loweringFailed()) {6610 if (file.zir.?.loweringFailed()) {
6627 var wip_errors: std.zig.ErrorBundle.Wip = undefined;6611 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
6628 try wip_errors.init(gpa);6612 try wip_errors.init(gpa);
6629 defer wip_errors.deinit();6613 defer wip_errors.deinit();
...@@ -6652,13 +6636,12 @@ fn cmdChangelist(...@@ -6652,13 +6636,12 @@ fn cmdChangelist(
6652 var new_tree = try Ast.parse(gpa, new_source, .zig);6636 var new_tree = try Ast.parse(gpa, new_source, .zig);
6653 defer new_tree.deinit(gpa);6637 defer new_tree.deinit(gpa);
66546638
6655 var old_zir = file.zir;6639 var old_zir = file.zir.?;
6656 defer old_zir.deinit(gpa);6640 defer old_zir.deinit(gpa);
6657 file.zir_loaded = false;6641 file.zir = null;
6658 file.zir = try AstGen.generate(gpa, new_tree);6642 file.zir = try AstGen.generate(gpa, new_tree);
6659 file.zir_loaded = true;
66606643
6661 if (file.zir.loweringFailed()) {6644 if (file.zir.?.loweringFailed()) {
6662 var wip_errors: std.zig.ErrorBundle.Wip = undefined;6645 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
6663 try wip_errors.init(gpa);6646 try wip_errors.init(gpa);
6664 defer wip_errors.deinit();6647 defer wip_errors.deinit();
...@@ -6672,7 +6655,7 @@ fn cmdChangelist(...@@ -6672,7 +6655,7 @@ fn cmdChangelist(
6672 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty;6655 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty;
6673 defer inst_map.deinit(gpa);6656 defer inst_map.deinit(gpa);
66746657
6675 try Zcu.mapOldZirToNew(gpa, old_zir, file.zir, &inst_map);6658 try Zcu.mapOldZirToNew(gpa, old_zir, file.zir.?, &inst_map);
66766659
6677 var bw = io.bufferedWriter(io.getStdOut().writer());6660 var bw = io.bufferedWriter(io.getStdOut().writer());
6678 const stdout = bw.writer();6661 const stdout = bw.writer();
src/print_zir.zig+10-13
...@@ -22,7 +22,7 @@ pub fn renderAsTextToFile(...@@ -22,7 +22,7 @@ pub fn renderAsTextToFile(
22 .gpa = gpa,22 .gpa = gpa,
23 .arena = arena.allocator(),23 .arena = arena.allocator(),
24 .file = scope_file,24 .file = scope_file,
25 .code = scope_file.zir,25 .code = scope_file.zir.?,
26 .indent = 0,26 .indent = 0,
27 .parent_decl_node = 0,27 .parent_decl_node = 0,
28 .recurse_decls = true,28 .recurse_decls = true,
...@@ -36,18 +36,18 @@ pub fn renderAsTextToFile(...@@ -36,18 +36,18 @@ pub fn renderAsTextToFile(
36 try stream.print("%{d} ", .{@intFromEnum(main_struct_inst)});36 try stream.print("%{d} ", .{@intFromEnum(main_struct_inst)});
37 try writer.writeInstToStream(stream, main_struct_inst);37 try writer.writeInstToStream(stream, main_struct_inst);
38 try stream.writeAll("\n");38 try stream.writeAll("\n");
39 const imports_index = scope_file.zir.extra[@intFromEnum(Zir.ExtraIndex.imports)];39 const imports_index = scope_file.zir.?.extra[@intFromEnum(Zir.ExtraIndex.imports)];
40 if (imports_index != 0) {40 if (imports_index != 0) {
41 try stream.writeAll("Imports:\n");41 try stream.writeAll("Imports:\n");
4242
43 const extra = scope_file.zir.extraData(Zir.Inst.Imports, imports_index);43 const extra = scope_file.zir.?.extraData(Zir.Inst.Imports, imports_index);
44 var extra_index = extra.end;44 var extra_index = extra.end;
4545
46 for (0..extra.data.imports_len) |_| {46 for (0..extra.data.imports_len) |_| {
47 const item = scope_file.zir.extraData(Zir.Inst.Imports.Item, extra_index);47 const item = scope_file.zir.?.extraData(Zir.Inst.Imports.Item, extra_index);
48 extra_index = item.end;48 extra_index = item.end;
4949
50 const import_path = scope_file.zir.nullTerminatedString(item.data.name);50 const import_path = scope_file.zir.?.nullTerminatedString(item.data.name);
51 try stream.print(" @import(\"{}\") ", .{51 try stream.print(" @import(\"{}\") ", .{
52 std.zig.fmtEscapes(import_path),52 std.zig.fmtEscapes(import_path),
53 });53 });
...@@ -75,7 +75,7 @@ pub fn renderInstructionContext(...@@ -75,7 +75,7 @@ pub fn renderInstructionContext(
75 .gpa = gpa,75 .gpa = gpa,
76 .arena = arena.allocator(),76 .arena = arena.allocator(),
77 .file = scope_file,77 .file = scope_file,
78 .code = scope_file.zir,78 .code = scope_file.zir.?,
79 .indent = if (indent < 2) 2 else indent,79 .indent = if (indent < 2) 2 else indent,
80 .parent_decl_node = parent_decl_node,80 .parent_decl_node = parent_decl_node,
81 .recurse_decls = false,81 .recurse_decls = false,
...@@ -107,7 +107,7 @@ pub fn renderSingleInstruction(...@@ -107,7 +107,7 @@ pub fn renderSingleInstruction(
107 .gpa = gpa,107 .gpa = gpa,
108 .arena = arena.allocator(),108 .arena = arena.allocator(),
109 .file = scope_file,109 .file = scope_file,
110 .code = scope_file.zir,110 .code = scope_file.zir.?,
111 .indent = indent,111 .indent = indent,
112 .parent_decl_node = parent_decl_node,112 .parent_decl_node = parent_decl_node,
113 .recurse_decls = false,113 .recurse_decls = false,
...@@ -2759,8 +2759,7 @@ const Writer = struct {...@@ -2759,8 +2759,7 @@ const Writer = struct {
2759 }2759 }
27602760
2761 fn writeSrcNode(self: *Writer, stream: anytype, src_node: i32) !void {2761 fn writeSrcNode(self: *Writer, stream: anytype, src_node: i32) !void {
2762 if (!self.file.tree_loaded) return;2762 const tree = self.file.tree orelse return;
2763 const tree = self.file.tree;
2764 const abs_node = self.relativeToNodeIndex(src_node);2763 const abs_node = self.relativeToNodeIndex(src_node);
2765 const src_span = tree.nodeToSpan(abs_node);2764 const src_span = tree.nodeToSpan(abs_node);
2766 const start = self.line_col_cursor.find(tree.source, src_span.start);2765 const start = self.line_col_cursor.find(tree.source, src_span.start);
...@@ -2772,8 +2771,7 @@ const Writer = struct {...@@ -2772,8 +2771,7 @@ const Writer = struct {
2772 }2771 }
27732772
2774 fn writeSrcTok(self: *Writer, stream: anytype, src_tok: u32) !void {2773 fn writeSrcTok(self: *Writer, stream: anytype, src_tok: u32) !void {
2775 if (!self.file.tree_loaded) return;2774 const tree = self.file.tree orelse return;
2776 const tree = self.file.tree;
2777 const abs_tok = tree.firstToken(self.parent_decl_node) + src_tok;2775 const abs_tok = tree.firstToken(self.parent_decl_node) + src_tok;
2778 const span_start = tree.tokens.items(.start)[abs_tok];2776 const span_start = tree.tokens.items(.start)[abs_tok];
2779 const span_end = span_start + @as(u32, @intCast(tree.tokenSlice(abs_tok).len));2777 const span_end = span_start + @as(u32, @intCast(tree.tokenSlice(abs_tok).len));
...@@ -2786,8 +2784,7 @@ const Writer = struct {...@@ -2786,8 +2784,7 @@ const Writer = struct {
2786 }2784 }
27872785
2788 fn writeSrcTokAbs(self: *Writer, stream: anytype, src_tok: u32) !void {2786 fn writeSrcTokAbs(self: *Writer, stream: anytype, src_tok: u32) !void {
2789 if (!self.file.tree_loaded) return;2787 const tree = self.file.tree orelse return;
2790 const tree = self.file.tree;
2791 const span_start = tree.tokens.items(.start)[src_tok];2788 const span_start = tree.tokens.items(.start)[src_tok];
2792 const span_end = span_start + @as(u32, @intCast(tree.tokenSlice(src_tok).len));2789 const span_end = span_start + @as(u32, @intCast(tree.tokenSlice(src_tok).len));
2793 const start = self.line_col_cursor.find(tree.source, span_start);2790 const start = self.line_col_cursor.find(tree.source, span_start);
test/cases/compile_errors/@import_zon_bad_import.zig deleted-9
...@@ -1,9 +0,0 @@
1export fn entry() void {
2 _ = @import(
3 "bogus-does-not-exist.zon",
4 );
5}
6
7// error
8//
9// :3:9: error: unable to open 'bogus-does-not-exist.zon': FileNotFound
test/incremental/change_zon_file created+46
...@@ -0,0 +1,46 @@
1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe
4//#target=wasm32-wasi-selfhosted
5#update=initial version
6#file=main.zig
7const std = @import("std");
8const message: []const u8 = @import("message.zon");
9pub fn main() !void {
10 try std.io.getStdOut().writeAll(message);
11}
12#file=message.zon
13"Hello, World!\n"
14#expect_stdout="Hello, World!\n"
15
16#update=change ZON file contents
17#file=message.zon
18"Hello again, World!\n"
19#expect_stdout="Hello again, World!\n"
20
21#update=delete file
22#rm_file=message.zon
23#expect_error=message.zon:1:1: error: unable to load './message.zon': FileNotFound
24
25#update=remove reference to ZON file
26#file=main.zig
27const std = @import("std");
28const message: []const u8 = @import("message.zon");
29pub fn main() !void {
30 try std.io.getStdOut().writeAll("a hardcoded string\n");
31}
32#expect_error=message.zon:1:1: error: unable to load './message.zon': FileNotFound
33
34#update=recreate ZON file
35#file=message.zon
36"We're back, World!\n"
37#expect_stdout="a hardcoded string\n"
38
39#update=re-introduce reference to ZON file
40#file=main.zig
41const std = @import("std");
42const message: []const u8 = @import("message.zon");
43pub fn main() !void {
44 try std.io.getStdOut().writeAll(message);
45}
46#expect_stdout="We're back, World!\n"