From 65c27e8e6612b8d649ae1481c27c8e7f0e78ad32 Mon Sep 17 00:00:00 2001 From: Matthew Borkowski Date: Wed, 20 Oct 2021 02:34:51 -0400 Subject: [PATCH] astgen.zig: delay adding closure_capture instructions to preserve GenZir nesting. Only containers create Namespaces, so the declaring_gz is always the GenZir passed to containerDecl, and containerDecl will always add exactly one instruction (an extended *_decl) to that GenZir. Thus, closure_capture instructions are always lined up immediately after a container decl instruction, so rather than adding them at the point of first mention, where we're nested arbitrarily deep, simply walk through the Namespace captures hash map at the end of each containerDecl branch and add them then. --- src/AstGen.zig | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/AstGen.zig b/src/AstGen.zig index 06dc88d231c812b41ecdc8c27cee479b4e8ff065..c0f8538194f7da91d903ace82511858dacb37385 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -3850,6 +3850,7 @@ fn structDeclInner( astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); astgen.extra.appendSliceAssumeCapacity(fields_slice); + try gz.addNamespaceCaptures(&namespace); return indexToRef(decl_inst); } @@ -3993,6 +3994,7 @@ fn unionDeclInner( astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); astgen.extra.appendSliceAssumeCapacity(fields_slice); + try gz.addNamespaceCaptures(&namespace); return indexToRef(decl_inst); } @@ -4234,6 +4236,7 @@ fn containerDecl( astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); astgen.extra.appendSliceAssumeCapacity(fields_slice); + try gz.addNamespaceCaptures(&namespace); return rvalue(gz, rl, indexToRef(decl_inst), node); }, .keyword_opaque => { @@ -4268,6 +4271,7 @@ fn containerDecl( try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len); astgen.extra.appendSliceAssumeCapacity(decls_slice); + try gz.addNamespaceCaptures(&namespace); return rvalue(gz, rl, indexToRef(decl_inst), node); }, else => unreachable, @@ -6108,9 +6112,15 @@ fn tunnelThroughClosure( // already has one for this value. const gop = try ns.?.captures.getOrPut(gpa, refToIndex(value).?); if (!gop.found_existing) { - // Make a new capture for this value - const capture_ref = try ns.?.declaring_gz.?.addUnTok(.closure_capture, value, token); - gop.value_ptr.* = refToIndex(capture_ref).?; + // Make a new capture for this value but don't add it to the declaring_gz yet + try gz.astgen.instructions.append(gz.astgen.gpa, .{ + .tag = .closure_capture, + .data = .{ .un_tok = .{ + .operand = value, + .src_tok = ns.?.declaring_gz.?.tokenIndexToRelative(token), + } }, + }); + gop.value_ptr.* = @intCast(Zir.Inst.Index, gz.astgen.instructions.len - 1); } // Add an instruction to get the value from the closure into @@ -8736,7 +8746,7 @@ const Scope = struct { /// Map from the raw captured value to the instruction /// ref of the capture for decls in this namespace - captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, + captures: std.AutoArrayHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, pub fn deinit(self: *Namespace, gpa: *Allocator) void { self.decls.deinit(gpa); @@ -9876,6 +9886,15 @@ const GenZir = struct { else => unreachable, } } + + fn addNamespaceCaptures(gz: *GenZir, namespace: *Scope.Namespace) !void { + if (namespace.captures.count() > 0) { + try gz.instructions.ensureUnusedCapacity(gz.astgen.gpa, namespace.captures.count()); + for (namespace.captures.values()) |capture| { + gz.instructions.appendAssumeCapacity(capture); + } + } + } }; /// This can only be for short-lived references; the memory becomes invalidated -- 2.54.0