aboutsummaryrefslogtreecommitdiff
path: root/src/Zcu.zig
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2025-04-20 03:43:02 +0100
committermlugg <mlugg@mlugg.co.uk>2025-04-20 18:11:53 +0100
commit8c9c24e09b8a1e1ea92a16edd654a4b27e9ecf94 (patch)
treeca9b15c23345a9ed82e0d8f25b28510583cf1b8e /src/Zcu.zig
parent6561a98a61bb54c9d6c868f788da3eaa6f48d2c3 (diff)
downloadzig-8c9c24e09b8a1e1ea92a16edd654a4b27e9ecf94.tar.gz
zig-8c9c24e09b8a1e1ea92a16edd654a4b27e9ecf94.zip
compiler: integrate `@compileLog` with incremental compilation
Compile log output is now separated based on the `AnalUnit` which perfomred the `@compileLog` call, so that we can omit the output for unreferenced ("dead") units. The units are also sorted when collecting the `ErrorBundle`, so that compile logs are always printed in a consistent order, like compile errors are. This is important not only for incremental compilation, but also for parallel analysis. Resolves: #23609
Diffstat (limited to 'src/Zcu.zig')
-rw-r--r--src/Zcu.zig86
1 files changed, 77 insertions, 9 deletions
diff --git a/src/Zcu.zig b/src/Zcu.zig
index 1486be6746..f9fbe0b652 100644
--- a/src/Zcu.zig
+++ b/src/Zcu.zig
@@ -130,18 +130,23 @@ transitive_failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .emp
/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
failed_codegen: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, *ErrorMsg) = .empty,
failed_types: std.AutoArrayHashMapUnmanaged(InternPool.Index, *ErrorMsg) = .empty,
-/// Keep track of one `@compileLog` callsite per `AnalUnit`.
-/// The value is the source location of the `@compileLog` call, convertible to a `LazySrcLoc`.
-compile_log_sources: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
+/// Keep track of `@compileLog`s per `AnalUnit`.
+/// We track the source location of the first `@compileLog` call, and all logged lines as a linked list.
+/// The list is singly linked, but we do track its tail for fast appends (optimizing many logs in one unit).
+compile_logs: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
base_node_inst: InternPool.TrackedInst.Index,
node_offset: Ast.Node.Offset,
+ first_line: CompileLogLine.Index,
+ last_line: CompileLogLine.Index,
pub fn src(self: @This()) LazySrcLoc {
return .{
.base_node_inst = self.base_node_inst,
.offset = LazySrcLoc.Offset.nodeOffset(self.node_offset),
};
}
-}) = .{},
+}) = .empty,
+compile_log_lines: std.ArrayListUnmanaged(CompileLogLine) = .empty,
+free_compile_log_lines: std.ArrayListUnmanaged(CompileLogLine.Index) = .empty,
/// Using a map here for consistency with the other fields here.
/// The ErrorMsg memory is owned by the `File`, using Module's general purpose allocator.
failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .empty,
@@ -196,8 +201,6 @@ stage1_flags: packed struct {
reserved: u2 = 0,
} = .{},
-compile_log_text: std.ArrayListUnmanaged(u8) = .empty,
-
test_functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty,
global_assembly: std.AutoArrayHashMapUnmanaged(AnalUnit, []u8) = .empty,
@@ -547,6 +550,31 @@ pub const Export = struct {
};
};
+pub const CompileLogLine = struct {
+ next: Index.Optional,
+ /// Does *not* include the trailing newline.
+ data: InternPool.NullTerminatedString,
+ pub const Index = enum(u32) {
+ _,
+ pub fn get(idx: Index, zcu: *Zcu) *CompileLogLine {
+ return &zcu.compile_log_lines.items[@intFromEnum(idx)];
+ }
+ pub fn toOptional(idx: Index) Optional {
+ return @enumFromInt(@intFromEnum(idx));
+ }
+ pub const Optional = enum(u32) {
+ none = std.math.maxInt(u32),
+ _,
+ pub fn unwrap(opt: Optional) ?Index {
+ return switch (opt) {
+ .none => null,
+ _ => @enumFromInt(@intFromEnum(opt)),
+ };
+ }
+ };
+ };
+};
+
pub const Reference = struct {
/// The `AnalUnit` whose semantic analysis was triggered by this reference.
referenced: AnalUnit,
@@ -2464,6 +2492,30 @@ pub const LazySrcLoc = struct {
.lazy = lazy.offset,
};
}
+
+ /// Used to sort error messages, so that they're printed in a consistent order.
+ /// If an error is returned, that error makes sorting impossible.
+ pub fn lessThan(lhs_lazy: LazySrcLoc, rhs_lazy: LazySrcLoc, zcu: *Zcu) !bool {
+ const lhs_src = lhs_lazy.upgradeOrLost(zcu) orelse {
+ // LHS source location lost, so should never be referenced. Just sort it to the end.
+ return false;
+ };
+ const rhs_src = rhs_lazy.upgradeOrLost(zcu) orelse {
+ // RHS source location lost, so should never be referenced. Just sort it to the end.
+ return true;
+ };
+ if (lhs_src.file_scope != rhs_src.file_scope) {
+ return std.mem.order(
+ u8,
+ lhs_src.file_scope.sub_file_path,
+ rhs_src.file_scope.sub_file_path,
+ ).compare(.lt);
+ }
+
+ const lhs_span = try lhs_src.span(zcu.gpa);
+ const rhs_span = try rhs_src.span(zcu.gpa);
+ return lhs_span.main < rhs_span.main;
+ }
};
pub const SemaError = error{ OutOfMemory, AnalysisFail };
@@ -2506,8 +2558,6 @@ pub fn deinit(zcu: *Zcu) void {
}
zcu.embed_table.deinit(gpa);
- zcu.compile_log_text.deinit(gpa);
-
zcu.local_zir_cache.handle.close();
zcu.global_zir_cache.handle.close();
@@ -2535,7 +2585,9 @@ pub fn deinit(zcu: *Zcu) void {
}
zcu.cimport_errors.deinit(gpa);
- zcu.compile_log_sources.deinit(gpa);
+ zcu.compile_logs.deinit(gpa);
+ zcu.compile_log_lines.deinit(gpa);
+ zcu.free_compile_log_lines.deinit(gpa);
zcu.all_exports.deinit(gpa);
zcu.free_exports.deinit(gpa);
@@ -3412,6 +3464,22 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
}
}
+/// Delete all compile logs performed by this `AnalUnit`.
+/// Re-analysis of the `AnalUnit` will cause logs to be rediscovered.
+pub fn deleteUnitCompileLogs(zcu: *Zcu, anal_unit: AnalUnit) void {
+ const kv = zcu.compile_logs.fetchSwapRemove(anal_unit) orelse return;
+ const gpa = zcu.gpa;
+ var opt_line_idx = kv.value.first_line.toOptional();
+ while (opt_line_idx.unwrap()) |line_idx| {
+ zcu.free_compile_log_lines.append(gpa, line_idx) catch {
+ // This space will be reused eventually, so we need not propagate this error.
+ // Just leak it for now, and let GC reclaim it later on.
+ return;
+ };
+ opt_line_idx = line_idx.get(zcu).next;
+ }
+}
+
pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void {
const gpa = zcu.gpa;