From 4996c2b6a94b042d86b50eb61c9d8d98e63415af Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 7 Apr 2021 19:38:00 -0700 Subject: stage2: fix incremental compilation Decl deletion logic * `analyzeContainer` now has an `outdated_decls` set as well as `deleted_decls`. Instead of queuing up outdated Decls for re-analysis right away, they are added to this new set. When processing the `deleted_decls` set, we remove deleted Decls from the `outdated_decls` set, to avoid deleted Decl pointers from being in the work_queue. Only after processing the deleted decls do we add analyze_decl work items to the queue. * Module.deletion_set is now an `AutoArrayHashMap` rather than `ArrayList`. `declareDeclDependency` will now remove a Decl from it as appropriate. When processing the `deletion_set` in `Compilation.performAllTheWork`, it now assumes all Decl in the set are to be deleted. * Fix crash when handling parse errors. Currently we unload the `ast.Tree` if any parse errors occur. Previously the code emitted a LazySrcLoc pointing to a token index, but then when we try to resolve the token index to a byte offset to create a compile error message, the ast.Tree` would be unloaded. Now we use `LazySrcLoc.byte_abs` instead of `token_abs` so the error message can be created even with the `ast.Tree` unloaded. Together, these changes solve a crash that happened with incremental compilation when Decls were added and removed in some combinations. --- src/Compilation.zig | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src/Compilation.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index b086e513b9..6bf0e004f3 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1377,14 +1377,17 @@ pub fn update(self: *Compilation) !void { if (!use_stage1) { if (self.bin_file.options.module) |module| { - // Process the deletion set. - while (module.deletion_set.popOrNull()) |decl| { - if (decl.dependants.items().len != 0) { - decl.deletion_flag = false; - continue; - } - try module.deleteDecl(decl); + // Process the deletion set. We use a while loop here because the + // deletion set may grow as we call `deleteDecl` within this loop, + // and more unreferenced Decls are revealed. + var entry_i: usize = 0; + while (entry_i < module.deletion_set.entries.items.len) : (entry_i += 1) { + const decl = module.deletion_set.entries.items[entry_i].key; + assert(decl.deletion_flag); + assert(decl.dependants.items().len == 0); + try module.deleteDecl(decl, null); } + module.deletion_set.shrinkRetainingCapacity(0); } } -- cgit v1.2.3