mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 16:24:51 +00:00
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`.
This commit is contained in:
parent
a7dd34bfc5
commit
c6842b58d4
@ -3076,15 +3076,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
||||
});
|
||||
}
|
||||
|
||||
var all_references: ?std.AutoHashMapUnmanaged(InternPool.AnalUnit, ?Zcu.ResolvedReference) = null;
|
||||
defer if (all_references) |*a| a.deinit(gpa);
|
||||
|
||||
if (comp.zcu) |zcu| {
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {
|
||||
if (error_msg) |msg| {
|
||||
try addModuleErrorMsg(zcu, &bundle, msg.*, &all_references);
|
||||
try addModuleErrorMsg(zcu, &bundle, msg.*);
|
||||
} else {
|
||||
// Must be ZIR errors. Note that this may include AST errors.
|
||||
// addZirErrorMessages asserts that the tree is loaded.
|
||||
@ -3093,7 +3090,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
||||
}
|
||||
}
|
||||
for (zcu.failed_embed_files.values()) |error_msg| {
|
||||
try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
|
||||
try addModuleErrorMsg(zcu, &bundle, error_msg.*);
|
||||
}
|
||||
{
|
||||
const SortOrder = struct {
|
||||
@ -3136,10 +3133,8 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
||||
}
|
||||
for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| {
|
||||
if (comp.incremental) {
|
||||
if (all_references == null) {
|
||||
all_references = try zcu.resolveReferences();
|
||||
}
|
||||
if (!all_references.?.contains(anal_unit)) continue;
|
||||
const refs = try zcu.resolveReferences();
|
||||
if (!refs.contains(anal_unit)) continue;
|
||||
}
|
||||
|
||||
const file_index = switch (anal_unit.unwrap()) {
|
||||
@ -3151,7 +3146,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
||||
// We'll try again once parsing succeeds.
|
||||
if (!zcu.fileByIndex(file_index).okToReportErrors()) continue;
|
||||
|
||||
try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
|
||||
try addModuleErrorMsg(zcu, &bundle, error_msg.*);
|
||||
if (zcu.cimport_errors.get(anal_unit)) |errors| {
|
||||
for (errors.getMessages()) |err_msg_index| {
|
||||
const err_msg = errors.getErrorMessage(err_msg_index);
|
||||
@ -3175,10 +3170,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
||||
}
|
||||
for (zcu.failed_codegen.keys(), zcu.failed_codegen.values()) |nav, error_msg| {
|
||||
if (!zcu.navFileScope(nav).okToReportErrors()) continue;
|
||||
try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
|
||||
try addModuleErrorMsg(zcu, &bundle, error_msg.*);
|
||||
}
|
||||
for (zcu.failed_exports.values()) |value| {
|
||||
try addModuleErrorMsg(zcu, &bundle, value.*, &all_references);
|
||||
try addModuleErrorMsg(zcu, &bundle, value.*);
|
||||
}
|
||||
|
||||
const actual_error_count = zcu.intern_pool.global_error_set.getNamesFromMainThread().len;
|
||||
@ -3252,17 +3247,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
||||
};
|
||||
}
|
||||
|
||||
try addModuleErrorMsg(zcu, &bundle, err_msg, &all_references);
|
||||
try addModuleErrorMsg(zcu, &bundle, err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (comp.zcu) |zcu| {
|
||||
if (comp.incremental and bundle.root_list.items.len == 0) {
|
||||
const should_have_error = for (zcu.transitive_failed_analysis.keys()) |failed_unit| {
|
||||
if (all_references == null) {
|
||||
all_references = try zcu.resolveReferences();
|
||||
}
|
||||
if (all_references.?.contains(failed_unit)) break true;
|
||||
const refs = try zcu.resolveReferences();
|
||||
if (refs.contains(failed_unit)) break true;
|
||||
} else false;
|
||||
if (should_have_error) {
|
||||
@panic("referenced transitive analysis errors, but none actually emitted");
|
||||
@ -3331,14 +3324,13 @@ pub const ErrorNoteHashContext = struct {
|
||||
};
|
||||
|
||||
pub fn addModuleErrorMsg(
|
||||
mod: *Zcu,
|
||||
zcu: *Zcu,
|
||||
eb: *ErrorBundle.Wip,
|
||||
module_err_msg: Zcu.ErrorMsg,
|
||||
all_references: *?std.AutoHashMapUnmanaged(InternPool.AnalUnit, ?Zcu.ResolvedReference),
|
||||
) !void {
|
||||
const gpa = eb.gpa;
|
||||
const ip = &mod.intern_pool;
|
||||
const err_src_loc = module_err_msg.src_loc.upgrade(mod);
|
||||
const ip = &zcu.intern_pool;
|
||||
const err_src_loc = module_err_msg.src_loc.upgrade(zcu);
|
||||
const err_source = err_src_loc.file_scope.getSource(gpa) catch |err| {
|
||||
const file_path = try err_src_loc.file_scope.fullPath(gpa);
|
||||
defer gpa.free(file_path);
|
||||
@ -3358,22 +3350,20 @@ pub fn addModuleErrorMsg(
|
||||
defer ref_traces.deinit(gpa);
|
||||
|
||||
if (module_err_msg.reference_trace_root.unwrap()) |rt_root| {
|
||||
if (all_references.* == null) {
|
||||
all_references.* = try mod.resolveReferences();
|
||||
}
|
||||
const all_references = try zcu.resolveReferences();
|
||||
|
||||
var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty;
|
||||
defer seen.deinit(gpa);
|
||||
|
||||
const max_references = mod.comp.reference_trace orelse Sema.default_reference_trace_len;
|
||||
const max_references = zcu.comp.reference_trace orelse Sema.default_reference_trace_len;
|
||||
|
||||
var referenced_by = rt_root;
|
||||
while (all_references.*.?.get(referenced_by)) |maybe_ref| {
|
||||
while (all_references.get(referenced_by)) |maybe_ref| {
|
||||
const ref = maybe_ref orelse break;
|
||||
const gop = try seen.getOrPut(gpa, ref.referencer);
|
||||
if (gop.found_existing) break;
|
||||
if (ref_traces.items.len < max_references) {
|
||||
const src = ref.src.upgrade(mod);
|
||||
const src = ref.src.upgrade(zcu);
|
||||
const source = try src.file_scope.getSource(gpa);
|
||||
const span = try src.span(gpa);
|
||||
const loc = std.zig.findLineColumn(source.bytes, span.main);
|
||||
@ -3385,7 +3375,7 @@ pub fn addModuleErrorMsg(
|
||||
.type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
|
||||
.none => "comptime",
|
||||
},
|
||||
.func => |f| ip.getNav(mod.funcInfo(f).owner_nav).name.toSlice(ip),
|
||||
.func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
|
||||
};
|
||||
try ref_traces.append(gpa, .{
|
||||
.decl_name = try eb.addString(name),
|
||||
@ -3435,7 +3425,7 @@ pub fn addModuleErrorMsg(
|
||||
defer notes.deinit(gpa);
|
||||
|
||||
for (module_err_msg.notes) |module_note| {
|
||||
const note_src_loc = module_note.src_loc.upgrade(mod);
|
||||
const note_src_loc = module_note.src_loc.upgrade(zcu);
|
||||
const source = try note_src_loc.file_scope.getSource(gpa);
|
||||
const span = try note_src_loc.span(gpa);
|
||||
const loc = std.zig.findLineColumn(source.bytes, span.main);
|
||||
@ -3488,13 +3478,13 @@ pub fn performAllTheWork(
|
||||
comp: *Compilation,
|
||||
main_progress_node: std.Progress.Node,
|
||||
) JobError!void {
|
||||
defer if (comp.zcu) |mod| {
|
||||
mod.sema_prog_node.end();
|
||||
mod.sema_prog_node = std.Progress.Node.none;
|
||||
mod.codegen_prog_node.end();
|
||||
mod.codegen_prog_node = std.Progress.Node.none;
|
||||
defer if (comp.zcu) |zcu| {
|
||||
zcu.sema_prog_node.end();
|
||||
zcu.sema_prog_node = std.Progress.Node.none;
|
||||
zcu.codegen_prog_node.end();
|
||||
zcu.codegen_prog_node = std.Progress.Node.none;
|
||||
|
||||
mod.generation += 1;
|
||||
zcu.generation += 1;
|
||||
};
|
||||
try comp.performAllTheWorkInner(main_progress_node);
|
||||
if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error;
|
||||
|
||||
@ -2559,10 +2559,9 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg
|
||||
const zcu = sema.pt.zcu;
|
||||
|
||||
if (build_options.enable_debug_extensions and zcu.comp.debug_compile_errors) {
|
||||
var all_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?Zcu.ResolvedReference) = null;
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
wip_errors.init(gpa) catch @panic("out of memory");
|
||||
Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*, &all_references) catch @panic("out of memory");
|
||||
Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*) catch @panic("out of memory");
|
||||
std.debug.print("compile error during Sema:\n", .{});
|
||||
var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory");
|
||||
error_bundle.renderToStdErr(.{ .ttyconf = .no_color });
|
||||
|
||||
27
src/Zcu.zig
27
src/Zcu.zig
@ -173,6 +173,10 @@ retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .empty,
|
||||
/// These are the modules which we initially queue for analysis in `Compilation.update`.
|
||||
/// `resolveReferences` will use these as the root of its reachability traversal.
|
||||
analysis_roots: std.BoundedArray(*Package.Module, 3) = .{},
|
||||
/// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and
|
||||
/// reset to `null` when any semantic analysis occurs (since this invalidates the data).
|
||||
/// Allocated into `gpa`.
|
||||
resolved_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = null,
|
||||
|
||||
stage1_flags: packed struct {
|
||||
have_winmain: bool = false,
|
||||
@ -2192,6 +2196,8 @@ pub fn deinit(zcu: *Zcu) void {
|
||||
zcu.all_type_references.deinit(gpa);
|
||||
zcu.free_type_references.deinit(gpa);
|
||||
|
||||
if (zcu.resolved_references) |*r| r.deinit(gpa);
|
||||
|
||||
zcu.intern_pool.deinit(gpa);
|
||||
}
|
||||
|
||||
@ -2760,6 +2766,8 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
|
||||
pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
zcu.clearCachedResolvedReferences();
|
||||
|
||||
unit_refs: {
|
||||
const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse break :unit_refs;
|
||||
var idx = kv.value;
|
||||
@ -2792,6 +2800,8 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
|
||||
pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void {
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
zcu.clearCachedResolvedReferences();
|
||||
|
||||
try zcu.reference_table.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
const ref_idx = zcu.free_references.popOrNull() orelse idx: {
|
||||
@ -2815,6 +2825,8 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit
|
||||
pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPool.Index, ref_src: LazySrcLoc) Allocator.Error!void {
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
zcu.clearCachedResolvedReferences();
|
||||
|
||||
try zcu.type_reference_table.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
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
|
||||
gop.value_ptr.* = @intCast(ref_idx);
|
||||
}
|
||||
|
||||
fn clearCachedResolvedReferences(zcu: *Zcu) void {
|
||||
if (zcu.resolved_references) |*r| r.deinit(zcu.gpa);
|
||||
zcu.resolved_references = null;
|
||||
}
|
||||
|
||||
pub fn errorSetBits(zcu: *const Zcu) u16 {
|
||||
if (zcu.error_limit == 0) return 0;
|
||||
return @as(u16, std.math.log2_int(ErrorInt, zcu.error_limit)) + 1;
|
||||
@ -3138,7 +3155,15 @@ pub const ResolvedReference = struct {
|
||||
/// Returns a mapping from an `AnalUnit` to where it is referenced.
|
||||
/// If the value is `null`, the `AnalUnit` is a root of analysis.
|
||||
/// If an `AnalUnit` is not in the returned map, it is unreferenced.
|
||||
pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
|
||||
/// The returned hashmap is owned by the `Zcu`, so should not be freed by the caller.
|
||||
/// This hashmap is cached, so repeated calls to this function are cheap.
|
||||
pub fn resolveReferences(zcu: *Zcu) !*const std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
|
||||
if (zcu.resolved_references == null) {
|
||||
zcu.resolved_references = try zcu.resolveReferencesInner();
|
||||
}
|
||||
return &zcu.resolved_references.?;
|
||||
}
|
||||
fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
|
||||
const gpa = zcu.gpa;
|
||||
const comp = zcu.comp;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user