authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-10-16 15:59:27+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-10-16 16:30:36+01:00
logc6842b58d488c236aca74dea82082eec365eb117
treec858fc6af4e0a3358c22e5b0f4411e54e003cb8b
parenta7dd34bfc57f4f84bb5290177f26e2d1f0bdc27e
signaturelock-open Commit is signed but in an unrecognized format.

Zcu: cache output of `resolveReferences` between calls

This not only simplifies the error bundling logic, but also improves efficiency by allowing the result to be cached between, for instance, multiple calls to `totalErrorCount`.

3 files changed, 52 insertions(+), 38 deletions(-)

src/Compilation.zig+25-35
......@@ -3076,15 +3076,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
30763076 });
30773077 }
30783078
3079 var all_references: ?std.AutoHashMapUnmanaged(InternPool.AnalUnit, ?Zcu.ResolvedReference) = null;
3080 defer if (all_references) |*a| a.deinit(gpa);
3081
30823079 if (comp.zcu) |zcu| {
30833080 const ip = &zcu.intern_pool;
30843081
30853082 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {
30863083 if (error_msg) |msg| {
3087 try addModuleErrorMsg(zcu, &bundle, msg.*, &all_references);
3084 try addModuleErrorMsg(zcu, &bundle, msg.*);
30883085 } else {
30893086 // Must be ZIR errors. Note that this may include AST errors.
30903087 // addZirErrorMessages asserts that the tree is loaded.
......@@ -3093,7 +3090,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
30933090 }
30943091 }
30953092 for (zcu.failed_embed_files.values()) |error_msg| {
3096 try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
3093 try addModuleErrorMsg(zcu, &bundle, error_msg.*);
30973094 }
30983095 {
30993096 const SortOrder = struct {
......@@ -3136,10 +3133,8 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
31363133 }
31373134 for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| {
31383135 if (comp.incremental) {
3139 if (all_references == null) {
3140 all_references = try zcu.resolveReferences();
3141 }
3142 if (!all_references.?.contains(anal_unit)) continue;
3136 const refs = try zcu.resolveReferences();
3137 if (!refs.contains(anal_unit)) continue;
31433138 }
31443139
31453140 const file_index = switch (anal_unit.unwrap()) {
......@@ -3151,7 +3146,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
31513146 // We'll try again once parsing succeeds.
31523147 if (!zcu.fileByIndex(file_index).okToReportErrors()) continue;
31533148
3154 try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
3149 try addModuleErrorMsg(zcu, &bundle, error_msg.*);
31553150 if (zcu.cimport_errors.get(anal_unit)) |errors| {
31563151 for (errors.getMessages()) |err_msg_index| {
31573152 const err_msg = errors.getErrorMessage(err_msg_index);
......@@ -3175,10 +3170,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
31753170 }
31763171 for (zcu.failed_codegen.keys(), zcu.failed_codegen.values()) |nav, error_msg| {
31773172 if (!zcu.navFileScope(nav).okToReportErrors()) continue;
3178 try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
3173 try addModuleErrorMsg(zcu, &bundle, error_msg.*);
31793174 }
31803175 for (zcu.failed_exports.values()) |value| {
3181 try addModuleErrorMsg(zcu, &bundle, value.*, &all_references);
3176 try addModuleErrorMsg(zcu, &bundle, value.*);
31823177 }
31833178
31843179 const actual_error_count = zcu.intern_pool.global_error_set.getNamesFromMainThread().len;
......@@ -3252,17 +3247,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
32523247 };
32533248 }
32543249
3255 try addModuleErrorMsg(zcu, &bundle, err_msg, &all_references);
3250 try addModuleErrorMsg(zcu, &bundle, err_msg);
32563251 }
32573252 }
32583253
32593254 if (comp.zcu) |zcu| {
32603255 if (comp.incremental and bundle.root_list.items.len == 0) {
32613256 const should_have_error = for (zcu.transitive_failed_analysis.keys()) |failed_unit| {
3262 if (all_references == null) {
3263 all_references = try zcu.resolveReferences();
3264 }
3265 if (all_references.?.contains(failed_unit)) break true;
3257 const refs = try zcu.resolveReferences();
3258 if (refs.contains(failed_unit)) break true;
32663259 } else false;
32673260 if (should_have_error) {
32683261 @panic("referenced transitive analysis errors, but none actually emitted");
......@@ -3331,14 +3324,13 @@ pub const ErrorNoteHashContext = struct {
33313324};
33323325
33333326pub fn addModuleErrorMsg(
3334 mod: *Zcu,
3327 zcu: *Zcu,
33353328 eb: *ErrorBundle.Wip,
33363329 module_err_msg: Zcu.ErrorMsg,
3337 all_references: *?std.AutoHashMapUnmanaged(InternPool.AnalUnit, ?Zcu.ResolvedReference),
33383330) !void {
33393331 const gpa = eb.gpa;
3340 const ip = &mod.intern_pool;
3341 const err_src_loc = module_err_msg.src_loc.upgrade(mod);
3332 const ip = &zcu.intern_pool;
3333 const err_src_loc = module_err_msg.src_loc.upgrade(zcu);
33423334 const err_source = err_src_loc.file_scope.getSource(gpa) catch |err| {
33433335 const file_path = try err_src_loc.file_scope.fullPath(gpa);
33443336 defer gpa.free(file_path);
......@@ -3358,22 +3350,20 @@ pub fn addModuleErrorMsg(
33583350 defer ref_traces.deinit(gpa);
33593351
33603352 if (module_err_msg.reference_trace_root.unwrap()) |rt_root| {
3361 if (all_references.* == null) {
3362 all_references.* = try mod.resolveReferences();
3363 }
3353 const all_references = try zcu.resolveReferences();
33643354
33653355 var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty;
33663356 defer seen.deinit(gpa);
33673357
3368 const max_references = mod.comp.reference_trace orelse Sema.default_reference_trace_len;
3358 const max_references = zcu.comp.reference_trace orelse Sema.default_reference_trace_len;
33693359
33703360 var referenced_by = rt_root;
3371 while (all_references.*.?.get(referenced_by)) |maybe_ref| {
3361 while (all_references.get(referenced_by)) |maybe_ref| {
33723362 const ref = maybe_ref orelse break;
33733363 const gop = try seen.getOrPut(gpa, ref.referencer);
33743364 if (gop.found_existing) break;
33753365 if (ref_traces.items.len < max_references) {
3376 const src = ref.src.upgrade(mod);
3366 const src = ref.src.upgrade(zcu);
33773367 const source = try src.file_scope.getSource(gpa);
33783368 const span = try src.span(gpa);
33793369 const loc = std.zig.findLineColumn(source.bytes, span.main);
......@@ -3385,7 +3375,7 @@ pub fn addModuleErrorMsg(
33853375 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
33863376 .none => "comptime",
33873377 },
3388 .func => |f| ip.getNav(mod.funcInfo(f).owner_nav).name.toSlice(ip),
3378 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
33893379 };
33903380 try ref_traces.append(gpa, .{
33913381 .decl_name = try eb.addString(name),
......@@ -3435,7 +3425,7 @@ pub fn addModuleErrorMsg(
34353425 defer notes.deinit(gpa);
34363426
34373427 for (module_err_msg.notes) |module_note| {
3438 const note_src_loc = module_note.src_loc.upgrade(mod);
3428 const note_src_loc = module_note.src_loc.upgrade(zcu);
34393429 const source = try note_src_loc.file_scope.getSource(gpa);
34403430 const span = try note_src_loc.span(gpa);
34413431 const loc = std.zig.findLineColumn(source.bytes, span.main);
......@@ -3488,13 +3478,13 @@ pub fn performAllTheWork(
34883478 comp: *Compilation,
34893479 main_progress_node: std.Progress.Node,
34903480) JobError!void {
3491 defer if (comp.zcu) |mod| {
3492 mod.sema_prog_node.end();
3493 mod.sema_prog_node = std.Progress.Node.none;
3494 mod.codegen_prog_node.end();
3495 mod.codegen_prog_node = std.Progress.Node.none;
3481 defer if (comp.zcu) |zcu| {
3482 zcu.sema_prog_node.end();
3483 zcu.sema_prog_node = std.Progress.Node.none;
3484 zcu.codegen_prog_node.end();
3485 zcu.codegen_prog_node = std.Progress.Node.none;
34963486
3497 mod.generation += 1;
3487 zcu.generation += 1;
34983488 };
34993489 try comp.performAllTheWorkInner(main_progress_node);
35003490 if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error;
src/Sema.zig+1-2
......@@ -2559,10 +2559,9 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg
25592559 const zcu = sema.pt.zcu;
25602560
25612561 if (build_options.enable_debug_extensions and zcu.comp.debug_compile_errors) {
2562 var all_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?Zcu.ResolvedReference) = null;
25632562 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
25642563 wip_errors.init(gpa) catch @panic("out of memory");
2565 Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*, &all_references) catch @panic("out of memory");
2564 Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*) catch @panic("out of memory");
25662565 std.debug.print("compile error during Sema:\n", .{});
25672566 var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory");
25682567 error_bundle.renderToStdErr(.{ .ttyconf = .no_color });
src/Zcu.zig+26-1
......@@ -173,6 +173,10 @@ retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .empty,
173173/// These are the modules which we initially queue for analysis in `Compilation.update`.
174174/// `resolveReferences` will use these as the root of its reachability traversal.
175175analysis_roots: std.BoundedArray(*Package.Module, 3) = .{},
176/// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and
177/// reset to `null` when any semantic analysis occurs (since this invalidates the data).
178/// Allocated into `gpa`.
179resolved_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = null,
176180
177181stage1_flags: packed struct {
178182 have_winmain: bool = false,
......@@ -2192,6 +2196,8 @@ pub fn deinit(zcu: *Zcu) void {
21922196 zcu.all_type_references.deinit(gpa);
21932197 zcu.free_type_references.deinit(gpa);
21942198
2199 if (zcu.resolved_references) |*r| r.deinit(gpa);
2200
21952201 zcu.intern_pool.deinit(gpa);
21962202}
21972203
......@@ -2760,6 +2766,8 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
27602766pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
27612767 const gpa = zcu.gpa;
27622768
2769 zcu.clearCachedResolvedReferences();
2770
27632771 unit_refs: {
27642772 const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse break :unit_refs;
27652773 var idx = kv.value;
......@@ -2792,6 +2800,8 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
27922800pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void {
27932801 const gpa = zcu.gpa;
27942802
2803 zcu.clearCachedResolvedReferences();
2804
27952805 try zcu.reference_table.ensureUnusedCapacity(gpa, 1);
27962806
27972807 const ref_idx = zcu.free_references.popOrNull() orelse idx: {
......@@ -2815,6 +2825,8 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit
28152825pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPool.Index, ref_src: LazySrcLoc) Allocator.Error!void {
28162826 const gpa = zcu.gpa;
28172827
2828 zcu.clearCachedResolvedReferences();
2829
28182830 try zcu.type_reference_table.ensureUnusedCapacity(gpa, 1);
28192831
28202832 const ref_idx = zcu.free_type_references.popOrNull() orelse idx: {
......@@ -2835,6 +2847,11 @@ pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPo
28352847 gop.value_ptr.* = @intCast(ref_idx);
28362848}
28372849
2850fn clearCachedResolvedReferences(zcu: *Zcu) void {
2851 if (zcu.resolved_references) |*r| r.deinit(zcu.gpa);
2852 zcu.resolved_references = null;
2853}
2854
28382855pub fn errorSetBits(zcu: *const Zcu) u16 {
28392856 if (zcu.error_limit == 0) return 0;
28402857 return @as(u16, std.math.log2_int(ErrorInt, zcu.error_limit)) + 1;
......@@ -3138,7 +3155,15 @@ pub const ResolvedReference = struct {
31383155/// Returns a mapping from an `AnalUnit` to where it is referenced.
31393156/// If the value is `null`, the `AnalUnit` is a root of analysis.
31403157/// If an `AnalUnit` is not in the returned map, it is unreferenced.
3141pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
3158/// The returned hashmap is owned by the `Zcu`, so should not be freed by the caller.
3159/// This hashmap is cached, so repeated calls to this function are cheap.
3160pub fn resolveReferences(zcu: *Zcu) !*const std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
3161 if (zcu.resolved_references == null) {
3162 zcu.resolved_references = try zcu.resolveReferencesInner();
3163 }
3164 return &zcu.resolved_references.?;
3165}
3166fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
31423167 const gpa = zcu.gpa;
31433168 const comp = zcu.comp;
31443169 const ip = &zcu.intern_pool;