aboutsummaryrefslogtreecommitdiff
path: root/src/Compilation.zig
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2024-07-04 05:00:32 +0100
committermlugg <mlugg@mlugg.co.uk>2024-07-04 21:01:42 +0100
commit0e5335aaf5e0ac646fbd46a319710019d10c2971 (patch)
treebb5a2e4184a64985f8e8788f0d11b867213aaf3b /src/Compilation.zig
parent2f0f1efa6fa50ca27a44d5f7a0c38a6cafbbfb7c (diff)
downloadzig-0e5335aaf5e0ac646fbd46a319710019d10c2971.tar.gz
zig-0e5335aaf5e0ac646fbd46a319710019d10c2971.zip
compiler: rework type resolution, fully resolve all types
I'm so sorry. This commit was just meant to be making all types fully resolve by queueing resolution at the moment of their creation. Unfortunately, a lot of dominoes ended up falling. Here's what happened: * I added a work queue job to fully resolve a type. * I realised that from here we could eliminate `Sema.types_to_resolve` if we made function codegen a separate job. This is desirable for simplicity of both spec and implementation. * This led to a new AIR traversal to detect whether any required type is unresolved. If a type in the AIR failed to resolve, then we can't run codegen. * Because full type resolution now occurs by the work queue job, a bug was exposed whereby error messages for type resolution were associated with the wrong `Decl`, resulting in duplicate error messages when the type was also resolved "by" its owner `Decl` (which really *all* resolution should be done on). * A correct fix for this requires using a different `Sema` when performing type resolution: we need a `Sema` owned by the type. Also note that this fix is necessary for incremental compilation. * This means a whole bunch of functions no longer need to take `Sema`s. * First-order effects: `resolveTypeFields`, `resolveTypeLayout`, etc * Second-order effects: `Type.abiAlignmentAdvanced`, `Value.orderAgainstZeroAdvanced`, etc The end result of this is, in short, a more correct compiler and a simpler language specification. This regressed a few error notes in the test cases, but nothing that seems worth blocking this change. Oh, also, I ripped out the old code in `test/src/Cases.zig` which introduced a dependency on `Compilation`. This dependency was problematic at best, and this code has been unused for a while. When we re-enable incremental test cases, we must rewrite their executor to use the compiler server protocol.
Diffstat (limited to 'src/Compilation.zig')
-rw-r--r--src/Compilation.zig34
1 files changed, 32 insertions, 2 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig
index b964ffd0d1..7447d589fd 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -37,6 +37,7 @@ const Cache = std.Build.Cache;
const c_codegen = @import("codegen/c.zig");
const libtsan = @import("libtsan.zig");
const Zir = std.zig.Zir;
+const Air = @import("Air.zig");
const Builtin = @import("Builtin.zig");
const LlvmObject = @import("codegen/llvm.zig").Object;
@@ -316,18 +317,29 @@ const Job = union(enum) {
codegen_decl: InternPool.DeclIndex,
/// Write the machine code for a function to the output file.
/// This will either be a non-generic `func_decl` or a `func_instance`.
- codegen_func: InternPool.Index,
+ codegen_func: struct {
+ func: InternPool.Index,
+ /// This `Air` is owned by the `Job` and allocated with `gpa`.
+ /// It must be deinited when the job is processed.
+ air: Air,
+ },
/// Render the .h file snippet for the Decl.
emit_h_decl: InternPool.DeclIndex,
/// The Decl needs to be analyzed and possibly export itself.
/// It may have already be analyzed, or it may have been determined
/// to be outdated; in this case perform semantic analysis again.
analyze_decl: InternPool.DeclIndex,
+ /// Analyze the body of a runtime function.
+ /// After analysis, a `codegen_func` job will be queued.
+ /// These must be separate jobs to ensure any needed type resolution occurs *before* codegen.
+ analyze_func: InternPool.Index,
/// The source file containing the Decl has been updated, and so the
/// Decl may need its line number information updated in the debug info.
update_line_number: InternPool.DeclIndex,
/// The main source file for the module needs to be analyzed.
analyze_mod: *Package.Module,
+ /// Fully resolve the given `struct` or `union` type.
+ resolve_type_fully: InternPool.Index,
/// one of the glibc static objects
glibc_crt_file: glibc.CRTFile,
@@ -3389,7 +3401,7 @@ pub fn performAllTheWork(
if (try zcu.findOutdatedToAnalyze()) |outdated| {
switch (outdated.unwrap()) {
.decl => |decl| try comp.work_queue.writeItem(.{ .analyze_decl = decl }),
- .func => |func| try comp.work_queue.writeItem(.{ .codegen_func = func }),
+ .func => |func| try comp.work_queue.writeItem(.{ .analyze_func = func }),
}
continue;
}
@@ -3440,6 +3452,14 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: std.Progress.Node) !vo
defer named_frame.end();
const module = comp.module.?;
+ // This call takes ownership of `func.air`.
+ try module.linkerUpdateFunc(func.func, func.air);
+ },
+ .analyze_func => |func| {
+ const named_frame = tracy.namedFrame("analyze_func");
+ defer named_frame.end();
+
+ const module = comp.module.?;
module.ensureFuncBodyAnalyzed(func) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => return,
@@ -3518,6 +3538,16 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: std.Progress.Node) !vo
try module.ensureFuncBodyAnalysisQueued(decl.val.toIntern());
}
},
+ .resolve_type_fully => |ty| {
+ const named_frame = tracy.namedFrame("resolve_type_fully");
+ defer named_frame.end();
+
+ const zcu = comp.module.?;
+ Type.fromInterned(ty).resolveFully(zcu) catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
+ error.AnalysisFail => return,
+ };
+ },
.update_line_number => |decl_index| {
const named_frame = tracy.namedFrame("update_line_number");
defer named_frame.end();