diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-07-16 10:47:42 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-16 10:47:42 -0700 |
| commit | a58ceb3d554a9565a6cc0443f6384149ae2b3145 (patch) | |
| tree | af66e289a0ae028be92389722979ed270b42ee42 /src | |
| parent | a9d544575d5bd2a939b09b8f088bee5d8ff7b0d9 (diff) | |
| parent | 7dbd2a6bb549afa6dc3c95df46f40bf144db23a6 (diff) | |
| download | zig-a58ceb3d554a9565a6cc0443f6384149ae2b3145.tar.gz zig-a58ceb3d554a9565a6cc0443f6384149ae2b3145.zip | |
Merge pull request #20646 from ziglang/fix-updateZirRefs
frontend: fix updateZirRefs
Diffstat (limited to 'src')
| -rw-r--r-- | src/Air.zig | 3 | ||||
| -rw-r--r-- | src/Compilation.zig | 9 | ||||
| -rw-r--r-- | src/InternPool.zig | 10 | ||||
| -rw-r--r-- | src/Sema.zig | 2 | ||||
| -rw-r--r-- | src/Zcu.zig | 57 | ||||
| -rw-r--r-- | src/Zcu/PerThread.zig | 264 | ||||
| -rw-r--r-- | src/main.zig | 3 |
7 files changed, 188 insertions, 160 deletions
diff --git a/src/Air.zig b/src/Air.zig index d1c6d184e6..4a442aa332 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -1,4 +1,5 @@ //! Analyzed Intermediate Representation. +//! //! This data is produced by Sema and consumed by codegen. //! Unlike ZIR where there is one instance for an entire source file, each function //! gets its own `Air` instance. @@ -12,8 +13,6 @@ const Value = @import("Value.zig"); const Type = @import("Type.zig"); const InternPool = @import("InternPool.zig"); const Zcu = @import("Zcu.zig"); -/// Deprecated. -const Module = Zcu; instructions: std.MultiArrayList(Inst).Slice, /// The meaning of this data is determined by `Inst.Tag` value. diff --git a/src/Compilation.zig b/src/Compilation.zig index 76dc42fc64..8243bc3620 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3595,7 +3595,12 @@ fn performAllTheWorkInner( } if (comp.module) |zcu| { - const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = .main }; + const pt: Zcu.PerThread = .{ .zcu = zcu, .tid = .main }; + if (comp.incremental) { + const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0); + defer update_zir_refs_node.end(); + try pt.updateZirRefs(); + } try reportMultiModuleErrors(pt); try zcu.flushRetryableFailures(); zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); @@ -4306,7 +4311,7 @@ fn workerAstGenFile( defer child_prog_node.end(); const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) }; - pt.astGenFile(file, file_index, path_digest, root_decl) catch |err| switch (err) { + pt.astGenFile(file, path_digest, root_decl) catch |err| switch (err) { error.AnalysisFail => return, else => { file.status = .retryable_failure; diff --git a/src/InternPool.zig b/src/InternPool.zig index ff748ebc62..2440ccff3b 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -283,10 +283,12 @@ pub const DependencyIterator = struct { ip: *const InternPool, next_entry: DepEntry.Index.Optional, pub fn next(it: *DependencyIterator) ?AnalUnit { - const idx = it.next_entry.unwrap() orelse return null; - const entry = it.ip.dep_entries.items[@intFromEnum(idx)]; - it.next_entry = entry.next; - return entry.depender.unwrap().?; + while (true) { + const idx = it.next_entry.unwrap() orelse return null; + const entry = it.ip.dep_entries.items[@intFromEnum(idx)]; + it.next_entry = entry.next; + if (entry.depender.unwrap()) |depender| return depender; + } } }; diff --git a/src/Sema.zig b/src/Sema.zig index d0b14434f3..63632e9f0f 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6065,7 +6065,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr const path_digest = zcu.filePathDigest(result.file_index); const root_decl = zcu.fileRootDecl(result.file_index); - pt.astGenFile(result.file, result.file_index, path_digest, root_decl) catch |err| + pt.astGenFile(result.file, path_digest, root_decl) catch |err| return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); try pt.ensureFileAnalyzed(result.file_index); diff --git a/src/Zcu.zig b/src/Zcu.zig index 36b4c95571..dbc2e5a2c4 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -1,5 +1,8 @@ -//! Compilation of all Zig source code is represented by one `Module`. -//! Each `Compilation` has exactly one or zero `Module`, depending on whether +//! Zig Compilation Unit +//! +//! Compilation of all Zig source code is represented by one `Zcu`. +//! +//! Each `Compilation` has exactly one or zero `Zcu`, depending on whether //! there is or is not any zig source code, respectively. const std = @import("std"); @@ -13,8 +16,6 @@ const BigIntMutable = std.math.big.int.Mutable; const Target = std.Target; const Ast = std.zig.Ast; -/// Deprecated, use `Zcu`. -const Module = Zcu; const Zcu = @This(); const Compilation = @import("Compilation.zig"); const Cache = std.Build.Cache; @@ -2393,7 +2394,7 @@ pub const CompileError = error{ ComptimeBreak, }; -pub fn init(mod: *Module, thread_count: usize) !void { +pub fn init(mod: *Zcu, thread_count: usize) !void { const gpa = mod.gpa; try mod.intern_pool.init(gpa, thread_count); } @@ -2487,20 +2488,20 @@ pub fn deinit(zcu: *Zcu) void { zcu.intern_pool.deinit(gpa); } -pub fn declPtr(mod: *Module, index: Decl.Index) *Decl { +pub fn declPtr(mod: *Zcu, index: Decl.Index) *Decl { return mod.intern_pool.declPtr(index); } -pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace { +pub fn namespacePtr(mod: *Zcu, index: Namespace.Index) *Namespace { return mod.intern_pool.namespacePtr(index); } -pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace { +pub fn namespacePtrUnwrap(mod: *Zcu, index: Namespace.OptionalIndex) ?*Namespace { return mod.namespacePtr(index.unwrap() orelse return null); } /// Returns true if and only if the Decl is the top level struct associated with a File. -pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { +pub fn declIsRoot(mod: *Zcu, decl_index: Decl.Index) bool { const decl = mod.declPtr(decl_index); const namespace = mod.namespacePtr(decl.src_namespace); if (namespace.parent != .none) return false; @@ -2940,7 +2941,7 @@ pub fn mapOldZirToNew( /// analyzed, and for ensuring it can exist at runtime (see /// `sema.fnHasRuntimeBits`). This function does *not* guarantee that the body /// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`. -pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index) !void { +pub fn ensureFuncBodyAnalysisQueued(mod: *Zcu, func_index: InternPool.Index) !void { const ip = &mod.intern_pool; const func = mod.funcInfo(func_index); const decl_index = func.owner_decl; @@ -3102,13 +3103,13 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit gop.value_ptr.* = @intCast(ref_idx); } -pub fn errorSetBits(mod: *Module) u16 { +pub fn errorSetBits(mod: *Zcu) u16 { if (mod.error_limit == 0) return 0; return std.math.log2_int_ceil(ErrorInt, mod.error_limit + 1); // +1 for no error } pub fn errNote( - mod: *Module, + mod: *Zcu, src_loc: LazySrcLoc, parent: *ErrorMsg, comptime format: []const u8, @@ -3138,7 +3139,7 @@ pub fn optimizeMode(zcu: *const Zcu) std.builtin.OptimizeMode { return zcu.root_mod.optimize_mode; } -fn lockAndClearFileCompileError(mod: *Module, file: *File) void { +fn lockAndClearFileCompileError(mod: *Zcu, file: *File) void { switch (file.status) { .success_zir, .retryable_failure => {}, .never_loaded, .parse_failure, .astgen_failure => { @@ -3172,7 +3173,7 @@ pub fn handleUpdateExports( }; } -pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void { +pub fn addGlobalAssembly(mod: *Zcu, decl_index: Decl.Index, source: []const u8) !void { const gop = try mod.global_assembly.getOrPut(mod.gpa, decl_index); if (gop.found_existing) { const new_value = try std.fmt.allocPrint(mod.gpa, "{s}\n{s}", .{ gop.value_ptr.*, source }); @@ -3226,7 +3227,7 @@ pub const AtomicPtrAlignmentDiagnostics = struct { // TODO this function does not take into account CPU features, which can affect // this value. Audit this! pub fn atomicPtrAlignment( - mod: *Module, + mod: *Zcu, ty: Type, diags: *AtomicPtrAlignmentDiagnostics, ) AtomicPtrAlignmentError!Alignment { @@ -3332,7 +3333,7 @@ pub fn atomicPtrAlignment( return error.BadType; } -pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File { +pub fn declFileScope(mod: *Zcu, decl_index: Decl.Index) *File { return mod.declPtr(decl_index).getFileScope(mod); } @@ -3340,7 +3341,7 @@ pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File { /// * `@TypeOf(.{})` /// * A struct which has no fields (`struct {}`). /// * Not a struct. -pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType { +pub fn typeToStruct(mod: *Zcu, ty: Type) ?InternPool.LoadedStructType { if (ty.ip_index == .none) return null; const ip = &mod.intern_pool; return switch (ip.indexToKey(ty.ip_index)) { @@ -3349,13 +3350,13 @@ pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType { }; } -pub fn typeToPackedStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType { +pub fn typeToPackedStruct(mod: *Zcu, ty: Type) ?InternPool.LoadedStructType { const s = mod.typeToStruct(ty) orelse return null; if (s.layout != .@"packed") return null; return s; } -pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.LoadedUnionType { +pub fn typeToUnion(mod: *Zcu, ty: Type) ?InternPool.LoadedUnionType { if (ty.ip_index == .none) return null; const ip = &mod.intern_pool; return switch (ip.indexToKey(ty.ip_index)) { @@ -3364,32 +3365,32 @@ pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.LoadedUnionType { }; } -pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType { +pub fn typeToFunc(mod: *Zcu, ty: Type) ?InternPool.Key.FuncType { if (ty.ip_index == .none) return null; return mod.intern_pool.indexToFuncType(ty.toIntern()); } -pub fn funcOwnerDeclPtr(mod: *Module, func_index: InternPool.Index) *Decl { +pub fn funcOwnerDeclPtr(mod: *Zcu, func_index: InternPool.Index) *Decl { return mod.declPtr(mod.funcOwnerDeclIndex(func_index)); } -pub fn funcOwnerDeclIndex(mod: *Module, func_index: InternPool.Index) Decl.Index { +pub fn funcOwnerDeclIndex(mod: *Zcu, func_index: InternPool.Index) Decl.Index { return mod.funcInfo(func_index).owner_decl; } -pub fn iesFuncIndex(mod: *const Module, ies_index: InternPool.Index) InternPool.Index { +pub fn iesFuncIndex(mod: *const Zcu, ies_index: InternPool.Index) InternPool.Index { return mod.intern_pool.iesFuncIndex(ies_index); } -pub fn funcInfo(mod: *Module, func_index: InternPool.Index) InternPool.Key.Func { +pub fn funcInfo(mod: *Zcu, func_index: InternPool.Index) InternPool.Key.Func { return mod.intern_pool.indexToKey(func_index).func; } -pub fn toEnum(mod: *Module, comptime E: type, val: Value) E { +pub fn toEnum(mod: *Zcu, comptime E: type, val: Value) E { return mod.intern_pool.toEnum(E, val.toIntern()); } -pub fn isAnytypeParam(mod: *Module, func: InternPool.Index, index: u32) bool { +pub fn isAnytypeParam(mod: *Zcu, func: InternPool.Index, index: u32) bool { const file = mod.declPtr(func.owner_decl).getFileScope(mod); const tags = file.zir.instructions.items(.tag); @@ -3404,7 +3405,7 @@ pub fn isAnytypeParam(mod: *Module, func: InternPool.Index, index: u32) bool { }; } -pub fn getParamName(mod: *Module, func_index: InternPool.Index, index: u32) [:0]const u8 { +pub fn getParamName(mod: *Zcu, func_index: InternPool.Index, index: u32) [:0]const u8 { const func = mod.funcInfo(func_index); const file = mod.declPtr(func.owner_decl).getFileScope(mod); @@ -3441,7 +3442,7 @@ pub const UnionLayout = struct { }; /// Returns the index of the active field, given the current tag value -pub fn unionTagFieldIndex(mod: *Module, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 { +pub fn unionTagFieldIndex(mod: *Zcu, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 { const ip = &mod.intern_pool; if (enum_tag.toIntern() == .none) return null; assert(ip.typeOf(enum_tag.toIntern()) == loaded_union.enum_tag_ty); diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index c3f569cc7d..d639f3c824 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -60,10 +60,6 @@ pub fn destroyFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void { pub fn astGenFile( pt: Zcu.PerThread, file: *Zcu.File, - /// This parameter is provided separately from `file` because it is not - /// safe to access `import_table` without a lock, and this index is needed - /// in the call to `updateZirRefs`. - file_index: Zcu.File.Index, path_digest: Cache.BinDigest, opt_root_decl: Zcu.Decl.OptionalIndex, ) !void { @@ -210,13 +206,18 @@ pub fn astGenFile( pt.lockAndClearFileCompileError(file); - // If the previous ZIR does not have compile errors, keep it around - // in case parsing or new ZIR fails. In case of successful ZIR update - // at the end of this function we will free it. - // We keep the previous ZIR loaded so that we can use it - // for the update next time it does not have any compile errors. This avoids - // needlessly tossing out semantic analysis work when an error is - // temporarily introduced. + // Previous ZIR is kept for two reasons: + // + // 1. In case an update to the file causes a Parse or AstGen failure, we + // need to compare two successful ZIR files in order to proceed with an + // incremental update. This avoids needlessly tossing out semantic + // analysis work when an error is temporarily introduced. + // + // 2. In order to detect updates, we need to iterate over the intern pool + // values while comparing old ZIR to new ZIR. This is better done in a + // single-threaded context, so we need to keep both versions around + // until that point in the pipeline. Previous ZIR data is freed after + // that. if (file.zir_loaded and !file.zir.hasCompileErrors()) { assert(file.prev_zir == null); const prev_zir_ptr = try gpa.create(Zir); @@ -320,14 +321,6 @@ pub fn astGenFile( return error.AnalysisFail; } - if (file.prev_zir) |prev_zir| { - try pt.updateZirRefs(file, file_index, prev_zir.*); - // No need to keep previous ZIR. - prev_zir.deinit(gpa); - gpa.destroy(prev_zir); - file.prev_zir = null; - } - if (opt_root_decl.unwrap()) |root_decl| { // The root of this file must be re-analyzed, since the file has changed. comp.mutex.lock(); @@ -338,137 +331,162 @@ pub fn astGenFile( } } -/// This is called from the AstGen thread pool, so must acquire -/// the Compilation mutex when acting on shared state. -fn updateZirRefs(pt: Zcu.PerThread, file: *Zcu.File, file_index: Zcu.File.Index, old_zir: Zir) !void { +const UpdatedFile = struct { + file_index: Zcu.File.Index, + file: *Zcu.File, + inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index), +}; + +fn cleanupUpdatedFiles(gpa: Allocator, updated_files: *std.ArrayListUnmanaged(UpdatedFile)) void { + for (updated_files.items) |*elem| elem.inst_map.deinit(gpa); + updated_files.deinit(gpa); +} + +pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { + assert(pt.tid == .main); const zcu = pt.zcu; const ip = &zcu.intern_pool; const gpa = zcu.gpa; - const new_zir = file.zir; - - var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}; - defer inst_map.deinit(gpa); - try Zcu.mapOldZirToNew(gpa, old_zir, new_zir, &inst_map); + // We need to visit every updated File for every TrackedInst in InternPool. + var updated_files: std.ArrayListUnmanaged(UpdatedFile) = .{}; + defer cleanupUpdatedFiles(gpa, &updated_files); + for (zcu.import_table.values()) |file_index| { + const file = zcu.fileByIndex(file_index); + const old_zir = file.prev_zir orelse continue; + const new_zir = file.zir; + try updated_files.append(gpa, .{ + .file_index = file_index, + .file = file, + .inst_map = .{}, + }); + const inst_map = &updated_files.items[updated_files.items.len - 1].inst_map; + try Zcu.mapOldZirToNew(gpa, old_zir.*, new_zir, inst_map); + } - const old_tag = old_zir.instructions.items(.tag); - const old_data = old_zir.instructions.items(.data); + if (updated_files.items.len == 0) + return; - // TODO: this should be done after all AstGen workers complete, to avoid - // iterating over this full set for every updated file. for (ip.locals, 0..) |*local, tid| { - local.mutate.tracked_insts.mutex.lock(); - defer local.mutate.tracked_insts.mutex.unlock(); const tracked_insts_list = local.getMutableTrackedInsts(gpa); for (tracked_insts_list.view().items(.@"0"), 0..) |*tracked_inst, tracked_inst_unwrapped_index| { - if (tracked_inst.file != file_index) continue; - const old_inst = tracked_inst.inst; - const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{ - .tid = @enumFromInt(tid), - .index = @intCast(tracked_inst_unwrapped_index), - }).wrap(ip); - tracked_inst.inst = inst_map.get(old_inst) orelse { - // Tracking failed for this instruction. Invalidate associated `src_hash` deps. - zcu.comp.mutex.lock(); - defer zcu.comp.mutex.unlock(); - log.debug("tracking failed for %{d}", .{old_inst}); - try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index }); - continue; - }; + for (updated_files.items) |updated_file| { + const file_index = updated_file.file_index; + if (tracked_inst.file != file_index) continue; + + const file = updated_file.file; + const old_zir = file.prev_zir.?.*; + const new_zir = file.zir; + const old_tag = old_zir.instructions.items(.tag); + const old_data = old_zir.instructions.items(.data); + const inst_map = &updated_file.inst_map; + + const old_inst = tracked_inst.inst; + const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{ + .tid = @enumFromInt(tid), + .index = @intCast(tracked_inst_unwrapped_index), + }).wrap(ip); + tracked_inst.inst = inst_map.get(old_inst) orelse { + // Tracking failed for this instruction. Invalidate associated `src_hash` deps. + log.debug("tracking failed for %{d}", .{old_inst}); + try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index }); + continue; + }; - if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: { - if (new_zir.getAssociatedSrcHash(tracked_inst.inst)) |new_hash| { - if (std.zig.srcHashEql(old_hash, new_hash)) { - break :hash_changed; + if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: { + if (new_zir.getAssociatedSrcHash(tracked_inst.inst)) |new_hash| { + if (std.zig.srcHashEql(old_hash, new_hash)) { + break :hash_changed; + } + log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{ + old_inst, + tracked_inst.inst, + std.fmt.fmtSliceHexLower(&old_hash), + std.fmt.fmtSliceHexLower(&new_hash), + }); } - log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{ - old_inst, - tracked_inst.inst, - std.fmt.fmtSliceHexLower(&old_hash), - std.fmt.fmtSliceHexLower(&new_hash), - }); + // The source hash associated with this instruction changed - invalidate relevant dependencies. + try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index }); } - // The source hash associated with this instruction changed - invalidate relevant dependencies. - zcu.comp.mutex.lock(); - defer zcu.comp.mutex.unlock(); - try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index }); - } - // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies. - const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) { - .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) { - .struct_decl, .union_decl, .opaque_decl, .enum_decl => true, + // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies. + const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) { + .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) { + .struct_decl, .union_decl, .opaque_decl, .enum_decl => true, + else => false, + }, else => false, - }, - else => false, - }; - if (!has_namespace) continue; - - var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{}; - defer old_names.deinit(zcu.gpa); - { - var it = old_zir.declIterator(old_inst); - while (it.next()) |decl_inst| { - const decl_name = old_zir.getDeclaration(decl_inst)[0].name; - switch (decl_name) { - .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue, - _ => if (decl_name.isNamedTest(old_zir)) continue, + }; + if (!has_namespace) continue; + + var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{}; + defer old_names.deinit(zcu.gpa); + { + var it = old_zir.declIterator(old_inst); + while (it.next()) |decl_inst| { + const decl_name = old_zir.getDeclaration(decl_inst)[0].name; + switch (decl_name) { + .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue, + _ => if (decl_name.isNamedTest(old_zir)) continue, + } + const name_zir = decl_name.toString(old_zir).?; + const name_ip = try zcu.intern_pool.getOrPutString( + zcu.gpa, + pt.tid, + old_zir.nullTerminatedString(name_zir), + .no_embedded_nulls, + ); + try old_names.put(zcu.gpa, name_ip, {}); } - const name_zir = decl_name.toString(old_zir).?; - const name_ip = try zcu.intern_pool.getOrPutString( - zcu.gpa, - pt.tid, - old_zir.nullTerminatedString(name_zir), - .no_embedded_nulls, - ); - try old_names.put(zcu.gpa, name_ip, {}); } - } - var any_change = false; - { - var it = new_zir.declIterator(tracked_inst.inst); - while (it.next()) |decl_inst| { - const decl_name = old_zir.getDeclaration(decl_inst)[0].name; - switch (decl_name) { - .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue, - _ => if (decl_name.isNamedTest(old_zir)) continue, + var any_change = false; + { + var it = new_zir.declIterator(tracked_inst.inst); + while (it.next()) |decl_inst| { + const decl_name = old_zir.getDeclaration(decl_inst)[0].name; + switch (decl_name) { + .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue, + _ => if (decl_name.isNamedTest(old_zir)) continue, + } + const name_zir = decl_name.toString(old_zir).?; + const name_ip = try zcu.intern_pool.getOrPutString( + zcu.gpa, + pt.tid, + old_zir.nullTerminatedString(name_zir), + .no_embedded_nulls, + ); + if (!old_names.swapRemove(name_ip)) continue; + // Name added + any_change = true; + try zcu.markDependeeOutdated(.{ .namespace_name = .{ + .namespace = tracked_inst_index, + .name = name_ip, + } }); } - const name_zir = decl_name.toString(old_zir).?; - const name_ip = try zcu.intern_pool.getOrPutString( - zcu.gpa, - pt.tid, - old_zir.nullTerminatedString(name_zir), - .no_embedded_nulls, - ); - if (!old_names.swapRemove(name_ip)) continue; - // Name added + } + // The only elements remaining in `old_names` now are any names which were removed. + for (old_names.keys()) |name_ip| { any_change = true; - zcu.comp.mutex.lock(); - defer zcu.comp.mutex.unlock(); try zcu.markDependeeOutdated(.{ .namespace_name = .{ .namespace = tracked_inst_index, .name = name_ip, } }); } - } - // The only elements remaining in `old_names` now are any names which were removed. - for (old_names.keys()) |name_ip| { - any_change = true; - zcu.comp.mutex.lock(); - defer zcu.comp.mutex.unlock(); - try zcu.markDependeeOutdated(.{ .namespace_name = .{ - .namespace = tracked_inst_index, - .name = name_ip, - } }); - } - if (any_change) { - zcu.comp.mutex.lock(); - defer zcu.comp.mutex.unlock(); - try zcu.markDependeeOutdated(.{ .namespace = tracked_inst_index }); + if (any_change) { + try zcu.markDependeeOutdated(.{ .namespace = tracked_inst_index }); + } } } } + + for (updated_files.items) |updated_file| { + const file = updated_file.file; + const prev_zir = file.prev_zir.?; + file.prev_zir = null; + prev_zir.deinit(gpa); + gpa.destroy(prev_zir); + } } /// Like `ensureDeclAnalyzed`, but the Decl is a file's root Decl. diff --git a/src/main.zig b/src/main.zig index 2b36c31865..a5b315c2bb 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4230,6 +4230,9 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void { }); return; } + + // Serve empty error bundle to indicate the update is done. + try s.serveErrorBundle(std.zig.ErrorBundle.empty); } fn runOrTest( |
