feat(stdlib/S1.1): DeclId for every declaration — additive DeclTable [additive]
Build a DeclTable in parallel with the import facts: every RawDeclRef (source / imported / namespaced / C-imported) gets a stable DeclId carrying source path, display name, AST node identity, span, and DeclKind. Namespace targets record their members' DeclIds (NamespaceTarget.member_ids). A generic struct's template is keyed by DeclId in a parallel struct_template_by_decl store, written alongside the live name-keyed struct_template_map. A Debug-only round-trip cross-check (RawDeclRef -> DeclId -> AST node ptr) asserts the table identifies the same node across the corpus, run from buildDeclTable and pinned by a unit test. Additive (S0.1 class: mirror): the old maps stay active and lowering still consumes them; nothing reads the DeclTable / struct_template_by_decl for selection yet (the S4 cutover does). Generated IR + output bytes are unchanged by construction. Gate over the baseline-green corpus: zig build, zig build test (424/424), bash tests/run_examples.sh (540 passed) — all exit 0; single-author output byte-identical (37 .ir snapshots unchanged).
This commit is contained in:
12
src/core.zig
12
src/core.zig
@@ -38,6 +38,10 @@ pub const Compilation = struct {
|
||||
/// Namespace import edges (`importer → alias → NamespaceTarget`), built by
|
||||
/// `imports.buildImportFacts`. Borrowed by `ProgramIndex.namespace_edges`.
|
||||
namespace_edges: imports.NamespaceEdges,
|
||||
/// Stable `DeclId` for every declaration (Fork C S1), built by
|
||||
/// `imports.buildDeclTable` in parallel with the import facts. Borrowed by
|
||||
/// `ProgramIndex.decl_table`.
|
||||
decl_table: imports.DeclTable,
|
||||
ir_emitter: ?ir.LLVMEmitter = null,
|
||||
/// Lowered IR module, kept alive past `generateCode` so post-link
|
||||
/// callbacks can re-enter the interpreter to invoke sx functions
|
||||
@@ -68,6 +72,7 @@ pub const Compilation = struct {
|
||||
.module_fns = imports.ModuleFns.init(allocator),
|
||||
.module_decls = imports.ModuleDecls.init(allocator),
|
||||
.namespace_edges = imports.NamespaceEdges.init(allocator),
|
||||
.decl_table = imports.DeclTable.init(allocator),
|
||||
.target_config = target_config,
|
||||
.stdlib_paths = stdlib_paths,
|
||||
};
|
||||
@@ -143,6 +148,12 @@ pub const Compilation = struct {
|
||||
self.module_decls = facts.decls;
|
||||
self.namespace_edges = facts.ns_edges;
|
||||
|
||||
// DeclTable (Fork C S1): a stable DeclId for every declaration, built in
|
||||
// parallel from the SAME modules. Additive — nothing consumes it for
|
||||
// selection yet, so generated IR + bytes are unchanged. Updates
|
||||
// `namespace_edges` in place to record each target's member ids.
|
||||
self.decl_table = try imports.buildDeclTable(self.allocator, self.file_path, mod, &cache, &self.module_decls, &self.namespace_edges);
|
||||
|
||||
// Store main file source in import_sources so error reporting can find it
|
||||
self.import_sources.put(self.file_path, self.source) catch {};
|
||||
|
||||
@@ -312,6 +323,7 @@ pub const Compilation = struct {
|
||||
lowering.program_index.module_fns = &self.module_fns;
|
||||
lowering.program_index.module_decls = &self.module_decls;
|
||||
lowering.program_index.namespace_edges = &self.namespace_edges;
|
||||
lowering.program_index.decl_table = &self.decl_table;
|
||||
lowering.lowerRoot(root);
|
||||
if (self.diagnostics.hasErrors()) return error.CompileError;
|
||||
|
||||
|
||||
@@ -503,3 +503,103 @@ test "buildImportFacts: namespace-alias-then-fn same-module collision is diagnos
|
||||
const m_idx = facts.decls.get(main_path) orelse return error.MissingMainIndex;
|
||||
try expectTag(m_idx.names.get("dup") orelse return error.MissingDup, .namespace_decl);
|
||||
}
|
||||
|
||||
// ── DeclTable unit tests (Fork C S1.1) ──
|
||||
|
||||
// Every source / imported / namespaced declaration gets a stable DeclId; the
|
||||
// RawDeclRef → DeclId → AST node round-trip holds; a generic struct is keyable
|
||||
// by DeclId; and the namespace target records its members' ids. The OLD facts
|
||||
// (`module_decls` / `ns_edges`) are untouched — the table is built in parallel.
|
||||
test "buildDeclTable: stable DeclId per decl, round-trip, struct keying, namespace member ids" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
const io = testIo();
|
||||
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
|
||||
try tmp.dir.writeFile(io, .{ .sub_path = "lib.sx", .data = "helper :: () -> s64 { 9 }\nBox :: struct($T: Type) { v: T; }\n" });
|
||||
try tmp.dir.writeFile(io, .{ .sub_path = "geom.sx", .data = "Point :: struct { x: s64 }\n" });
|
||||
try tmp.dir.writeFile(io, .{ .sub_path = "main.sx", .data = "#import \"lib.sx\";\ng :: #import \"geom.sx\";\nmain :: () -> s32 { 0 }\n" });
|
||||
|
||||
var dirbuf: [4096]u8 = undefined;
|
||||
const absdir = dirbuf[0..try tmp.dir.realPath(io, &dirbuf)];
|
||||
const main_path = try std.fmt.allocPrint(alloc, "{s}/main.sx", .{absdir});
|
||||
const lib_path = try std.fmt.allocPrint(alloc, "{s}/lib.sx", .{absdir});
|
||||
|
||||
const main_bytes = try std.Io.Dir.readFileAlloc(.cwd(), io, main_path, alloc, .limited(1 << 20));
|
||||
const main_source = try alloc.dupeZ(u8, main_bytes);
|
||||
var p = parser.Parser.init(alloc, main_source);
|
||||
const root = p.parse() catch return error.ParseFailed;
|
||||
|
||||
var diags = errors.DiagnosticList.init(alloc, main_source, main_path);
|
||||
var chain = std.StringHashMap(void).init(alloc);
|
||||
var cache = imports.ModuleCache.init(alloc);
|
||||
var import_graph = std.StringHashMap(std.StringHashMap(void)).init(alloc);
|
||||
var flat_import_graph = std.StringHashMap(std.StringHashMap(void)).init(alloc);
|
||||
const stdlib_paths = [_][]const u8{};
|
||||
|
||||
const mod = try imports.resolveImports(
|
||||
alloc,
|
||||
io,
|
||||
root,
|
||||
absdir,
|
||||
main_path,
|
||||
&chain,
|
||||
&cache,
|
||||
null,
|
||||
&diags,
|
||||
&stdlib_paths,
|
||||
&import_graph,
|
||||
&flat_import_graph,
|
||||
.{},
|
||||
);
|
||||
|
||||
var facts = try imports.buildImportFacts(alloc, main_path, mod, &cache);
|
||||
var table = try imports.buildDeclTable(alloc, main_path, mod, &cache, &facts.decls, &facts.ns_edges);
|
||||
defer table.deinit();
|
||||
|
||||
// Every module author resolves to a DeclId that round-trips to the same node
|
||||
// and carries the matching name + source. (verifyRoundTrip also asserts this
|
||||
// in Debug; this pins the public lookup API too.)
|
||||
var mit = facts.decls.iterator();
|
||||
var seen: usize = 0;
|
||||
while (mit.next()) |m| {
|
||||
var nit = m.value_ptr.names.iterator();
|
||||
while (nit.next()) |kv| {
|
||||
const ref = kv.value_ptr.*;
|
||||
const id = table.declIdForRef(ref) orelse return error.MissingDeclId;
|
||||
const info = table.get(id);
|
||||
try std.testing.expectEqual(imports.authorNodePtrOf(ref), imports.authorNodePtrOf(info.ref));
|
||||
try std.testing.expectEqualStrings(kv.key_ptr.*, info.name);
|
||||
try std.testing.expectEqualStrings(m.value_ptr.source, info.source);
|
||||
seen += 1;
|
||||
}
|
||||
}
|
||||
try std.testing.expect(seen > 0);
|
||||
|
||||
// The generic struct `Box` (authored in lib.sx) is keyable by DeclId via its
|
||||
// inner *StructDecl, and the id reports DeclKind.@"struct" + name "Box".
|
||||
const lib_idx = facts.decls.get(lib_path) orelse return error.MissingLibIndex;
|
||||
const box_ref = lib_idx.names.get("Box") orelse return error.MissingBox;
|
||||
const box_sd = switch (box_ref) {
|
||||
.struct_decl => |sd| sd,
|
||||
.const_decl => |cd| if (cd.value.data == .struct_decl) &cd.value.data.struct_decl else return error.BoxNotStruct,
|
||||
else => return error.BoxNotStruct,
|
||||
};
|
||||
const box_id = table.declIdForStructDecl(box_sd) orelse return error.BoxNoDeclId;
|
||||
try std.testing.expectEqual(imports.DeclKind.@"struct", table.get(box_id).kind);
|
||||
try std.testing.expectEqualStrings("Box", table.get(box_id).name);
|
||||
|
||||
// The namespaced `geom.sx` target records its members' DeclIds (here: Point),
|
||||
// each round-tripping to a DeclInfo named "Point".
|
||||
const aliases = facts.ns_edges.get(main_path) orelse return error.MissingNsEdges;
|
||||
const target = aliases.get("g") orelse return error.MissingAlias;
|
||||
try std.testing.expect(target.member_ids.len >= 1);
|
||||
var found_point = false;
|
||||
for (target.member_ids) |id| {
|
||||
if (std.mem.eql(u8, table.get(id).name, "Point")) found_point = true;
|
||||
}
|
||||
try std.testing.expect(found_point);
|
||||
}
|
||||
|
||||
214
src/imports.zig
214
src/imports.zig
@@ -537,6 +537,10 @@ pub const NamespaceTarget = struct {
|
||||
target_module_path: []const u8,
|
||||
own_decls: []const *Node,
|
||||
is_pub: bool = false,
|
||||
/// The `DeclId` of each member in `own_decls`, in slice order. Filled by
|
||||
/// `buildDeclTable` (empty until then). Lets a member be addressed by stable
|
||||
/// id without re-deriving it from the node pointer.
|
||||
member_ids: []const DeclId = &.{},
|
||||
};
|
||||
|
||||
/// `importer_source → alias → NamespaceTarget`.
|
||||
@@ -615,6 +619,216 @@ pub fn buildImportFacts(
|
||||
return .{ .decls = decls, .ns_edges = ns_edges };
|
||||
}
|
||||
|
||||
// ── DeclTable: a stable DeclId for every declaration (Fork C S1, additive) ──
|
||||
//
|
||||
// `buildDeclTable` lifts every `RawDeclRef` the import facts hold into a stable
|
||||
// `DeclId` carrying source + name + AST node identity + span + `DeclKind`. It is
|
||||
// built in PARALLEL with the old maps and nothing in lowering consumes it for
|
||||
// selection yet (S4 makes it the fact-store key), so generated IR + bytes are
|
||||
// unchanged by construction.
|
||||
|
||||
/// The taxonomy of a declaration, mirroring the `RawDeclRef` variants so a
|
||||
/// `DeclTable` row carries its kind without re-switching on the AST node.
|
||||
pub const DeclKind = enum {
|
||||
function,
|
||||
constant,
|
||||
@"struct",
|
||||
@"enum",
|
||||
@"union",
|
||||
error_set,
|
||||
protocol,
|
||||
foreign_class,
|
||||
namespace,
|
||||
};
|
||||
|
||||
fn declKindOf(ref: RawDeclRef) DeclKind {
|
||||
return switch (ref) {
|
||||
.fn_decl => .function,
|
||||
.const_decl => .constant,
|
||||
.struct_decl => .@"struct",
|
||||
.enum_decl => .@"enum",
|
||||
.union_decl => .@"union",
|
||||
.error_set_decl => .error_set,
|
||||
.protocol_decl => .protocol,
|
||||
.foreign_class_decl => .foreign_class,
|
||||
.namespace_decl => .namespace,
|
||||
};
|
||||
}
|
||||
|
||||
/// The AST node identity a `RawDeclRef` wraps — the inner decl pointer every
|
||||
/// variant holds (the same identity `resolver.zig` selects authors by). This is
|
||||
/// the key the `DeclTable` indexes and round-trips on.
|
||||
pub fn authorNodePtrOf(ref: RawDeclRef) usize {
|
||||
return switch (ref) {
|
||||
inline else => |p| @intFromPtr(p),
|
||||
};
|
||||
}
|
||||
|
||||
/// The `*const ast.StructDecl` a top-level decl node carries, or null when it is
|
||||
/// not a struct — a bare `struct_decl` or a `const_decl` whose value is one,
|
||||
/// both unwrapping to the same inner decl (mirrors lower's `structDeclOfRaw`).
|
||||
fn structDeclPtrOf(decl: *const Node) ?*const ast.StructDecl {
|
||||
return switch (decl.data) {
|
||||
.struct_decl => &decl.data.struct_decl,
|
||||
.const_decl => |cd| if (cd.value.data == .struct_decl) &cd.value.data.struct_decl else null,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// A stable identifier for one declaration, assigned by `DeclTable` in module-
|
||||
/// walk order. Process-local: it indexes the table's `entries` (S5 stabilizes it
|
||||
/// to `(source, index)` for the LSP, per the deep-dive's R5).
|
||||
pub const DeclId = enum(u32) { _ };
|
||||
|
||||
/// One `DeclTable` row: a `RawDeclRef` lifted to a stable `DeclId`, with its
|
||||
/// authoring source path, display name, AST span, and `DeclKind`. `ref` is the
|
||||
/// same raw author the import facts hold (its AST node identity is `id`'s key).
|
||||
pub const DeclInfo = struct {
|
||||
id: DeclId,
|
||||
source: []const u8,
|
||||
name: []const u8,
|
||||
ref: RawDeclRef,
|
||||
span: ast.Span,
|
||||
kind: DeclKind,
|
||||
};
|
||||
|
||||
/// Stable `DeclId` for every source / namespaced / imported / C-imported decl.
|
||||
/// `entries` is indexed by `DeclId`; `by_node` reverse-maps the AST node
|
||||
/// identity (`authorNodePtrOf`) to its id; `by_struct` maps a generic struct's
|
||||
/// inner `*StructDecl` to its id (so a template registered during lowering can
|
||||
/// be keyed by `DeclId`). Borrowed by `ProgramIndex.decl_table`.
|
||||
pub const DeclTable = struct {
|
||||
alloc: std.mem.Allocator,
|
||||
entries: std.ArrayList(DeclInfo) = .empty,
|
||||
by_node: std.AutoHashMap(usize, DeclId),
|
||||
by_struct: std.AutoHashMap(usize, DeclId),
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator) DeclTable {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.by_node = std.AutoHashMap(usize, DeclId).init(alloc),
|
||||
.by_struct = std.AutoHashMap(usize, DeclId).init(alloc),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *DeclTable) void {
|
||||
self.entries.deinit(self.alloc);
|
||||
self.by_node.deinit();
|
||||
self.by_struct.deinit();
|
||||
}
|
||||
|
||||
pub fn get(self: *const DeclTable, id: DeclId) DeclInfo {
|
||||
return self.entries.items[@intFromEnum(id)];
|
||||
}
|
||||
|
||||
/// The `DeclId` for an AST node (by its `RawDeclRef` identity), or null when
|
||||
/// the node never entered the table.
|
||||
pub fn declIdForRef(self: *const DeclTable, ref: RawDeclRef) ?DeclId {
|
||||
return self.by_node.get(authorNodePtrOf(ref));
|
||||
}
|
||||
|
||||
/// The `DeclId` for a generic struct template's inner `*StructDecl`, or null.
|
||||
pub fn declIdForStructDecl(self: *const DeclTable, sd: *const ast.StructDecl) ?DeclId {
|
||||
return self.by_struct.get(@intFromPtr(sd));
|
||||
}
|
||||
|
||||
/// Intern one top-level decl node, returning its (possibly pre-existing)
|
||||
/// `DeclId`. First-wins / diamond dedup by node identity, matching how the
|
||||
/// scalar import facts dedup. The caller guarantees `rawDeclRefOf(decl)` is
|
||||
/// non-null (so `declName` is too).
|
||||
fn intern(self: *DeclTable, source: []const u8, decl: *const Node) !DeclId {
|
||||
const ref = rawDeclRefOf(decl).?;
|
||||
const key = authorNodePtrOf(ref);
|
||||
if (self.by_node.get(key)) |existing| return existing;
|
||||
const id: DeclId = @enumFromInt(@as(u32, @intCast(self.entries.items.len)));
|
||||
try self.entries.append(self.alloc, .{
|
||||
.id = id,
|
||||
.source = source,
|
||||
.name = decl.data.declName().?,
|
||||
.ref = ref,
|
||||
.span = decl.span,
|
||||
.kind = declKindOf(ref),
|
||||
});
|
||||
try self.by_node.put(key, id);
|
||||
if (structDeclPtrOf(decl)) |sd| try self.by_struct.put(@intFromPtr(sd), id);
|
||||
return id;
|
||||
}
|
||||
|
||||
fn internModule(self: *DeclTable, source: []const u8, own_decls: []const *Node) !void {
|
||||
for (own_decls) |decl| {
|
||||
if (rawDeclRefOf(decl) == null) continue;
|
||||
_ = try self.intern(source, decl);
|
||||
}
|
||||
}
|
||||
|
||||
/// Debug cross-check (S1.1 acceptance): every `RawDeclRef` the import facts
|
||||
/// hold round-trips `RawDeclRef → DeclId → AST node ptr` back to the same
|
||||
/// node, with matching name. Asserts; call only under `builtin.mode == .Debug`.
|
||||
pub fn verifyRoundTrip(self: *const DeclTable, decls: *const ModuleDecls, ns_edges: *const NamespaceEdges) void {
|
||||
var mit = decls.iterator();
|
||||
while (mit.next()) |m| {
|
||||
var nit = m.value_ptr.names.iterator();
|
||||
while (nit.next()) |kv| {
|
||||
const ref = kv.value_ptr.*;
|
||||
const id = self.declIdForRef(ref) orelse @panic("DeclTable round-trip: module ref has no DeclId");
|
||||
const info = self.get(id);
|
||||
std.debug.assert(authorNodePtrOf(info.ref) == authorNodePtrOf(ref));
|
||||
std.debug.assert(std.mem.eql(u8, info.name, kv.key_ptr.*));
|
||||
}
|
||||
}
|
||||
var nsit = ns_edges.iterator();
|
||||
while (nsit.next()) |imp| {
|
||||
var ait = imp.value_ptr.valueIterator();
|
||||
while (ait.next()) |target| {
|
||||
for (target.own_decls) |decl| {
|
||||
const ref = rawDeclRefOf(decl) orelse continue;
|
||||
const id = self.declIdForRef(ref) orelse @panic("DeclTable round-trip: ns member has no DeclId");
|
||||
std.debug.assert(authorNodePtrOf(self.get(id).ref) == authorNodePtrOf(ref));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Build the `DeclTable` from the resolved program + the import facts: every
|
||||
/// module author (main + cache) interned first, then every namespace member
|
||||
/// (reusing the module author's id when it is also a module decl, minting a new
|
||||
/// id for a synthetic C-import member). `ns_edges` is updated in place so each
|
||||
/// `NamespaceTarget.member_ids` lists its members' ids. Built from the SAME
|
||||
/// modules `buildImportFacts` walks; no IR lowering required.
|
||||
pub fn buildDeclTable(
|
||||
allocator: std.mem.Allocator,
|
||||
main_path: []const u8,
|
||||
main_mod: ResolvedModule,
|
||||
cache: *const ModuleCache,
|
||||
decls: *const ModuleDecls,
|
||||
ns_edges: *NamespaceEdges,
|
||||
) !DeclTable {
|
||||
var table = DeclTable.init(allocator);
|
||||
try table.internModule(main_path, main_mod.own_decls);
|
||||
var it = cache.iterator();
|
||||
while (it.next()) |entry| {
|
||||
try table.internModule(entry.key_ptr.*, entry.value_ptr.own_decls);
|
||||
}
|
||||
|
||||
var nsit = ns_edges.iterator();
|
||||
while (nsit.next()) |imp| {
|
||||
var ait = imp.value_ptr.valueIterator();
|
||||
while (ait.next()) |target| {
|
||||
var ids = std.ArrayList(DeclId).empty;
|
||||
for (target.own_decls) |decl| {
|
||||
if (rawDeclRefOf(decl) == null) continue;
|
||||
const id = try table.intern(target.target_module_path, decl);
|
||||
try ids.append(allocator, id);
|
||||
}
|
||||
target.member_ids = try ids.toOwnedSlice(allocator);
|
||||
}
|
||||
}
|
||||
|
||||
if (builtin.mode == .Debug) table.verifyRoundTrip(decls, ns_edges);
|
||||
return table;
|
||||
}
|
||||
|
||||
/// Surface a same-module duplicate top-level declaration as a hard error at an
|
||||
/// explicit name + span. `addOwnDecl` / `addNamespace` return `false` when the
|
||||
/// name is already in this module's scope and drop the second author; without
|
||||
|
||||
@@ -15487,6 +15487,17 @@ pub const Lowering = struct {
|
||||
const tmpl = self.buildGenericStructTemplate(sd, source_file) orelse return;
|
||||
self.program_index.struct_template_map.put(tmpl.name, tmpl) catch {};
|
||||
|
||||
// S1.1 (additive): key the template by DeclId in parallel. Nothing
|
||||
// reads this for selection yet; `struct_template_map` stays the live
|
||||
// consumer. A template whose decl is not in the table (comptime /
|
||||
// block-local registration with facts unwired) keeps only the
|
||||
// name-keyed entry.
|
||||
if (self.program_index.decl_table) |dt| {
|
||||
if (dt.declIdForStructDecl(sd)) |id| {
|
||||
self.program_index.struct_template_by_decl.put(id, tmpl) catch {};
|
||||
}
|
||||
}
|
||||
|
||||
// Register methods under "TemplateName.method" in fn_ast_map
|
||||
for (sd.methods) |method_node| {
|
||||
if (method_node.data == .fn_decl) {
|
||||
|
||||
@@ -628,6 +628,10 @@ pub const ProgramIndex = struct {
|
||||
/// `imports.buildImportFacts`, carrying each alias's resolved target path.
|
||||
/// Borrowed view.
|
||||
namespace_edges: ?*imports.NamespaceEdges = null,
|
||||
/// Stable `DeclId` for every declaration, built by `imports.buildDeclTable`
|
||||
/// in parallel with the import facts. Borrowed view; nothing in lowering
|
||||
/// consumes it for selection yet (additive — S4 makes it the fact-store key).
|
||||
decl_table: ?*imports.DeclTable = null,
|
||||
|
||||
// ── Declaration maps ──
|
||||
/// Function name → AST decl.
|
||||
@@ -649,6 +653,11 @@ pub const ProgramIndex = struct {
|
||||
type_alias_map: std.StringHashMap(TypeId) = std.StringHashMap(TypeId).init(std.heap.page_allocator),
|
||||
/// Generic struct name → template.
|
||||
struct_template_map: std.StringHashMap(StructTemplate) = std.StringHashMap(StructTemplate).init(std.heap.page_allocator),
|
||||
/// `DeclId` → generic struct template — the DeclId-keyed analogue of
|
||||
/// `struct_template_map`, built in parallel during `registerStructDecl`.
|
||||
/// Nothing reads it for selection yet; `struct_template_map` stays the live
|
||||
/// consumer until the S4 cutover.
|
||||
struct_template_by_decl: std.AutoHashMap(imports.DeclId, StructTemplate) = std.AutoHashMap(imports.DeclId, StructTemplate).init(std.heap.page_allocator),
|
||||
/// Protocol name → protocol info.
|
||||
protocol_decl_map: std.StringHashMap(ProtocolDeclInfo) = std.StringHashMap(ProtocolDeclInfo).init(std.heap.page_allocator),
|
||||
/// Protocol name → AST node.
|
||||
@@ -687,7 +696,7 @@ pub const ProgramIndex = struct {
|
||||
|
||||
pub fn deinit(self: *ProgramIndex) void {
|
||||
// Owned maps only — module_scopes / import_graph / flat_import_graph /
|
||||
// module_fns / module_decls / namespace_edges are borrowed.
|
||||
// module_fns / module_decls / namespace_edges / decl_table are borrowed.
|
||||
self.import_flags.deinit();
|
||||
self.fn_ast_map.deinit();
|
||||
self.qualified_fn_source.deinit();
|
||||
@@ -695,6 +704,7 @@ pub const ProgramIndex = struct {
|
||||
self.global_names.deinit();
|
||||
self.type_alias_map.deinit();
|
||||
self.struct_template_map.deinit();
|
||||
self.struct_template_by_decl.deinit();
|
||||
self.protocol_decl_map.deinit();
|
||||
self.protocol_ast_map.deinit();
|
||||
self.module_const_map.deinit();
|
||||
|
||||
Reference in New Issue
Block a user