authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-14 19:59:58-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-15 00:55:07-07:00
log8592c5cdac41e4e04034e4f9a0fd8cb51e8c4257
treec7c69a498e603d5038c23ca1f925be53788b672d
parent4f952c7e0e36dab15f9359f55eb8714f8fe92bcf

compiler: rework capture scopes in-memory layout

* Use 32-bit integers instead of pointers for compactness and serialization friendliness. * Use a separate hash map for runtime and comptime capture scopes, avoiding the 1-bit union tag. * Use a compact array representation instead of a tree of hash maps. * Eliminate the only instance of ref-counting in the compiler, instead relying on garbage collection (not implemented yet but is the plan for almost all long-lived objects related to incremental compilation). Because a code modification may need to access capture scope data, this makes capture scope data long-lived state. My goal is to get incremental compilation state serialization down to a single pwritev syscall, by unifying the on-disk representation with the in-memory representation. This commit eliminates the last remaining pointer field of `Module.Decl`.

2 files changed, 97 insertions(+), 228 deletions(-)

src/Module.zig+37-94
......@@ -92,6 +92,17 @@ embed_table: std.StringHashMapUnmanaged(*EmbedFile) = .{},
9292/// is not yet implemented.
9393intern_pool: InternPool = .{},
9494
95/// The index type for this array is `CaptureScope.Index` and the elements here are
96/// the indexes of the parent capture scopes.
97/// Memory is owned by gpa; garbage collected.
98capture_scope_parents: std.ArrayListUnmanaged(CaptureScope.Index) = .{},
99/// Value is index of type
100/// Memory is owned by gpa; garbage collected.
101runtime_capture_scopes: std.AutoArrayHashMapUnmanaged(CaptureScope.Key, InternPool.Index) = .{},
102/// Value is index of value
103/// Memory is owned by gpa; garbage collected.
104comptime_capture_scopes: std.AutoArrayHashMapUnmanaged(CaptureScope.Key, InternPool.Index) = .{},
105
95106/// To be eliminated in a future commit by moving more data into InternPool.
96107/// Current uses that must be eliminated:
97108/// * Struct comptime_args
......@@ -272,83 +283,26 @@ pub const Export = struct {
272283};
273284
274285pub const CaptureScope = struct {
275 refs: u32,
276 parent: ?*CaptureScope,
277
278 /// Values from this decl's evaluation that will be closed over in
279 /// child decls. This map is backed by the gpa, and deinited when
280 /// the refcount reaches 0.
281 captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Capture) = .{},
282
283 pub const Capture = union(enum) {
284 comptime_val: InternPool.Index, // index of value
285 runtime_val: InternPool.Index, // index of type
286 pub const Key = extern struct {
287 zir_index: Zir.Inst.Index,
288 index: Index,
286289 };
287290
288 pub fn failed(noalias self: *const CaptureScope) bool {
289 return self.captures.available == 0 and self.captures.size == std.math.maxInt(u32);
290 }
291
292 pub fn fail(noalias self: *CaptureScope, gpa: Allocator) void {
293 self.captures.deinit(gpa);
294 self.captures.available = 0;
295 self.captures.size = std.math.maxInt(u32);
296 }
297
298 pub fn incRef(self: *CaptureScope) void {
299 // TODO: wtf is reference counting doing in my beautiful codebase? 😠
300 // seriously though, let's change this to rely on InternPool garbage
301 // collection instead.
302 self.refs += 1;
303 }
291 /// Index into `capture_scope_parents` which uniquely identifies a capture scope.
292 pub const Index = enum(u32) {
293 none = std.math.maxInt(u32),
294 _,
304295
305 pub fn decRef(self: *CaptureScope, gpa: Allocator) void {
306 self.refs -= 1;
307 if (self.refs > 0) return;
308 if (self.parent) |p| p.decRef(gpa);
309 if (!self.failed()) {
310 self.captures.deinit(gpa);
296 pub fn parent(i: Index, mod: *Module) Index {
297 return mod.capture_scope_parents.items[@intFromEnum(i)];
311298 }
312 gpa.destroy(self);
313 }
299 };
314300};
315301
316pub const WipCaptureScope = struct {
317 scope: *CaptureScope,
318 finalized: bool,
319 gpa: Allocator,
320
321 pub fn init(gpa: Allocator, parent: ?*CaptureScope) !WipCaptureScope {
322 const scope = try gpa.create(CaptureScope);
323 if (parent) |p| p.incRef();
324 scope.* = .{ .refs = 1, .parent = parent };
325 return .{
326 .scope = scope,
327 .finalized = false,
328 .gpa = gpa,
329 };
330 }
331
332 pub fn finalize(noalias self: *WipCaptureScope) !void {
333 self.finalized = true;
334 }
335
336 pub fn reset(noalias self: *WipCaptureScope, parent: ?*CaptureScope) !void {
337 self.scope.decRef(self.gpa);
338 self.scope = try self.gpa.create(CaptureScope);
339 if (parent) |p| p.incRef();
340 self.scope.* = .{ .refs = 1, .parent = parent };
341 }
342
343 pub fn deinit(noalias self: *WipCaptureScope) void {
344 if (self.finalized) {
345 self.scope.decRef(self.gpa);
346 } else {
347 self.scope.fail(self.gpa);
348 }
349 self.* = undefined;
350 }
351};
302pub fn createCaptureScope(mod: *Module, parent: CaptureScope.Index) error{OutOfMemory}!CaptureScope.Index {
303 try mod.capture_scope_parents.append(mod.gpa, parent);
304 return @enumFromInt(mod.capture_scope_parents.items.len - 1);
305}
352306
353307const ValueArena = struct {
354308 state: std.heap.ArenaAllocator.State,
......@@ -413,7 +367,7 @@ pub const Decl = struct {
413367 /// The scope which lexically contains this decl. A decl must depend
414368 /// on its lexical parent, in order to ensure that this pointer is valid.
415369 /// This scope is allocated out of the arena of the parent decl.
416 src_scope: ?*CaptureScope,
370 src_scope: CaptureScope.Index,
417371
418372 /// An integer that can be checked against the corresponding incrementing
419373 /// generation field of Module. This is used to determine whether `complete` status
......@@ -2893,6 +2847,10 @@ pub fn deinit(mod: *Module) void {
28932847 mod.memoized_decls.deinit(gpa);
28942848 mod.intern_pool.deinit(gpa);
28952849 mod.tmp_hack_arena.deinit();
2850
2851 mod.capture_scope_parents.deinit(gpa);
2852 mod.runtime_capture_scopes.deinit(gpa);
2853 mod.comptime_capture_scopes.deinit(gpa);
28962854}
28972855
28982856pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
......@@ -2914,7 +2872,6 @@ pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void {
29142872 mod.destroyNamespace(i);
29152873 }
29162874 }
2917 if (decl.src_scope) |scope| scope.decRef(gpa);
29182875 decl.dependants.deinit(gpa);
29192876 decl.dependencies.deinit(gpa);
29202877 }
......@@ -3909,7 +3866,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
39093866 const new_namespace = mod.namespacePtr(new_namespace_index);
39103867 errdefer mod.destroyNamespace(new_namespace_index);
39113868
3912 const new_decl_index = try mod.allocateNewDecl(new_namespace_index, 0, null);
3869 const new_decl_index = try mod.allocateNewDecl(new_namespace_index, 0, .none);
39133870 const new_decl = mod.declPtr(new_decl_index);
39143871 errdefer @panic("TODO error handling");
39153872
......@@ -3984,11 +3941,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
39843941 };
39853942 defer sema.deinit();
39863943
3987 var wip_captures = try WipCaptureScope.init(gpa, null);
3988 defer wip_captures.deinit();
3989
39903944 if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_index)) |_| {
3991 try wip_captures.finalize();
39923945 for (comptime_mutable_decls.items) |decl_index| {
39933946 const decl = mod.declPtr(decl_index);
39943947 _ = try decl.internValue(mod);
......@@ -4115,15 +4068,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
41154068 return false;
41164069 }
41174070
4118 var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope);
4119 defer wip_captures.deinit();
4120
41214071 var block_scope: Sema.Block = .{
41224072 .parent = null,
41234073 .sema = &sema,
41244074 .src_decl = decl_index,
41254075 .namespace = decl.src_namespace,
4126 .wip_capture_scope = wip_captures.scope,
4076 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
41274077 .instructions = .{},
41284078 .inlining = null,
41294079 .is_comptime = true,
......@@ -4137,7 +4087,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
41374087 const result_ref = (try sema.analyzeBodyBreak(&block_scope, body)).?.operand;
41384088 // We'll do some other bits with the Sema. Clear the type target index just in case they analyze any type.
41394089 sema.builtin_type_target_index = .none;
4140 try wip_captures.finalize();
41414090 for (comptime_mutable_decls.items) |ct_decl_index| {
41424091 const ct_decl = mod.declPtr(ct_decl_index);
41434092 _ = try ct_decl.internValue(mod);
......@@ -5069,15 +5018,12 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
50695018 try sema.air_extra.ensureTotalCapacity(gpa, reserved_count);
50705019 sema.air_extra.items.len += reserved_count;
50715020
5072 var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope);
5073 defer wip_captures.deinit();
5074
50755021 var inner_block: Sema.Block = .{
50765022 .parent = null,
50775023 .sema = &sema,
50785024 .src_decl = decl_index,
50795025 .namespace = decl.src_namespace,
5080 .wip_capture_scope = wip_captures.scope,
5026 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
50815027 .instructions = .{},
50825028 .inlining = null,
50835029 .is_comptime = false,
......@@ -5189,7 +5135,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
51895135 };
51905136 }
51915137
5192 try wip_captures.finalize();
51935138 for (comptime_mutable_decls.items) |ct_decl_index| {
51945139 const ct_decl = mod.declPtr(ct_decl_index);
51955140 _ = try ct_decl.internValue(mod);
......@@ -5308,7 +5253,7 @@ pub fn allocateNewDecl(
53085253 mod: *Module,
53095254 namespace: Namespace.Index,
53105255 src_node: Ast.Node.Index,
5311 src_scope: ?*CaptureScope,
5256 src_scope: CaptureScope.Index,
53125257) !Decl.Index {
53135258 const ip = &mod.intern_pool;
53145259 const gpa = mod.gpa;
......@@ -5344,8 +5289,6 @@ pub fn allocateNewDecl(
53445289 }
53455290 }
53465291
5347 if (src_scope) |scope| scope.incRef();
5348
53495292 return decl_index;
53505293}
53515294
......@@ -5374,7 +5317,7 @@ pub fn createAnonymousDeclFromDecl(
53745317 mod: *Module,
53755318 src_decl: *Decl,
53765319 namespace: Namespace.Index,
5377 src_scope: ?*CaptureScope,
5320 src_scope: CaptureScope.Index,
53785321 tv: TypedValue,
53795322) !Decl.Index {
53805323 const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node, src_scope);
......@@ -5968,7 +5911,7 @@ pub fn populateTestFunctions(
59685911 .len = test_decl_name.len,
59695912 .child = .u8_type,
59705913 });
5971 const test_name_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, null, .{
5914 const test_name_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, .none, .{
59725915 .ty = test_name_decl_ty,
59735916 .val = (try mod.intern(.{ .aggregate = .{
59745917 .ty = test_name_decl_ty.toIntern(),
......@@ -6015,7 +5958,7 @@ pub fn populateTestFunctions(
60155958 .child = test_fn_ty.toIntern(),
60165959 .sentinel = .none,
60175960 });
6018 const array_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, null, .{
5961 const array_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, .none, .{
60195962 .ty = array_decl_ty,
60205963 .val = (try mod.intern(.{ .aggregate = .{
60215964 .ty = array_decl_ty.toIntern(),
src/Sema.zig+60-134
......@@ -131,7 +131,6 @@ const CompileError = Module.CompileError;
131131const SemaError = Module.SemaError;
132132const Decl = Module.Decl;
133133const CaptureScope = Module.CaptureScope;
134const WipCaptureScope = Module.WipCaptureScope;
135134const LazySrcLoc = Module.LazySrcLoc;
136135const RangeSet = @import("RangeSet.zig");
137136const target_util = @import("target.zig");
......@@ -308,7 +307,7 @@ pub const Block = struct {
308307 /// used to add a `func_instance` into the `InternPool`.
309308 params: std.MultiArrayList(Param) = .{},
310309
311 wip_capture_scope: *CaptureScope,
310 wip_capture_scope: CaptureScope.Index,
312311
313312 label: ?*Label = null,
314313 inlining: ?*Inlining,
......@@ -951,21 +950,12 @@ fn analyzeBodyInner(
951950 // different values for the same Zir.Inst.Index, so in those cases, we will
952951 // have to create nested capture scopes; see the `.repeat` case below.
953952 const parent_capture_scope = block.wip_capture_scope;
954 parent_capture_scope.incRef();
955 var wip_captures: WipCaptureScope = .{
956 .scope = parent_capture_scope,
957 .gpa = sema.gpa,
958 .finalized = true, // don't finalize the parent scope
959 };
960 defer wip_captures.deinit();
961953
962954 const mod = sema.mod;
963955 const map = &sema.inst_map;
964956 const tags = sema.code.instructions.items(.tag);
965957 const datas = sema.code.instructions.items(.data);
966958
967 var orig_captures: usize = parent_capture_scope.captures.count();
968
969959 var crash_info = crash_report.prepAnalyzeBody(sema, block, body);
970960 crash_info.push();
971961 defer crash_info.pop();
......@@ -1500,16 +1490,11 @@ fn analyzeBodyInner(
15001490 // Send comptime control flow back to the beginning of this block.
15011491 const src = LazySrcLoc.nodeOffset(datas[inst].node);
15021492 try sema.emitBackwardBranch(block, src);
1503 if (wip_captures.scope.captures.count() != orig_captures) {
1504 // We need to construct new capture scopes for the next loop iteration so it
1505 // can capture values without clobbering the earlier iteration's captures.
1506 // At first, we reused the parent capture scope as an optimization, but for
1507 // successive scopes we have to create new ones as children of the parent
1508 // scope.
1509 try wip_captures.reset(parent_capture_scope);
1510 block.wip_capture_scope = wip_captures.scope;
1511 orig_captures = 0;
1512 }
1493
1494 // We need to construct new capture scopes for the next loop iteration so it
1495 // can capture values without clobbering the earlier iteration's captures.
1496 block.wip_capture_scope = try mod.createCaptureScope(parent_capture_scope);
1497
15131498 i = 0;
15141499 continue;
15151500 } else {
......@@ -1520,16 +1505,11 @@ fn analyzeBodyInner(
15201505 // Send comptime control flow back to the beginning of this block.
15211506 const src = LazySrcLoc.nodeOffset(datas[inst].node);
15221507 try sema.emitBackwardBranch(block, src);
1523 if (wip_captures.scope.captures.count() != orig_captures) {
1524 // We need to construct new capture scopes for the next loop iteration so it
1525 // can capture values without clobbering the earlier iteration's captures.
1526 // At first, we reused the parent capture scope as an optimization, but for
1527 // successive scopes we have to create new ones as children of the parent
1528 // scope.
1529 try wip_captures.reset(parent_capture_scope);
1530 block.wip_capture_scope = wip_captures.scope;
1531 orig_captures = 0;
1532 }
1508
1509 // We need to construct new capture scopes for the next loop iteration so it
1510 // can capture values without clobbering the earlier iteration's captures.
1511 block.wip_capture_scope = try mod.createCaptureScope(parent_capture_scope);
1512
15331513 i = 0;
15341514 continue;
15351515 },
......@@ -1803,12 +1783,9 @@ fn analyzeBodyInner(
18031783 }
18041784 if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some);
18051785
1806 if (!wip_captures.finalized) {
1807 // We've updated the capture scope due to a `repeat` instruction where
1808 // the body had a capture; finalize our child scope and reset
1809 try wip_captures.finalize();
1810 block.wip_capture_scope = parent_capture_scope;
1811 }
1786 // We may have overwritten the capture scope due to a `repeat` instruction where
1787 // the body had a capture; restore it now.
1788 block.wip_capture_scope = parent_capture_scope;
18121789
18131790 return result;
18141791}
......@@ -3157,15 +3134,12 @@ fn zirEnumDecl(
31573134 sema.func_index = .none;
31583135 defer sema.func_index = prev_func_index;
31593136
3160 var wip_captures = try WipCaptureScope.init(gpa, new_decl.src_scope);
3161 defer wip_captures.deinit();
3162
31633137 var enum_block: Block = .{
31643138 .parent = null,
31653139 .sema = sema,
31663140 .src_decl = new_decl_index,
31673141 .namespace = new_namespace_index,
3168 .wip_capture_scope = wip_captures.scope,
3142 .wip_capture_scope = try mod.createCaptureScope(new_decl.src_scope),
31693143 .instructions = .{},
31703144 .inlining = null,
31713145 .is_comptime = true,
......@@ -3176,8 +3150,6 @@ fn zirEnumDecl(
31763150 try sema.analyzeBody(&enum_block, body);
31773151 }
31783152
3179 try wip_captures.finalize();
3180
31813153 if (tag_type_ref != .none) {
31823154 const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref);
31833155 if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) {
......@@ -7298,15 +7270,12 @@ fn analyzeCall(
72987270
72997271 try mod.declareDeclDependencyType(ics.callee().owner_decl_index, module_fn.owner_decl, .function_body);
73007272
7301 var wip_captures = try WipCaptureScope.init(gpa, fn_owner_decl.src_scope);
7302 defer wip_captures.deinit();
7303
73047273 var child_block: Block = .{
73057274 .parent = null,
73067275 .sema = sema,
73077276 .src_decl = module_fn.owner_decl,
73087277 .namespace = fn_owner_decl.src_namespace,
7309 .wip_capture_scope = wip_captures.scope,
7278 .wip_capture_scope = try mod.createCaptureScope(fn_owner_decl.src_scope),
73107279 .instructions = .{},
73117280 .label = null,
73127281 .inlining = &inlining,
......@@ -7514,8 +7483,6 @@ fn analyzeCall(
75147483 break :res2 result;
75157484 };
75167485
7517 try wip_captures.finalize();
7518
75197486 break :res res2;
75207487 } else res: {
75217488 assert(!func_ty_info.is_generic);
......@@ -7840,15 +7807,12 @@ fn instantiateGenericCall(
78407807 };
78417808 defer child_sema.deinit();
78427809
7843 var wip_captures = try WipCaptureScope.init(gpa, sema.owner_decl.src_scope);
7844 defer wip_captures.deinit();
7845
78467810 var child_block: Block = .{
78477811 .parent = null,
78487812 .sema = &child_sema,
78497813 .src_decl = generic_owner_func.owner_decl,
78507814 .namespace = namespace_index,
7851 .wip_capture_scope = wip_captures.scope,
7815 .wip_capture_scope = try mod.createCaptureScope(sema.owner_decl.src_scope),
78527816 .instructions = .{},
78537817 .inlining = null,
78547818 .is_comptime = true,
......@@ -8000,8 +7964,6 @@ fn instantiateGenericCall(
80007964 const func_ty = callee.ty.toType();
80017965 const func_ty_info = mod.typeToFunc(func_ty).?;
80027966
8003 try wip_captures.finalize();
8004
80057967 // If the call evaluated to a return type that requires comptime, never mind
80067968 // our generic instantiation. Instead we need to perform a comptime call.
80077969 if (try sema.typeRequiresComptime(func_ty_info.return_type.toType())) {
......@@ -11897,11 +11859,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1189711859 const body = sema.code.extra[extra_index..][0..info.body_len];
1189811860 extra_index += info.body_len;
1189911861
11900 var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope);
11901 defer wip_captures.deinit();
11902
1190311862 case_block.instructions.shrinkRetainingCapacity(0);
11904 case_block.wip_capture_scope = wip_captures.scope;
11863 case_block.wip_capture_scope = try mod.createCaptureScope(child_block.wip_capture_scope);
1190511864
1190611865 const item = case_vals.items[scalar_i];
1190711866 // `item` is already guaranteed to be constant known.
......@@ -11929,8 +11888,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1192911888 _ = try case_block.addNoOp(.unreach);
1193011889 }
1193111890
11932 try wip_captures.finalize();
11933
1193411891 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
1193511892 cases_extra.appendAssumeCapacity(1); // items_len
1193611893 cases_extra.appendAssumeCapacity(@intCast(case_block.instructions.items.len));
......@@ -12177,11 +12134,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1217712134 var cond_body = try case_block.instructions.toOwnedSlice(gpa);
1217812135 defer gpa.free(cond_body);
1217912136
12180 var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope);
12181 defer wip_captures.deinit();
12182
1218312137 case_block.instructions.shrinkRetainingCapacity(0);
12184 case_block.wip_capture_scope = wip_captures.scope;
12138 case_block.wip_capture_scope = try mod.createCaptureScope(child_block.wip_capture_scope);
1218512139
1218612140 const body = sema.code.extra[extra_index..][0..info.body_len];
1218712141 extra_index += info.body_len;
......@@ -12200,8 +12154,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1220012154 );
1220112155 }
1220212156
12203 try wip_captures.finalize();
12204
1220512157 if (is_first) {
1220612158 is_first = false;
1220712159 first_else_body = cond_body;
......@@ -12407,11 +12359,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1240712359 }),
1240812360 };
1240912361
12410 var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope);
12411 defer wip_captures.deinit();
12412
1241312362 case_block.instructions.shrinkRetainingCapacity(0);
12414 case_block.wip_capture_scope = wip_captures.scope;
12363 case_block.wip_capture_scope = try mod.createCaptureScope(child_block.wip_capture_scope);
1241512364
1241612365 if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and
1241712366 operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally))
......@@ -12456,8 +12405,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1245612405 }
1245712406 }
1245812407
12459 try wip_captures.finalize();
12460
1246112408 if (is_first) {
1246212409 final_else_body = case_block.instructions.items;
1246312410 } else {
......@@ -16557,51 +16504,53 @@ fn zirThis(
1655716504}
1655816505
1655916506fn zirClosureCapture(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
16507 const mod = sema.mod;
16508 const gpa = sema.gpa;
1656016509 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1656116510 // Closures are not necessarily constant values. For example, the
1656216511 // code might do something like this:
1656316512 // fn foo(x: anytype) void { const S = struct {field: @TypeOf(x)}; }
1656416513 // ...in which case the closure_capture instruction has access to a runtime
16565 // value only. In such case we preserve the type and use a dummy runtime value.
16514 // value only. In such case only the type is saved into the scope.
1656616515 const operand = try sema.resolveInst(inst_data.operand);
1656716516 const ty = sema.typeOf(operand);
16568 const capture: CaptureScope.Capture = blk: {
16569 if (try sema.resolveMaybeUndefValAllowVariables(operand)) |val| {
16570 const ip_index = try val.intern(ty, sema.mod);
16571 break :blk .{ .comptime_val = ip_index };
16572 }
16573 break :blk .{ .runtime_val = ty.toIntern() };
16517 const key: CaptureScope.Key = .{
16518 .zir_index = inst,
16519 .index = block.wip_capture_scope,
1657416520 };
16575 try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, capture);
16521 if (try sema.resolveMaybeUndefValAllowVariables(operand)) |val| {
16522 try mod.comptime_capture_scopes.put(gpa, key, try val.intern(ty, mod));
16523 } else {
16524 try mod.runtime_capture_scopes.put(gpa, key, ty.toIntern());
16525 }
1657616526}
1657716527
1657816528fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1657916529 const mod = sema.mod;
16580 const ip = &mod.intern_pool;
16530 //const ip = &mod.intern_pool;
1658116531 const inst_data = sema.code.instructions.items(.data)[inst].inst_node;
16582 var scope: *CaptureScope = mod.declPtr(block.src_decl).src_scope.?;
16532 var scope: CaptureScope.Index = mod.declPtr(block.src_decl).src_scope;
16533 assert(scope != .none);
1658316534 // Note: The target closure must be in this scope list.
1658416535 // If it's not here, the zir is invalid, or the list is broken.
16585 const capture = while (true) {
16536 const capture_ty = while (true) {
1658616537 // Note: We don't need to add a dependency here, because
1658716538 // decls always depend on their lexical parents.
16588
16589 // Fail this decl if a scope it depended on failed.
16590 if (scope.failed()) {
16591 if (sema.owner_func_index != .none) {
16592 ip.funcAnalysis(sema.owner_func_index).state = .dependency_failure;
16593 } else {
16594 sema.owner_decl.analysis = .dependency_failure;
16595 }
16596 return error.AnalysisFail;
16597 }
16598 if (scope.captures.get(inst_data.inst)) |capture| {
16599 break capture;
16600 }
16601 scope = scope.parent.?;
16539 const key: CaptureScope.Key = .{
16540 .zir_index = inst_data.inst,
16541 .index = scope,
16542 };
16543 if (mod.comptime_capture_scopes.get(key)) |val|
16544 return Air.internedToRef(val);
16545 if (mod.runtime_capture_scopes.get(key)) |ty|
16546 break ty;
16547 scope = scope.parent(mod);
16548 assert(scope != .none);
1660216549 };
1660316550
16604 if (capture == .runtime_val and !block.is_typeof and sema.func_index == .none) {
16551 // The comptime case is handled already above. Runtime case below.
16552
16553 if (!block.is_typeof and sema.func_index == .none) {
1660516554 const msg = msg: {
1660616555 const name = name: {
1660716556 const file = sema.owner_decl.getFileScope(mod);
......@@ -16629,7 +16578,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1662916578 return sema.failWithOwnedErrorMsg(block, msg);
1663016579 }
1663116580
16632 if (capture == .runtime_val and !block.is_typeof and !block.is_comptime and sema.func_index != .none) {
16581 if (!block.is_typeof and !block.is_comptime and sema.func_index != .none) {
1663316582 const msg = msg: {
1663416583 const name = name: {
1663516584 const file = sema.owner_decl.getFileScope(mod);
......@@ -16659,16 +16608,9 @@ fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1665916608 return sema.failWithOwnedErrorMsg(block, msg);
1666016609 }
1666116610
16662 switch (capture) {
16663 .runtime_val => |ty_ip_index| {
16664 assert(block.is_typeof);
16665 // We need a dummy runtime instruction with the correct type.
16666 return block.addTy(.alloc, ty_ip_index.toType());
16667 },
16668 .comptime_val => |val_ip_index| {
16669 return Air.internedToRef(val_ip_index);
16670 },
16671 }
16611 assert(block.is_typeof);
16612 // We need a dummy runtime instruction with the correct type.
16613 return block.addTy(.alloc, capture_ty.toType());
1667216614}
1667316615
1667416616fn zirRetAddr(
......@@ -24988,7 +24930,7 @@ fn zirBuiltinExtern(
2498824930
2498924931 // TODO check duplicate extern
2499024932
24991 const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null);
24933 const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, .none);
2499224934 errdefer mod.destroyDecl(new_decl_index);
2499324935 const new_decl = mod.declPtr(new_decl_index);
2499424936 new_decl.name = options.name;
......@@ -34327,15 +34269,12 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3432734269 };
3432834270 defer sema.deinit();
3432934271
34330 var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope);
34331 defer wip_captures.deinit();
34332
3433334272 var block: Block = .{
3433434273 .parent = null,
3433534274 .sema = &sema,
3433634275 .src_decl = decl_index,
3433734276 .namespace = struct_obj.namespace,
34338 .wip_capture_scope = wip_captures.scope,
34277 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
3433934278 .instructions = .{},
3434034279 .inlining = null,
3434134280 .is_comptime = true,
......@@ -34356,7 +34295,6 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3435634295
3435734296 try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);
3435834297 struct_obj.backing_int_ty = backing_int_ty;
34359 try wip_captures.finalize();
3436034298 for (comptime_mutable_decls.items) |ct_decl_index| {
3436134299 const ct_decl = mod.declPtr(ct_decl_index);
3436234300 _ = try ct_decl.internValue(mod);
......@@ -35018,15 +34956,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3501834956 };
3501934957 defer sema.deinit();
3502034958
35021 var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope);
35022 defer wip_captures.deinit();
35023
3502434959 var block_scope: Block = .{
3502534960 .parent = null,
3502634961 .sema = &sema,
3502734962 .src_decl = decl_index,
3502834963 .namespace = struct_obj.namespace,
35029 .wip_capture_scope = wip_captures.scope,
34964 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
3503034965 .instructions = .{},
3503134966 .inlining = null,
3503234967 .is_comptime = true,
......@@ -35283,7 +35218,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3528335218 }
3528435219 }
3528535220 }
35286 try wip_captures.finalize();
3528735221 for (comptime_mutable_decls.items) |ct_decl_index| {
3528835222 const ct_decl = mod.declPtr(ct_decl_index);
3528935223 _ = try ct_decl.internValue(mod);
......@@ -35361,15 +35295,12 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
3536135295 };
3536235296 defer sema.deinit();
3536335297
35364 var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope);
35365 defer wip_captures.deinit();
35366
3536735298 var block_scope: Block = .{
3536835299 .parent = null,
3536935300 .sema = &sema,
3537035301 .src_decl = decl_index,
3537135302 .namespace = union_type.namespace,
35372 .wip_capture_scope = wip_captures.scope,
35303 .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
3537335304 .instructions = .{},
3537435305 .inlining = null,
3537535306 .is_comptime = true,
......@@ -35380,7 +35311,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
3538035311 try sema.analyzeBody(&block_scope, body);
3538135312 }
3538235313
35383 try wip_captures.finalize();
3538435314 for (comptime_mutable_decls.items) |ct_decl_index| {
3538535315 const ct_decl = mod.declPtr(ct_decl_index);
3538635316 _ = try ct_decl.internValue(mod);
......@@ -35823,18 +35753,16 @@ fn generateUnionTagTypeSimple(
3582335753}
3582435754
3582535755fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
35756 const mod = sema.mod;
3582635757 const gpa = sema.gpa;
3582735758 const src = LazySrcLoc.nodeOffset(0);
3582835759
35829 var wip_captures = try WipCaptureScope.init(gpa, sema.owner_decl.src_scope);
35830 defer wip_captures.deinit();
35831
3583235760 var block: Block = .{
3583335761 .parent = null,
3583435762 .sema = sema,
3583535763 .src_decl = sema.owner_decl_index,
3583635764 .namespace = sema.owner_decl.src_namespace,
35837 .wip_capture_scope = wip_captures.scope,
35765 .wip_capture_scope = try mod.createCaptureScope(sema.owner_decl.src_scope),
3583835766 .instructions = .{},
3583935767 .inlining = null,
3584035768 .is_comptime = true,
......@@ -35875,17 +35803,15 @@ fn getBuiltinDecl(sema: *Sema, block: *Block, name: []const u8) CompileError!Mod
3587535803}
3587635804
3587735805fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
35806 const mod = sema.mod;
3587835807 const ty_inst = try sema.getBuiltin(name);
3587935808
35880 var wip_captures = try WipCaptureScope.init(sema.gpa, sema.owner_decl.src_scope);
35881 defer wip_captures.deinit();
35882
3588335809 var block: Block = .{
3588435810 .parent = null,
3588535811 .sema = sema,
3588635812 .src_decl = sema.owner_decl_index,
3588735813 .namespace = sema.owner_decl.src_namespace,
35888 .wip_capture_scope = wip_captures.scope,
35814 .wip_capture_scope = try mod.createCaptureScope(sema.owner_decl.src_scope),
3588935815 .instructions = .{},
3589035816 .inlining = null,
3589135817 .is_comptime = true,