authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-02-07 12:23:54+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:09+00:00
log03e23bcbdea2e832307085e5855ca20b51ac9d9a
tree761fe4f62155bf1873c389cb64af6337605e1076
parentc91b06ef52f31090b3c8fda9b9a419bf1391d805
signaturelock-open Commit is signed but in an unrecognized format.

resolve some of my TODOs


5 files changed, 143 insertions(+), 185 deletions(-)

src/Sema.zig+60-69
...@@ -5746,91 +5746,94 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -5746,91 +5746,94 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
5746 }5746 }
5747 }5747 }
57485748
5749 const export_ty = ptr_ty.childType(zcu);
5750 if (!export_ty.validateExtern(.other, zcu)) {
5751 return sema.failWithOwnedErrorMsg(block, msg: {
5752 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
5753 errdefer msg.destroy(sema.gpa);
5754 try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other);
5755 try sema.addDeclaredHereNote(msg, export_ty);
5756 break :msg msg;
5757 });
5758 }
5759
5749 const ptr_info = ip.indexToKey(ptr_val.toIntern()).ptr;5760 const ptr_info = ip.indexToKey(ptr_val.toIntern()).ptr;
5750 switch (ptr_info.base_addr) {5761 const target: Zcu.Exported = switch (ptr_info.base_addr) {
5751 .comptime_alloc, .int, .comptime_field => return sema.fail(block, ptr_src, "export target must be a global variable or a comptime-known constant", .{}),5762 .comptime_alloc, .int, .comptime_field => return sema.fail(block, ptr_src, "export target must be a global variable or a comptime-known constant", .{}),
5752 .eu_payload, .opt_payload, .field, .arr_elem => return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}),5763 .eu_payload, .opt_payload, .field, .arr_elem => return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}),
5753 .uav => |uav| {5764 .uav => |uav| .{ .uav = uav.val },
5754 if (ptr_info.byte_offset != 0) {5765 .nav => |orig_nav| target: {
5755 return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});5766 try sema.ensureNavResolved(block, src, orig_nav, .fully);
5756 }5767 const export_nav = switch (ip.indexToKey(ip.getNav(orig_nav).status.fully_resolved.val)) {
5757 if (zcu.llvm_object != null and options.linkage == .internal) return;5768 .variable => |v| v.owner_nav,
5758 const export_ty = Value.fromInterned(uav.val).typeOf(zcu);5769 .@"extern" => |e| e.owner_nav,
5759 if (!export_ty.validateExtern(.other, zcu)) {5770 .func => |f| f.owner_nav,
5760 return sema.failWithOwnedErrorMsg(block, msg: {5771 else => orig_nav,
5761 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});5772 };
5762 errdefer msg.destroy(sema.gpa);5773 if (ip.getNav(export_nav).getExtern(ip) != null) {
5763 try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other);5774 return sema.fail(block, src, "export target cannot be extern", .{});
5764 try sema.addDeclaredHereNote(msg, export_ty);
5765 break :msg msg;
5766 });
5767 }
5768 try sema.exports.append(zcu.gpa, .{
5769 .opts = options,
5770 .src = src,
5771 .exported = .{ .uav = uav.val },
5772 .status = .in_progress,
5773 });
5774 },
5775 .nav => |nav| {
5776 if (ptr_info.byte_offset != 0) {
5777 return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});
5778 }5775 }
5779 try sema.analyzeExport(block, src, options, nav);5776 try sema.maybeQueueFuncBodyAnalysis(block, src, export_nav);
5777 break :target .{ .nav = export_nav };
5780 },5778 },
5779 };
5780 if (ptr_info.byte_offset != 0) {
5781 return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});
5781 }5782 }
5783 if (zcu.llvm_object != null and options.linkage == .internal) return;
5784 try sema.exports.append(zcu.gpa, .{
5785 .opts = options,
5786 .src = src,
5787 .exported = target,
5788 .status = .in_progress,
5789 });
5782}5790}
57835791
5784pub fn analyzeExport(5792/// Asserts that `sema.owner` is a `.nav_val` whose value is resolved.
5793///
5794/// Exports that `Nav` by the given name with all other options set to default.
5795pub fn analyzeExportSelfNav(
5785 sema: *Sema,5796 sema: *Sema,
5786 block: *Block,5797 block: *Block,
5787 src: LazySrcLoc,5798 src: LazySrcLoc,
5788 options: Zcu.Export.Options,5799 name: InternPool.NullTerminatedString,
5789 orig_nav_index: InternPool.Nav.Index,
5790) !void {5800) !void {
5791 const gpa = sema.gpa;5801 const gpa = sema.gpa;
5792 const pt = sema.pt;5802 const pt = sema.pt;
5793 const zcu = pt.zcu;5803 const zcu = pt.zcu;
5794 const ip = &zcu.intern_pool;5804 const ip = &zcu.intern_pool;
57955805
5796 if (zcu.llvm_object != null and options.linkage == .internal)5806 const orig_nav = sema.owner.unwrap().nav_val;
5797 return;5807 const export_val: Value = .fromInterned(ip.getNav(orig_nav).status.fully_resolved.val);
57985808 const export_ty = export_val.typeOf(zcu);
5799 try sema.ensureNavResolved(block, src, orig_nav_index, .fully);
5800
5801 const exported_nav_index = switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
5802 .variable => |v| v.owner_nav,
5803 .@"extern" => |e| e.owner_nav,
5804 .func => |f| f.owner_nav,
5805 else => orig_nav_index,
5806 };
5807
5808 const exported_nav = ip.getNav(exported_nav_index);
5809 const export_ty: Type = .fromInterned(exported_nav.typeOf(ip));
58105809
5811 if (!export_ty.validateExtern(.other, zcu)) {5810 if (!export_ty.validateExtern(.other, zcu)) {
5812 return sema.failWithOwnedErrorMsg(block, msg: {5811 return sema.failWithOwnedErrorMsg(block, msg: {
5813 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});5812 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
5814 errdefer msg.destroy(gpa);5813 errdefer msg.destroy(gpa);
5815
5816 try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other);5814 try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other);
5817
5818 try sema.addDeclaredHereNote(msg, export_ty);5815 try sema.addDeclaredHereNote(msg, export_ty);
5819 break :msg msg;5816 break :msg msg;
5820 });5817 });
5821 }5818 }
58225819
5823 // TODO: some backends might support re-exporting extern decls5820 const export_nav = switch (ip.indexToKey(export_val.toIntern())) {
5824 if (exported_nav.getExtern(ip) != null) {5821 .variable => |v| v.owner_nav,
5825 return sema.fail(block, src, "export target cannot be extern", .{});5822 .@"extern" => |e| e.owner_nav,
5826 }5823 .func => |f| export_nav: {
58275824 assert(export_ty.fnHasRuntimeBits(zcu)); // otherwise `validateExtern` failed above
5828 try sema.maybeQueueFuncBodyAnalysis(block, src, exported_nav_index);5825 const orig_fn_index = ip.unwrapCoercedFunc(export_val.toIntern());
5826 try sema.addReferenceEntry(block, src, .wrap(.{ .func = orig_fn_index }));
5827 try zcu.ensureFuncBodyAnalysisQueued(orig_fn_index);
5828 break :export_nav f.owner_nav;
5829 },
5830 else => orig_nav,
5831 };
58295832
5830 try sema.exports.append(gpa, .{5833 try sema.exports.append(gpa, .{
5831 .opts = options,5834 .opts = .{ .name = name },
5832 .src = src,5835 .src = src,
5833 .exported = .{ .nav = exported_nav_index },5836 .exported = .{ .nav = export_nav },
5834 .status = .in_progress,5837 .status = .in_progress,
5835 });5838 });
5836}5839}
...@@ -33739,21 +33742,9 @@ pub fn flushExports(sema: *Sema) !void {...@@ -33739,21 +33742,9 @@ pub fn flushExports(sema: *Sema) !void {
33739 const zcu = sema.pt.zcu;33742 const zcu = sema.pt.zcu;
33740 const gpa = zcu.gpa;33743 const gpa = zcu.gpa;
3374133744
33742 // There may be existing exports. For instance, a struct may export33745 assert(!zcu.single_exports.contains(sema.owner));
33743 // things during both field type resolution and field default resolution.33746 assert(!zcu.multi_exports.contains(sema.owner));
33744 //
33745 // So, pick up and delete any existing exports. This strategy performs
33746 // redundant work, but that's okay, because this case is exceedingly rare.
33747 //
33748 // MLUGG TODO: is this still possible? if not, delete this logic and combine deleteUnitExports into resetUnit
33749 if (zcu.single_exports.get(sema.owner)) |export_idx| {
33750 try sema.exports.append(gpa, export_idx.ptr(zcu).*);
33751 } else if (zcu.multi_exports.get(sema.owner)) |info| {
33752 try sema.exports.appendSlice(gpa, zcu.all_exports.items[info.index..][0..info.len]);
33753 }
33754 zcu.deleteUnitExports(sema.owner);
3375533747
33756 // `sema.exports` is completed; store the data into the `Zcu`.
33757 if (sema.exports.items.len == 1) {33748 if (sema.exports.items.len == 1) {
33758 try zcu.single_exports.ensureUnusedCapacity(gpa, 1);33749 try zcu.single_exports.ensureUnusedCapacity(gpa, 1);
33759 const export_idx: Zcu.Export.Index = zcu.free_exports.pop() orelse idx: {33750 const export_idx: Zcu.Export.Index = zcu.free_exports.pop() orelse idx: {
...@@ -34038,7 +34029,7 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ...@@ -34038,7 +34029,7 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
34038 };34029 };
34039}34030}
3404034031
34041fn setTypeName(34032pub fn setTypeName(
34042 sema: *Sema,34033 sema: *Sema,
34043 block: *Block,34034 block: *Block,
34044 wip: *const InternPool.WipContainerType,34035 wip: *const InternPool.WipContainerType,
src/Sema/LowerZon.zig+50-62
...@@ -125,89 +125,77 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter...@@ -125,89 +125,77 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
125 return (try pt.aggregateValue(.fromInterned(ty), values)).toIntern();125 return (try pt.aggregateValue(.fromInterned(ty), values)).toIntern();
126 },126 },
127 .struct_literal => |init| {127 .struct_literal => |init| {
128 if (true) @panic("MLUGG TODO");
129 const elems = try self.sema.arena.alloc(InternPool.Index, init.names.len);128 const elems = try self.sema.arena.alloc(InternPool.Index, init.names.len);
130 for (0..init.names.len) |i| {129 for (0..init.names.len) |i| {
131 elems[i] = try self.lowerExprAnonResTy(init.vals.at(@intCast(i)));130 elems[i] = try self.lowerExprAnonResTy(init.vals.at(@intCast(i)));
132 }131 }
133 const struct_ty = switch (try ip.getStructType(132 const struct_ty: Type = switch (try ip.getReifiedStructType(gpa, io, pt.tid, .{
134 gpa,133 .zir_index = self.base_node_inst,
135 io,134 .type_hash = hash: {
136 pt.tid,135 var hasher: std.hash.Wyhash = .init(0);
137 .{136 hasher.update(std.mem.asBytes(&node));
138 .layout = .auto,137 hasher.update(std.mem.sliceAsBytes(elems));
139 .fields_len = @intCast(init.names.len),138 hasher.update(std.mem.sliceAsBytes(init.names));
140 .known_non_opv = false,139 break :hash hasher.final();
141 .requires_comptime = .no,
142 .any_comptime_fields = true,
143 .any_default_inits = true,
144 .inits_resolved = true,
145 .any_aligned_fields = false,
146 .key = .{ .reified = .{
147 .zir_index = self.base_node_inst,
148 .type_hash = hash: {
149 var hasher: std.hash.Wyhash = .init(0);
150 hasher.update(std.mem.asBytes(&node));
151 hasher.update(std.mem.sliceAsBytes(elems));
152 hasher.update(std.mem.sliceAsBytes(init.names));
153 break :hash hasher.final();
154 },
155 } },
156 },140 },
157 false,141 .fields_len = @intCast(init.names.len),
158 )) {142 .layout = .auto,
143 .any_comptime_fields = true,
144 .any_field_defaults = true,
145 .any_field_aligns = false,
146 .packed_backing_int_type = .none,
147 })) {
148 .existing => |ty| .fromInterned(ty),
159 .wip => |wip| ty: {149 .wip => |wip| ty: {
160 errdefer wip.cancel(ip, pt.tid);150 errdefer wip.cancel(ip, pt.tid);
161 const type_name = try self.sema.createTypeName(151 const block = self.block;
162 self.block,152 const zcu = pt.zcu;
163 .anon,153 try self.sema.setTypeName(block, &wip, .anon, "struct", self.base_node_inst.resolve(ip).?);
164 "struct",154
165 self.base_node_inst.resolve(ip),155 // Reified structs have field information populated immediately.
166 wip.index,156 @memcpy(wip.field_values.get(ip), elems);
167 );157 if (init.names.len > 0) {
168 wip.setName(ip, type_name.name, type_name.nav);158 // All fields are comptime, but unused bits remain zeroed.
169159 const unused_bits = switch (init.names.len % 32) {
170 const struct_type = ip.loadStructType(wip.index);160 0 => 0,
171161 else => |n| 32 - n,
172 for (init.names, 0..) |name, field_idx| {162 };
173 const name_interned = try ip.getOrPutString(163 const comptime_bits = wip.field_is_comptime_bits.getAll(ip);
164 @memset(comptime_bits[0 .. comptime_bits.len - 1], std.math.maxInt(u32));
165 comptime_bits[comptime_bits.len - 1] = @as(u32, std.math.maxInt(u32)) >> @intCast(unused_bits);
166 }
167 for (
168 init.names,
169 wip.field_names.get(ip),
170 wip.field_types.get(ip),
171 wip.field_values.get(ip),
172 ) |zoir_name, *field_name, *field_ty, field_val| {
173 field_name.* = try ip.getOrPutString(
174 gpa,174 gpa,
175 io,175 io,
176 pt.tid,176 pt.tid,
177 name.get(self.file.zoir.?),177 zoir_name.get(self.file.zoir.?),
178 .no_embedded_nulls,178 .no_embedded_nulls,
179 );179 );
180 assert(struct_type.addFieldName(ip, name_interned) == null);180 field_ty.* = ip.typeOf(field_val);
181 struct_type.setFieldComptime(ip, field_idx);
182 }
183
184 @memcpy(struct_type.field_inits.get(ip), elems);
185 const types = struct_type.field_types.get(ip);
186 for (0..init.names.len) |i| {
187 types[i] = Value.fromInterned(elems[i]).typeOf(pt.zcu).toIntern();
188 }181 }
189182
190 const new_namespace_index = try pt.createNamespace(.{183 const new_namespace_index = try pt.createNamespace(.{
191 .parent = self.block.namespace.toOptional(),184 .parent = block.namespace.toOptional(),
192 .owner_type = wip.index,185 .owner_type = wip.index,
193 .file_scope = self.block.getFileScopeIndex(pt.zcu),186 .file_scope = block.getFileScopeIndex(zcu),
194 .generation = pt.zcu.generation,187 .generation = zcu.generation,
195 });188 });
196 try pt.zcu.comp.queueJob(.{ .resolve_type_fully = wip.index });189 errdefer pt.destroyNamespace(new_namespace_index);
197 codegen_type: {190 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
198 if (pt.zcu.comp.config.use_llvm) break :codegen_type;191 break :ty .fromInterned(wip.finish(ip, new_namespace_index));
199 if (self.block.ownerModule().strip) break :codegen_type;
200 pt.zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
201 try pt.zcu.comp.queueJob(.{ .link_type = wip.index });
202 }
203 break :ty wip.finish(ip, new_namespace_index);
204 },192 },
205 .existing => |ty| ty,
206 };193 };
207 try self.sema.declareDependency(.{ .interned = struct_ty });
208 try self.sema.addTypeReferenceEntry(self.nodeSrc(node), struct_ty);194 try self.sema.addTypeReferenceEntry(self.nodeSrc(node), struct_ty);
195 // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty.
196 try self.sema.ensureLayoutResolved(struct_ty, self.nodeSrc(node), .init);
209197
210 return (try pt.aggregateValue(.fromInterned(struct_ty), elems)).toIntern();198 return (try pt.aggregateValue(struct_ty, elems)).toIntern();
211 },199 },
212 }200 }
213}201}
src/Value.zig-1
...@@ -1954,7 +1954,6 @@ pub const PointerDeriveStep = union(enum) {...@@ -1954,7 +1954,6 @@ pub const PointerDeriveStep = union(enum) {
1954/// which prefer field/elem accesses when lowering constant pointer values.1954/// which prefer field/elem accesses when lowering constant pointer values.
1955/// It is also used by the Value printing logic for pointers.1955/// It is also used by the Value printing logic for pointers.
1956pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, opt_sema: ?*Sema) Allocator.Error!PointerDeriveStep {1956pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, opt_sema: ?*Sema) Allocator.Error!PointerDeriveStep {
1957 // MLUGG TODO: audit tf outta this code
1958 const zcu = pt.zcu;1957 const zcu = pt.zcu;
1959 const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr;1958 const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
1960 const base_derive: PointerDeriveStep = switch (ptr.base_addr) {1959 const base_derive: PointerDeriveStep = switch (ptr.base_addr) {
src/Zcu.zig+31-41
...@@ -3518,50 +3518,10 @@ pub const ImportResult = struct {...@@ -3518,50 +3518,10 @@ pub const ImportResult = struct {
3518 module: ?*Package.Module,3518 module: ?*Package.Module,
3519};3519};
35203520
3521/// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of
3522/// this `AnalUnit` will cause them to be re-created (or not).
3523pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
3524 const gpa = zcu.gpa;
3525
3526 const exports_base, const exports_len = if (zcu.single_exports.fetchSwapRemove(anal_unit)) |kv|
3527 .{ @intFromEnum(kv.value), 1 }
3528 else if (zcu.multi_exports.fetchSwapRemove(anal_unit)) |info|
3529 .{ info.value.index, info.value.len }
3530 else
3531 return;
3532
3533 const exports = zcu.all_exports.items[exports_base..][0..exports_len];
3534
3535 // In an only-c build, we're guaranteed to never use incremental compilation, so there are
3536 // guaranteed not to be any exports in the output file that need deleting (since we only call
3537 // `updateExports` on flush).
3538 // This case is needed because in some rare edge cases, `Sema` wants to add and delete exports
3539 // within a single update.
3540 if (dev.env.supports(.incremental)) {
3541 for (exports, exports_base..) |exp, export_index_usize| {
3542 const export_idx: Export.Index = @enumFromInt(export_index_usize);
3543 if (zcu.comp.bin_file) |lf| {
3544 lf.deleteExport(exp.exported, exp.opts.name);
3545 }
3546 if (zcu.failed_exports.fetchSwapRemove(export_idx)) |failed_kv| {
3547 failed_kv.value.destroy(gpa);
3548 }
3549 }
3550 }
3551
3552 zcu.free_exports.ensureUnusedCapacity(gpa, exports_len) catch {
3553 // This space will be reused eventually, so we need not propagate this error.
3554 // Just leak it for now, and let GC reclaim it later on.
3555 return;
3556 };
3557 for (exports_base..exports_base + exports_len) |export_idx| {
3558 zcu.free_exports.appendAssumeCapacity(@enumFromInt(export_idx));
3559 }
3560}
3561
3562/// Prepares `unit` for re-analysis by clearing all of the following state:3521/// Prepares `unit` for re-analysis by clearing all of the following state:
3563/// * Compile errors associated with `unit`3522/// * Compile errors associated with `unit`
3564/// * Compile logs associated with `unit`3523/// * Compile logs associated with `unit`
3524/// * Exports performed by `unit`
3565/// * Dependencies from `unit` on other things3525/// * Dependencies from `unit` on other things
3566/// * References from `unit` to other units3526/// * References from `unit` to other units
3567/// Delete all references in `reference_table` which are caused by `unit`, and all dependencies it3527/// Delete all references in `reference_table` which are caused by `unit`, and all dependencies it
...@@ -3593,6 +3553,36 @@ pub fn resetUnit(zcu: *Zcu, unit: AnalUnit) void {...@@ -3593,6 +3553,36 @@ pub fn resetUnit(zcu: *Zcu, unit: AnalUnit) void {
3593 }3553 }
3594 }3554 }
35953555
3556 // Exports
3557 exports: {
3558 const base: u32, const len: u32 = index: {
3559 if (zcu.single_exports.fetchSwapRemove(unit)) |kv| {
3560 break :index .{ @intFromEnum(kv.value), 1 };
3561 }
3562 if (zcu.multi_exports.fetchSwapRemove(unit)) |kv| {
3563 break :index .{ kv.value.index, kv.value.len };
3564 }
3565 break :exports;
3566 };
3567 for (zcu.all_exports.items[base..][0..len], base..) |exp, exp_index_usize| {
3568 const exp_index: Export.Index = @enumFromInt(exp_index_usize);
3569 if (zcu.comp.bin_file) |lf| {
3570 lf.deleteExport(exp.exported, exp.opts.name);
3571 }
3572 if (zcu.failed_exports.fetchSwapRemove(exp_index)) |failed_kv| {
3573 failed_kv.value.destroy(gpa);
3574 }
3575 }
3576 zcu.free_exports.ensureUnusedCapacity(gpa, len) catch {
3577 // This space will be reused eventually, so we need not propagate this error.
3578 // Just leak it for now, and let GC reclaim it later on.
3579 break :exports;
3580 };
3581 for (base..base + len) |exp_index| {
3582 zcu.free_exports.appendAssumeCapacity(@enumFromInt(exp_index));
3583 }
3584 }
3585
3596 // Dependencies3586 // Dependencies
3597 zcu.intern_pool.removeDependenciesForDepender(gpa, unit);3587 zcu.intern_pool.removeDependenciesForDepender(gpa, unit);
35983588
src/Zcu/PerThread.zig+2-12
...@@ -752,7 +752,6 @@ pub fn ensureMemoizedStateUpToDate(...@@ -752,7 +752,6 @@ pub fn ensureMemoizedStateUpToDate(
752 if (was_outdated) {752 if (was_outdated) {
753 dev.check(.incremental);753 dev.check(.incremental);
754 _ = zcu.outdated_ready.swapRemove(unit);754 _ = zcu.outdated_ready.swapRemove(unit);
755 // No need for `deleteUnitExports` because we never export anything.
756 zcu.resetUnit(unit);755 zcu.resetUnit(unit);
757 } else {756 } else {
758 if (prev_failed) return error.AnalysisFail;757 if (prev_failed) return error.AnalysisFail;
...@@ -874,7 +873,6 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU...@@ -874,7 +873,6 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU
874 _ = zcu.outdated_ready.swapRemove(anal_unit);873 _ = zcu.outdated_ready.swapRemove(anal_unit);
875 // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`.874 // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`.
876 if (dev.env.supports(.incremental)) {875 if (dev.env.supports(.incremental)) {
877 zcu.deleteUnitExports(anal_unit);
878 zcu.resetUnit(anal_unit);876 zcu.resetUnit(anal_unit);
879 }877 }
880 } else {878 } else {
...@@ -1033,7 +1031,6 @@ pub fn ensureTypeLayoutUpToDate(...@@ -1033,7 +1031,6 @@ pub fn ensureTypeLayoutUpToDate(
1033 _ = zcu.outdated_ready.swapRemove(anal_unit);1031 _ = zcu.outdated_ready.swapRemove(anal_unit);
1034 // `was_outdated` is true in the initial update, so this isn't a `dev.check`.1032 // `was_outdated` is true in the initial update, so this isn't a `dev.check`.
1035 if (dev.env.supports(.incremental)) {1033 if (dev.env.supports(.incremental)) {
1036 zcu.deleteUnitExports(anal_unit);
1037 zcu.resetUnit(anal_unit);1034 zcu.resetUnit(anal_unit);
1038 }1035 }
1039 // For types, we already know that we have to invalidate all dependees.1036 // For types, we already know that we have to invalidate all dependees.
...@@ -1151,7 +1148,6 @@ pub fn ensureNavValUpToDate(...@@ -1151,7 +1148,6 @@ pub fn ensureNavValUpToDate(
1151 if (was_outdated) {1148 if (was_outdated) {
1152 dev.check(.incremental);1149 dev.check(.incremental);
1153 _ = zcu.outdated_ready.swapRemove(anal_unit);1150 _ = zcu.outdated_ready.swapRemove(anal_unit);
1154 zcu.deleteUnitExports(anal_unit);
1155 zcu.resetUnit(anal_unit);1151 zcu.resetUnit(anal_unit);
1156 } else {1152 } else {
1157 // We can trust the current information about this unit.1153 // We can trust the current information about this unit.
...@@ -1238,7 +1234,7 @@ fn analyzeNavVal(...@@ -1238,7 +1234,7 @@ fn analyzeNavVal(
1238 const zir_decl = zir.getDeclaration(inst_resolved.inst);1234 const zir_decl = zir.getDeclaration(inst_resolved.inst);
12391235
1240 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, reason);1236 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, reason);
1241 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);1237 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
12421238
1243 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);1239 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
1244 defer analysis_arena.deinit();1240 defer analysis_arena.deinit();
...@@ -1443,15 +1439,11 @@ fn analyzeNavVal(...@@ -1443,15 +1439,11 @@ fn analyzeNavVal(
1443 .@"addrspace" = modifiers.@"addrspace",1439 .@"addrspace" = modifiers.@"addrspace",
1444 });1440 });
14451441
1446 // Mark the unit as completed before evaluating the export!
1447 // MLUGG TODO: do we really need to do this?
1448 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1449
1450 if (zir_decl.linkage == .@"export") {1442 if (zir_decl.linkage == .@"export") {
1451 const export_src = block.src(.{ .token_offset = @enumFromInt(@intFromBool(zir_decl.is_pub)) });1443 const export_src = block.src(.{ .token_offset = @enumFromInt(@intFromBool(zir_decl.is_pub)) });
1452 const name_slice = zir.nullTerminatedString(zir_decl.name);1444 const name_slice = zir.nullTerminatedString(zir_decl.name);
1453 const name_ip = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);1445 const name_ip = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
1454 try sema.analyzeExport(&block, export_src, .{ .name = name_ip }, nav_id);1446 try sema.analyzeExportSelfNav(&block, export_src, name_ip);
1455 }1447 }
14561448
1457 try sema.flushExports();1449 try sema.flushExports();
...@@ -1514,7 +1506,6 @@ pub fn ensureNavTypeUpToDate(...@@ -1514,7 +1506,6 @@ pub fn ensureNavTypeUpToDate(
1514 if (was_outdated) {1506 if (was_outdated) {
1515 dev.check(.incremental);1507 dev.check(.incremental);
1516 _ = zcu.outdated_ready.swapRemove(anal_unit);1508 _ = zcu.outdated_ready.swapRemove(anal_unit);
1517 zcu.deleteUnitExports(anal_unit);
1518 zcu.resetUnit(anal_unit);1509 zcu.resetUnit(anal_unit);
1519 } else {1510 } else {
1520 // We can trust the current information about this unit.1511 // We can trust the current information about this unit.
...@@ -1751,7 +1742,6 @@ pub fn ensureFuncBodyUpToDate(...@@ -1751,7 +1742,6 @@ pub fn ensureFuncBodyUpToDate(
1751 if (was_outdated) {1742 if (was_outdated) {
1752 dev.check(.incremental);1743 dev.check(.incremental);
1753 _ = zcu.outdated_ready.swapRemove(anal_unit);1744 _ = zcu.outdated_ready.swapRemove(anal_unit);
1754 zcu.deleteUnitExports(anal_unit);
1755 zcu.resetUnit(anal_unit);1745 zcu.resetUnit(anal_unit);
1756 } else {1746 } else {
1757 // We can trust the current information about this function.1747 // We can trust the current information about this function.