authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-28 00:31:16+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-06-12 13:55:39+01:00
log424e6ac54b0f8bbfb43f24e28c71ac72169f3719
treef979f0e580e4ebff81eac779da8cb4889d57f1b1
parent4a02e080d127cc577d40f8ea5d68122ba8ac4243
signaturelock-open Commit is signed but in an unrecognized format.

compiler: minor refactors to ZCU linking

* The `codegen_nav`, `codegen_func`, `codegen_type` tasks are renamed to `link_nav`, `link_func`, and `link_type`, to more accurately reflect their purpose of sending data to the *linker*. Currently, `link_func` remains responsible for codegen; this will change in an upcoming commit. * Don't go on a pointless detour through `PerThread` when linking ZCU functions/`Nav`s; so, the `linkerUpdateNav` etc logic now lives in `link.zig`. Currently, `linkerUpdateFunc` is an exception, because it has broader responsibilities including codegen, but this will be solved in an upcoming commit.

5 files changed, 109 insertions(+), 129 deletions(-)

src/Compilation.zig+15-14
......@@ -848,17 +848,18 @@ pub const RcIncludes = enum {
848848const Job = union(enum) {
849849 /// Corresponds to the task in `link.Task`.
850850 /// Only needed for backends that haven't yet been updated to not race against Sema.
851 codegen_nav: InternPool.Nav.Index,
851 link_nav: InternPool.Nav.Index,
852852 /// Corresponds to the task in `link.Task`.
853 /// TODO: this is currently also responsible for performing codegen.
853854 /// Only needed for backends that haven't yet been updated to not race against Sema.
854 codegen_func: link.Task.CodegenFunc,
855 link_func: link.Task.CodegenFunc,
855856 /// Corresponds to the task in `link.Task`.
856857 /// Only needed for backends that haven't yet been updated to not race against Sema.
857 codegen_type: InternPool.Index,
858 link_type: InternPool.Index,
858859 update_line_number: InternPool.TrackedInst.Index,
859860 /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed.
860861 /// This may be its first time being analyzed, or it may be outdated.
861 /// If the unit is a function, a `codegen_func` job will then be queued.
862 /// If the unit is a test function, an `analyze_func` job will then be queued.
862863 analyze_comptime_unit: InternPool.AnalUnit,
863864 /// This function must be semantically analyzed.
864865 /// This may be its first time being analyzed, or it may be outdated.
......@@ -879,13 +880,13 @@ const Job = union(enum) {
879880 return switch (tag) {
880881 // Prioritize functions so that codegen can get to work on them on a
881882 // separate thread, while Sema goes back to its own work.
882 .resolve_type_fully, .analyze_func, .codegen_func => 0,
883 .resolve_type_fully, .analyze_func, .link_func => 0,
883884 else => 1,
884885 };
885886 }
886887 comptime {
887888 // Job dependencies
888 assert(stage(.resolve_type_fully) <= stage(.codegen_func));
889 assert(stage(.resolve_type_fully) <= stage(.link_func));
889890 }
890891};
891892
......@@ -4552,7 +4553,7 @@ pub fn queueJobs(comp: *Compilation, jobs: []const Job) !void {
45524553
45534554fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {
45544555 switch (job) {
4555 .codegen_nav => |nav_index| {
4556 .link_nav => |nav_index| {
45564557 const zcu = comp.zcu.?;
45574558 const nav = zcu.intern_pool.getNav(nav_index);
45584559 if (nav.analysis != null) {
......@@ -4562,16 +4563,16 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {
45624563 }
45634564 }
45644565 assert(nav.status == .fully_resolved);
4565 comp.dispatchCodegenTask(tid, .{ .codegen_nav = nav_index });
4566 comp.dispatchLinkTask(tid, .{ .link_nav = nav_index });
45664567 },
4567 .codegen_func => |func| {
4568 comp.dispatchCodegenTask(tid, .{ .codegen_func = func });
4568 .link_func => |func| {
4569 comp.dispatchLinkTask(tid, .{ .link_func = func });
45694570 },
4570 .codegen_type => |ty| {
4571 comp.dispatchCodegenTask(tid, .{ .codegen_type = ty });
4571 .link_type => |ty| {
4572 comp.dispatchLinkTask(tid, .{ .link_type = ty });
45724573 },
45734574 .update_line_number => |ti| {
4574 comp.dispatchCodegenTask(tid, .{ .update_line_number = ti });
4575 comp.dispatchLinkTask(tid, .{ .update_line_number = ti });
45754576 },
45764577 .analyze_func => |func| {
45774578 const named_frame = tracy.namedFrame("analyze_func");
......@@ -4665,7 +4666,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {
46654666
46664667/// The reason for the double-queue here is that the first queue ensures any
46674668/// resolve_type_fully tasks are complete before this dispatch function is called.
4668fn dispatchCodegenTask(comp: *Compilation, tid: usize, link_task: link.Task) void {
4669fn dispatchLinkTask(comp: *Compilation, tid: usize, link_task: link.Task) void {
46694670 if (comp.separateCodegenThreadOk()) {
46704671 comp.queueLinkTasks(&.{link_task});
46714672 } else {
src/Sema.zig+8-8
......@@ -2991,7 +2991,7 @@ fn zirStructDecl(
29912991 if (zcu.comp.config.use_llvm) break :codegen_type;
29922992 if (block.ownerModule().strip) break :codegen_type;
29932993 // This job depends on any resolve_type_fully jobs queued up before it.
2994 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
2994 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
29952995 }
29962996 try sema.declareDependency(.{ .interned = wip_ty.index });
29972997 try sema.addTypeReferenceEntry(src, wip_ty.index);
......@@ -3250,7 +3250,7 @@ fn zirEnumDecl(
32503250 if (zcu.comp.config.use_llvm) break :codegen_type;
32513251 if (block.ownerModule().strip) break :codegen_type;
32523252 // This job depends on any resolve_type_fully jobs queued up before it.
3253 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
3253 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
32543254 }
32553255 return Air.internedToRef(wip_ty.index);
32563256}
......@@ -3368,7 +3368,7 @@ fn zirUnionDecl(
33683368 if (zcu.comp.config.use_llvm) break :codegen_type;
33693369 if (block.ownerModule().strip) break :codegen_type;
33703370 // This job depends on any resolve_type_fully jobs queued up before it.
3371 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
3371 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
33723372 }
33733373 try sema.declareDependency(.{ .interned = wip_ty.index });
33743374 try sema.addTypeReferenceEntry(src, wip_ty.index);
......@@ -3455,7 +3455,7 @@ fn zirOpaqueDecl(
34553455 if (zcu.comp.config.use_llvm) break :codegen_type;
34563456 if (block.ownerModule().strip) break :codegen_type;
34573457 // This job depends on any resolve_type_fully jobs queued up before it.
3458 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
3458 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
34593459 }
34603460 try sema.addTypeReferenceEntry(src, wip_ty.index);
34613461 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
......@@ -20086,7 +20086,7 @@ fn structInitAnon(
2008620086 codegen_type: {
2008720087 if (zcu.comp.config.use_llvm) break :codegen_type;
2008820088 if (block.ownerModule().strip) break :codegen_type;
20089 try zcu.comp.queueJob(.{ .codegen_type = wip.index });
20089 try zcu.comp.queueJob(.{ .link_type = wip.index });
2009020090 }
2009120091 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
2009220092 break :ty wip.finish(ip, new_namespace_index);
......@@ -21396,7 +21396,7 @@ fn reifyEnum(
2139621396 if (zcu.comp.config.use_llvm) break :codegen_type;
2139721397 if (block.ownerModule().strip) break :codegen_type;
2139821398 // This job depends on any resolve_type_fully jobs queued up before it.
21399 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
21399 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
2140021400 }
2140121401 return Air.internedToRef(wip_ty.index);
2140221402}
......@@ -21650,7 +21650,7 @@ fn reifyUnion(
2165021650 if (zcu.comp.config.use_llvm) break :codegen_type;
2165121651 if (block.ownerModule().strip) break :codegen_type;
2165221652 // This job depends on any resolve_type_fully jobs queued up before it.
21653 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
21653 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
2165421654 }
2165521655 try sema.declareDependency(.{ .interned = wip_ty.index });
2165621656 try sema.addTypeReferenceEntry(src, wip_ty.index);
......@@ -22004,7 +22004,7 @@ fn reifyStruct(
2200422004 if (zcu.comp.config.use_llvm) break :codegen_type;
2200522005 if (block.ownerModule().strip) break :codegen_type;
2200622006 // This job depends on any resolve_type_fully jobs queued up before it.
22007 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
22007 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
2200822008 }
2200922009 try sema.declareDependency(.{ .interned = wip_ty.index });
2201022010 try sema.addTypeReferenceEntry(src, wip_ty.index);
src/Sema/LowerZon.zig+1-1
......@@ -194,7 +194,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
194194 codegen_type: {
195195 if (pt.zcu.comp.config.use_llvm) break :codegen_type;
196196 if (self.block.ownerModule().strip) break :codegen_type;
197 try pt.zcu.comp.queueJob(.{ .codegen_type = wip.index });
197 try pt.zcu.comp.queueJob(.{ .link_type = wip.index });
198198 }
199199 break :ty wip.finish(ip, new_namespace_index);
200200 },
src/Zcu/PerThread.zig+8-73
......@@ -1320,7 +1320,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
13201320 }
13211321
13221322 // This job depends on any resolve_type_fully jobs queued up before it.
1323 try zcu.comp.queueJob(.{ .codegen_nav = nav_id });
1323 try zcu.comp.queueJob(.{ .link_nav = nav_id });
13241324 }
13251325
13261326 switch (old_nav.status) {
......@@ -1716,7 +1716,7 @@ fn analyzeFuncBody(
17161716 }
17171717
17181718 // This job depends on any resolve_type_fully jobs queued up before it.
1719 try comp.queueJob(.{ .codegen_func = .{
1719 try comp.queueJob(.{ .link_func = .{
17201720 .func = func_index,
17211721 .air = air,
17221722 } });
......@@ -1880,7 +1880,7 @@ fn createFileRootStruct(
18801880 if (zcu.comp.config.use_llvm) break :codegen_type;
18811881 if (file.mod.?.strip) break :codegen_type;
18821882 // This job depends on any resolve_type_fully jobs queued up before it.
1883 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
1883 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
18841884 }
18851885 zcu.setFileRootType(file_index, wip_ty.index);
18861886 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
......@@ -3457,73 +3457,8 @@ pub fn populateTestFunctions(
34573457 zcu.codegen_prog_node = std.Progress.Node.none;
34583458 }
34593459
3460 try pt.linkerUpdateNav(nav_index);
3461 }
3462}
3463
3464pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error{OutOfMemory}!void {
3465 const zcu = pt.zcu;
3466 const comp = zcu.comp;
3467 const gpa = zcu.gpa;
3468 const ip = &zcu.intern_pool;
3469
3470 const nav = zcu.intern_pool.getNav(nav_index);
3471 const codegen_prog_node = zcu.codegen_prog_node.start(nav.fqn.toSlice(ip), 0);
3472 defer codegen_prog_node.end();
3473
3474 if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) {
3475 // The value of this nav failed to resolve. This is a transitive failure.
3476 // TODO: do we need to mark this failure anywhere? I don't think so, since compilation
3477 // will fail due to the type error anyway.
3478 } else if (comp.bin_file) |lf| {
3479 lf.updateNav(pt, nav_index) catch |err| switch (err) {
3480 error.OutOfMemory => return error.OutOfMemory,
3481 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
3482 error.Overflow, error.RelocationNotByteAligned => {
3483 try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create(
3484 gpa,
3485 zcu.navSrcLoc(nav_index),
3486 "unable to codegen: {s}",
3487 .{@errorName(err)},
3488 ));
3489 // Not a retryable failure.
3490 },
3491 };
3492 } else if (zcu.llvm_object) |llvm_object| {
3493 llvm_object.updateNav(pt, nav_index) catch |err| switch (err) {
3494 error.OutOfMemory => return error.OutOfMemory,
3495 };
3496 }
3497}
3498
3499pub fn linkerUpdateContainerType(pt: Zcu.PerThread, ty: InternPool.Index) error{OutOfMemory}!void {
3500 const zcu = pt.zcu;
3501 const gpa = zcu.gpa;
3502 const comp = zcu.comp;
3503 const ip = &zcu.intern_pool;
3504
3505 const codegen_prog_node = zcu.codegen_prog_node.start(Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), 0);
3506 defer codegen_prog_node.end();
3507
3508 if (zcu.failed_types.fetchSwapRemove(ty)) |*entry| entry.value.deinit(gpa);
3509
3510 if (!Air.typeFullyResolved(Type.fromInterned(ty), zcu)) {
3511 // This type failed to resolve. This is a transitive failure.
3512 return;
3513 }
3514
3515 if (comp.bin_file) |lf| lf.updateContainerType(pt, ty) catch |err| switch (err) {
3516 error.OutOfMemory => return error.OutOfMemory,
3517 error.TypeFailureReported => assert(zcu.failed_types.contains(ty)),
3518 };
3519}
3520
3521pub fn linkerUpdateLineNumber(pt: Zcu.PerThread, ti: InternPool.TrackedInst.Index) !void {
3522 if (pt.zcu.comp.bin_file) |lf| {
3523 lf.updateLineNumber(pt, ti) catch |err| switch (err) {
3524 error.OutOfMemory => return error.OutOfMemory,
3525 else => |e| log.err("update line number failed: {s}", .{@errorName(e)}),
3526 };
3460 // The linker thread is not running, so we actually need to dispatch this task directly.
3461 @import("../link.zig").doTask(zcu.comp, @intFromEnum(pt.tid), .{ .link_nav = nav_index });
35273462 }
35283463}
35293464
......@@ -3984,7 +3919,7 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!
39843919 const result = try pt.zcu.intern_pool.getExtern(pt.zcu.gpa, pt.tid, key);
39853920 if (result.new_nav.unwrap()) |nav| {
39863921 // This job depends on any resolve_type_fully jobs queued up before it.
3987 try pt.zcu.comp.queueJob(.{ .codegen_nav = nav });
3922 try pt.zcu.comp.queueJob(.{ .link_nav = nav });
39883923 if (pt.zcu.comp.debugIncremental()) try pt.zcu.incremental_debug_state.newNav(pt.zcu, nav);
39893924 }
39903925 return result.index;
......@@ -4132,7 +4067,7 @@ fn recreateStructType(
41324067 if (zcu.comp.config.use_llvm) break :codegen_type;
41334068 if (file.mod.?.strip) break :codegen_type;
41344069 // This job depends on any resolve_type_fully jobs queued up before it.
4135 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
4070 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
41364071 }
41374072
41384073 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
......@@ -4225,7 +4160,7 @@ fn recreateUnionType(
42254160 if (zcu.comp.config.use_llvm) break :codegen_type;
42264161 if (file.mod.?.strip) break :codegen_type;
42274162 // This job depends on any resolve_type_fully jobs queued up before it.
4228 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
4163 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
42294164 }
42304165
42314166 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
src/link.zig+77-33
......@@ -704,7 +704,7 @@ pub const File = struct {
704704 }
705705
706706 /// May be called before or after updateExports for any given Nav.
707 pub fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {
707 fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {
708708 const nav = pt.zcu.intern_pool.getNav(nav_index);
709709 assert(nav.status == .fully_resolved);
710710 switch (base.tag) {
......@@ -721,7 +721,7 @@ pub const File = struct {
721721 TypeFailureReported,
722722 };
723723
724 pub fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void {
724 fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void {
725725 switch (base.tag) {
726726 else => {},
727727 inline .elf => |tag| {
......@@ -732,6 +732,7 @@ pub const File = struct {
732732 }
733733
734734 /// May be called before or after updateExports for any given Decl.
735 /// TODO: currently `pub` because `Zcu.PerThread` is calling this.
735736 pub fn updateFunc(
736737 base: *File,
737738 pt: Zcu.PerThread,
......@@ -755,7 +756,7 @@ pub const File = struct {
755756
756757 /// On an incremental update, fixup the line number of all `Nav`s at the given `TrackedInst`, because
757758 /// its line number has changed. The ZIR instruction `ti_id` has tag `.declaration`.
758 pub fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) UpdateLineNumberError!void {
759 fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) UpdateLineNumberError!void {
759760 {
760761 const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?;
761762 const file = pt.zcu.fileByIndex(ti.file);
......@@ -1435,10 +1436,10 @@ pub const Task = union(enum) {
14351436 load_input: Input,
14361437
14371438 /// Write the constant value for a Decl to the output file.
1438 codegen_nav: InternPool.Nav.Index,
1439 link_nav: InternPool.Nav.Index,
14391440 /// Write the machine code for a function to the output file.
1440 codegen_func: CodegenFunc,
1441 codegen_type: InternPool.Index,
1441 link_func: CodegenFunc,
1442 link_type: InternPool.Index,
14421443
14431444 update_line_number: InternPool.TrackedInst.Index,
14441445
......@@ -1585,47 +1586,90 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
15851586 },
15861587 };
15871588 },
1588 .codegen_nav => |nav_index| {
1589 if (comp.remaining_prelink_tasks == 0) {
1590 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
1591 defer pt.deactivate();
1592 pt.linkerUpdateNav(nav_index) catch |err| switch (err) {
1593 error.OutOfMemory => diags.setAllocFailure(),
1594 };
1595 } else {
1589 .link_nav => |nav_index| {
1590 if (comp.remaining_prelink_tasks != 0) {
15961591 comp.link_task_queue_postponed.appendAssumeCapacity(task);
1592 return;
15971593 }
1598 },
1599 .codegen_func => |func| {
1600 if (comp.remaining_prelink_tasks == 0) {
1601 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
1602 defer pt.deactivate();
1603 var air = func.air;
1604 defer air.deinit(comp.gpa);
1605 pt.linkerUpdateFunc(func.func, &air) catch |err| switch (err) {
1594 const zcu = comp.zcu.?;
1595 const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
1596 defer pt.deactivate();
1597 if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) {
1598 // Type resolution failed in a way which affects this `Nav`. This is a transitive
1599 // failure, but it doesn't need recording, because this `Nav` semantically depends
1600 // on the failed type, so when it is changed the `Nav` will be updated.
1601 return;
1602 }
1603 if (comp.bin_file) |lf| {
1604 lf.updateNav(pt, nav_index) catch |err| switch (err) {
1605 error.OutOfMemory => diags.setAllocFailure(),
1606 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
1607 error.Overflow, error.RelocationNotByteAligned => {
1608 zcu.failed_codegen.ensureUnusedCapacity(zcu.gpa, 1) catch return diags.setAllocFailure();
1609 const msg = Zcu.ErrorMsg.create(
1610 zcu.gpa,
1611 zcu.navSrcLoc(nav_index),
1612 "unable to codegen: {s}",
1613 .{@errorName(err)},
1614 ) catch return diags.setAllocFailure();
1615 zcu.failed_codegen.putAssumeCapacityNoClobber(nav_index, msg);
1616 // Not a retryable failure.
1617 },
1618 };
1619 } else if (zcu.llvm_object) |llvm_object| {
1620 llvm_object.updateNav(pt, nav_index) catch |err| switch (err) {
16061621 error.OutOfMemory => diags.setAllocFailure(),
16071622 };
1608 } else {
1623 }
1624 },
1625 .link_func => |func| {
1626 if (comp.remaining_prelink_tasks != 0) {
16091627 comp.link_task_queue_postponed.appendAssumeCapacity(task);
1628 return;
16101629 }
1630 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
1631 defer pt.deactivate();
1632 var air = func.air;
1633 defer air.deinit(comp.gpa);
1634 pt.linkerUpdateFunc(func.func, &air) catch |err| switch (err) {
1635 error.OutOfMemory => diags.setAllocFailure(),
1636 };
16111637 },
1612 .codegen_type => |ty| {
1613 if (comp.remaining_prelink_tasks == 0) {
1614 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
1615 defer pt.deactivate();
1616 pt.linkerUpdateContainerType(ty) catch |err| switch (err) {
1638 .link_type => |ty| {
1639 if (comp.remaining_prelink_tasks != 0) {
1640 comp.link_task_queue_postponed.appendAssumeCapacity(task);
1641 return;
1642 }
1643 const zcu = comp.zcu.?;
1644 const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
1645 defer pt.deactivate();
1646 if (zcu.failed_types.fetchSwapRemove(ty)) |*entry| entry.value.deinit(zcu.gpa);
1647 if (!Air.typeFullyResolved(.fromInterned(ty), zcu)) {
1648 // Type resolution failed in a way which affects this type. This is a transitive
1649 // failure, but it doesn't need recording, because this type semantically depends
1650 // on the failed type, so when that is changed, this type will be updated.
1651 return;
1652 }
1653 if (comp.bin_file) |lf| {
1654 lf.updateContainerType(pt, ty) catch |err| switch (err) {
16171655 error.OutOfMemory => diags.setAllocFailure(),
1656 error.TypeFailureReported => assert(zcu.failed_types.contains(ty)),
16181657 };
1619 } else {
1620 comp.link_task_queue_postponed.appendAssumeCapacity(task);
16211658 }
16221659 },
16231660 .update_line_number => |ti| {
1661 if (comp.remaining_prelink_tasks != 0) {
1662 comp.link_task_queue_postponed.appendAssumeCapacity(task);
1663 return;
1664 }
16241665 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
16251666 defer pt.deactivate();
1626 pt.linkerUpdateLineNumber(ti) catch |err| switch (err) {
1627 error.OutOfMemory => diags.setAllocFailure(),
1628 };
1667 if (comp.bin_file) |lf| {
1668 lf.updateLineNumber(pt, ti) catch |err| switch (err) {
1669 error.OutOfMemory => diags.setAllocFailure(),
1670 else => |e| log.err("update line number failed: {s}", .{@errorName(e)}),
1671 };
1672 }
16291673 },
16301674 }
16311675}