| author | |
| committer | |
| log | 3ca588bcc6d6640b7faa41a271580dd384963927 |
| tree | c47ab77e60e00f5c52a32257124d3bc6b642cf77 |
| parent | 55a2e535fdb663793b84769cb6c3a261bda3fc66 |
| signature |
The changes from a few commits earlier, where semantic analysis no
longer occurs if any Zig files failed to lower to ZIR, mean `file`
dependencies are no longer necessary! However, we now need them for ZON
files, to be invalidated whenever a ZON file changes.5 files changed, 48 insertions(+), 22 deletions(-)
src/Compilation.zig+12-4| ... | ... | @@ -2903,10 +2903,12 @@ pub fn makeBinFileWritable(comp: *Compilation) !void { |
| 2903 | 2903 | const Header = extern struct { |
| 2904 | 2904 | intern_pool: extern struct { |
| 2905 | 2905 | thread_count: u32, |
| 2906 | file_deps_len: u32, | |
| 2907 | 2906 | src_hash_deps_len: u32, |
| 2908 | 2907 | nav_val_deps_len: u32, |
| 2909 | 2908 | nav_ty_deps_len: u32, |
| 2909 | interned_deps_len: u32, | |
| 2910 | zon_file_deps_len: u32, | |
| 2911 | embed_file_deps_len: u32, | |
| 2910 | 2912 | namespace_deps_len: u32, |
| 2911 | 2913 | namespace_name_deps_len: u32, |
| 2912 | 2914 | first_dependency_len: u32, |
| ... | ... | @@ -2947,10 +2949,12 @@ pub fn saveState(comp: *Compilation) !void { |
| 2947 | 2949 | const header: Header = .{ |
| 2948 | 2950 | .intern_pool = .{ |
| 2949 | 2951 | .thread_count = @intCast(ip.locals.len), |
| 2950 | .file_deps_len = @intCast(ip.file_deps.count()), | |
| 2951 | 2952 | .src_hash_deps_len = @intCast(ip.src_hash_deps.count()), |
| 2952 | 2953 | .nav_val_deps_len = @intCast(ip.nav_val_deps.count()), |
| 2953 | 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()), | |
| 2954 | 2958 | .namespace_deps_len = @intCast(ip.namespace_deps.count()), |
| 2955 | 2959 | .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()), |
| 2956 | 2960 | .first_dependency_len = @intCast(ip.first_dependency.count()), |
| ... | ... | @@ -2975,14 +2979,18 @@ pub fn saveState(comp: *Compilation) !void { |
| 2975 | 2979 | addBuf(&bufs, mem.asBytes(&header)); |
| 2976 | 2980 | addBuf(&bufs, mem.sliceAsBytes(pt_headers.items)); |
| 2977 | 2981 | |
| 2978 | addBuf(&bufs, mem.sliceAsBytes(ip.file_deps.keys())); | |
| 2979 | addBuf(&bufs, mem.sliceAsBytes(ip.file_deps.values())); | |
| 2980 | 2982 | addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.keys())); |
| 2981 | 2983 | addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values())); |
| 2982 | 2984 | addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys())); |
| 2983 | 2985 | addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.values())); |
| 2984 | 2986 | addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.keys())); |
| 2985 | 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())); | |
| 2986 | 2994 | addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys())); |
| 2987 | 2995 | addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values())); |
| 2988 | 2996 | addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys())); |
src/InternPool.zig+8-12| ... | ... | @@ -17,13 +17,6 @@ tid_shift_31: if (single_threaded) u0 else std.math.Log2Int(u32), |
| 17 | 17 | /// Cached shift amount to put a `tid` in the top bits of a 32-bit value. |
| 18 | 18 | tid_shift_32: if (single_threaded) u0 else std.math.Log2Int(u32), |
| 19 | 19 | |
| 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 | |
| 26 | file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index), | |
| 27 | 20 | /// Dependencies on the source code hash associated with a ZIR instruction. |
| 28 | 21 | /// * For a `declaration`, this is the entire declaration body. |
| 29 | 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 | 35 | /// * a container type requiring resolution (invalidated when the type must be recreated at a new index) |
| 43 | 36 | /// Value is index into `dep_entries` of the first dependency on this interned value. |
| 44 | 37 | interned_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. | |
| 40 | zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index), | |
| 45 | 41 | /// Dependencies on an embedded file. |
| 46 | 42 | /// Introduced by `@embedFile`; invalidated when the file changes. |
| 47 | 43 | /// Value is index into `dep_entries` of the first dependency on this `Zcu.EmbedFile`. |
| ... | ... | @@ -89,11 +85,11 @@ pub const empty: InternPool = .{ |
| 89 | 85 | .tid_shift_30 = if (single_threaded) 0 else 31, |
| 90 | 86 | .tid_shift_31 = if (single_threaded) 0 else 31, |
| 91 | 87 | .tid_shift_32 = if (single_threaded) 0 else 31, |
| 92 | .file_deps = .empty, | |
| 93 | 88 | .src_hash_deps = .empty, |
| 94 | 89 | .nav_val_deps = .empty, |
| 95 | 90 | .nav_ty_deps = .empty, |
| 96 | 91 | .interned_deps = .empty, |
| 92 | .zon_file_deps = .empty, | |
| 97 | 93 | .embed_file_deps = .empty, |
| 98 | 94 | .namespace_deps = .empty, |
| 99 | 95 | .namespace_name_deps = .empty, |
| ... | ... | @@ -824,11 +820,11 @@ pub const Nav = struct { |
| 824 | 820 | }; |
| 825 | 821 | |
| 826 | 822 | pub const Dependee = union(enum) { |
| 827 | file: FileIndex, | |
| 828 | 823 | src_hash: TrackedInst.Index, |
| 829 | 824 | nav_val: Nav.Index, |
| 830 | 825 | nav_ty: Nav.Index, |
| 831 | 826 | interned: Index, |
| 827 | zon_file: FileIndex, | |
| 832 | 828 | embed_file: Zcu.EmbedFile.Index, |
| 833 | 829 | namespace: TrackedInst.Index, |
| 834 | 830 | namespace_name: NamespaceNameKey, |
| ... | ... | @@ -876,11 +872,11 @@ pub const DependencyIterator = struct { |
| 876 | 872 | |
| 877 | 873 | pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyIterator { |
| 878 | 874 | const first_entry = switch (dependee) { |
| 879 | .file => |x| ip.file_deps.get(x), | |
| 880 | 875 | .src_hash => |x| ip.src_hash_deps.get(x), |
| 881 | 876 | .nav_val => |x| ip.nav_val_deps.get(x), |
| 882 | 877 | .nav_ty => |x| ip.nav_ty_deps.get(x), |
| 883 | 878 | .interned => |x| ip.interned_deps.get(x), |
| 879 | .zon_file => |x| ip.zon_file_deps.get(x), | |
| 884 | 880 | .embed_file => |x| ip.embed_file_deps.get(x), |
| 885 | 881 | .namespace => |x| ip.namespace_deps.get(x), |
| 886 | 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 | 943 | }, |
| 948 | 944 | inline else => |dependee_payload, tag| new_index: { |
| 949 | 945 | const gop = try switch (tag) { |
| 950 | .file => ip.file_deps, | |
| 951 | 946 | .src_hash => ip.src_hash_deps, |
| 952 | 947 | .nav_val => ip.nav_val_deps, |
| 953 | 948 | .nav_ty => ip.nav_ty_deps, |
| 954 | 949 | .interned => ip.interned_deps, |
| 950 | .zon_file => ip.zon_file_deps, | |
| 955 | 951 | .embed_file => ip.embed_file_deps, |
| 956 | 952 | .namespace => ip.namespace_deps, |
| 957 | 953 | .namespace_name => ip.namespace_name_deps, |
| ... | ... | @@ -6688,11 +6684,11 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void { |
| 6688 | 6684 | pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 6689 | 6685 | if (debug_state.enable_checks) std.debug.assert(debug_state.intern_pool == null); |
| 6690 | 6686 | |
| 6691 | ip.file_deps.deinit(gpa); | |
| 6692 | 6687 | ip.src_hash_deps.deinit(gpa); |
| 6693 | 6688 | ip.nav_val_deps.deinit(gpa); |
| 6694 | 6689 | ip.nav_ty_deps.deinit(gpa); |
| 6695 | 6690 | ip.interned_deps.deinit(gpa); |
| 6691 | ip.zon_file_deps.deinit(gpa); | |
| 6696 | 6692 | ip.embed_file_deps.deinit(gpa); |
| 6697 | 6693 | ip.namespace_deps.deinit(gpa); |
| 6698 | 6694 | ip.namespace_name_deps.deinit(gpa); |
src/Sema.zig+1-2| ... | ... | @@ -6143,7 +6143,6 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr |
| 6143 | 6143 | pt.updateFile(result.file, path_digest) catch |err| |
| 6144 | 6144 | return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); |
| 6145 | 6145 | |
| 6146 | try sema.declareDependency(.{ .file = result.file_index }); | |
| 6147 | 6146 | try pt.ensureFileAnalyzed(result.file_index); |
| 6148 | 6147 | const ty = zcu.fileRootType(result.file_index); |
| 6149 | 6148 | try sema.declareDependency(.{ .interned = ty }); |
| ... | ... | @@ -13986,7 +13985,6 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13986 | 13985 | }; |
| 13987 | 13986 | switch (result.file.getMode()) { |
| 13988 | 13987 | .zig => { |
| 13989 | try sema.declareDependency(.{ .file = result.file_index }); | |
| 13990 | 13988 | try pt.ensureFileAnalyzed(result.file_index); |
| 13991 | 13989 | const ty = zcu.fileRootType(result.file_index); |
| 13992 | 13990 | try sema.declareDependency(.{ .interned = ty }); |
| ... | ... | @@ -14003,6 +14001,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 14003 | 14001 | return sema.fail(block, operand_src, "'@import' of ZON must have a known result type", .{}); |
| 14004 | 14002 | } |
| 14005 | 14003 | |
| 14004 | try sema.declareDependency(.{ .zon_file = result.file_index }); | |
| 14006 | 14005 | const interned = try LowerZon.run( |
| 14007 | 14006 | sema, |
| 14008 | 14007 | result.file, |
src/Zcu.zig+12-4| ... | ... | @@ -705,6 +705,14 @@ pub const File = struct { |
| 705 | 705 | /// field is populated with that old ZIR. |
| 706 | 706 | prev_zir: ?*Zir = null, |
| 707 | 707 | |
| 708 | /// This field serves a similar purpose to `prev_zir`, but for ZOIR. However, since we do not | |
| 709 | /// need to map old ZOIR to new ZOIR -- instead only invalidating dependencies if the ZOIR | |
| 710 | /// changed -- this field is just a simple boolean. | |
| 711 | /// | |
| 712 | /// When `zoir` is updated, this field is set to `true`. In `updateZirRefs`, if this is `true`, | |
| 713 | /// we invalidate the corresponding `zon_file` dependency, and reset it to `false`. | |
| 714 | zoir_invalidated: bool = false, | |
| 715 | ||
| 708 | 716 | /// A single reference to a file. |
| 709 | 717 | pub const Reference = union(enum) { |
| 710 | 718 | /// The file is imported directly (i.e. not as a package) with @import. |
| ... | ... | @@ -4074,10 +4082,6 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com |
| 4074 | 4082 | const zcu = data.zcu; |
| 4075 | 4083 | const ip = &zcu.intern_pool; |
| 4076 | 4084 | switch (data.dependee) { |
| 4077 | .file => |file| { | |
| 4078 | const file_path = zcu.fileByIndex(file).sub_file_path; | |
| 4079 | return writer.print("file('{s}')", .{file_path}); | |
| 4080 | }, | |
| 4081 | 4085 | .src_hash => |ti| { |
| 4082 | 4086 | const info = ti.resolveFull(ip) orelse { |
| 4083 | 4087 | return writer.writeAll("inst(<lost>)"); |
| ... | ... | @@ -4098,6 +4102,10 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com |
| 4098 | 4102 | .func => |f| return writer.print("ies('{}')", .{ip.getNav(f.owner_nav).fqn.fmt(ip)}), |
| 4099 | 4103 | else => unreachable, |
| 4100 | 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 | }, | |
| 4101 | 4109 | .embed_file => |ef_idx| { |
| 4102 | 4110 | const ef = ef_idx.get(zcu); |
| 4103 | 4111 | return writer.print("embed_file('{s}')", .{std.fs.path.fmtJoin(&.{ |
src/Zcu/PerThread.zig+15| ... | ... | @@ -145,6 +145,9 @@ pub fn updateFile( |
| 145 | 145 | file.zir = null; |
| 146 | 146 | } |
| 147 | 147 | |
| 148 | // If ZOIR is changing, then we need to invalidate dependencies on it | |
| 149 | if (file.zoir != null) file.zoir_invalidated = true; | |
| 150 | ||
| 148 | 151 | // We're going to re-load everything, so unload source, AST, ZIR, ZOIR. |
| 149 | 152 | file.unload(gpa); |
| 150 | 153 | |
| ... | ... | @@ -380,11 +383,23 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 380 | 383 | const gpa = zcu.gpa; |
| 381 | 384 | |
| 382 | 385 | // We need to visit every updated File for every TrackedInst in InternPool. |
| 386 | // This only includes Zig files; ZON files are omitted. | |
| 383 | 387 | var updated_files: std.AutoArrayHashMapUnmanaged(Zcu.File.Index, UpdatedFile) = .empty; |
| 384 | 388 | defer cleanupUpdatedFiles(gpa, &updated_files); |
| 389 | ||
| 385 | 390 | for (zcu.import_table.values()) |file_index| { |
| 386 | 391 | const file = zcu.fileByIndex(file_index); |
| 387 | 392 | assert(file.status == .success); |
| 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 | }, | |
| 402 | } | |
| 388 | 403 | const old_zir = file.prev_zir orelse continue; |
| 389 | 404 | const new_zir = file.zir.?; |
| 390 | 405 | const gop = try updated_files.getOrPut(gpa, file_index); |