refactor(ir): extract ProgramIndex, move low-fanout decl facts (A1.1a)
Architecture phase A1.1a. Introduce src/ir/program_index.zig as the single storage owner for declaration-name / import / visibility facts, and move the three low-fanout maps out of the Lowering state bag: - import_flags (owned by ProgramIndex) - module_scopes (borrowed pointer into a core.zig-owned map) - import_graph (borrowed pointer into a core.zig-owned map) Lowering embeds one ProgramIndex by value and reaches every moved fact through self.program_index.<field>; later phases hand collaborator modules a *ProgramIndex instead of *Lowering. 8 call sites in lower.zig + 2 setters in core.zig repointed. No duplicate storage, no fallback path; zig build enforces no missed reference. Mutation-heavy registration (registerStructDecl etc.) stays in Lowering and now writes import_flags through the index. High-fanout maps are deferred to A1.1b. Adds src/ir/program_index.test.zig (init-empty, import_flags round-trip, borrowed-view ownership) wired into the ir.zig barrel. Behavior-preserving: zig build, zig build test, and bash tests/run_examples.sh (350 passed, 0 failed) all green.
This commit is contained in:
40
src/ir/program_index.test.zig
Normal file
40
src/ir/program_index.test.zig
Normal file
@@ -0,0 +1,40 @@
|
||||
const std = @import("std");
|
||||
const ProgramIndex = @import("program_index.zig").ProgramIndex;
|
||||
|
||||
test "ProgramIndex.init starts empty with unset borrowed views" {
|
||||
var idx = ProgramIndex.init(std.testing.allocator);
|
||||
defer idx.deinit();
|
||||
try std.testing.expectEqual(@as(u32, 0), idx.import_flags.count());
|
||||
try std.testing.expect(idx.module_scopes == null);
|
||||
try std.testing.expect(idx.import_graph == null);
|
||||
}
|
||||
|
||||
test "ProgramIndex.import_flags round-trips imported vs local" {
|
||||
var idx = ProgramIndex.init(std.testing.allocator);
|
||||
defer idx.deinit();
|
||||
try idx.import_flags.put("printf", true);
|
||||
try idx.import_flags.put("main", false);
|
||||
try std.testing.expectEqual(@as(?bool, true), idx.import_flags.get("printf"));
|
||||
try std.testing.expectEqual(@as(?bool, false), idx.import_flags.get("main"));
|
||||
try std.testing.expect(idx.import_flags.get("absent") == null);
|
||||
}
|
||||
|
||||
test "ProgramIndex borrows module_scopes / import_graph without owning them" {
|
||||
const ScopeSet = std.StringHashMap(std.StringHashMap(void));
|
||||
var scopes = ScopeSet.init(std.testing.allocator);
|
||||
defer scopes.deinit();
|
||||
var graph = ScopeSet.init(std.testing.allocator);
|
||||
defer graph.deinit();
|
||||
|
||||
var idx = ProgramIndex.init(std.testing.allocator);
|
||||
defer idx.deinit();
|
||||
idx.module_scopes = &scopes;
|
||||
idx.import_graph = &graph;
|
||||
|
||||
// Reads go through the borrowed pointer; the backing stays caller-owned,
|
||||
// so idx.deinit() must not free it (testing.allocator would flag a
|
||||
// double-free / leak otherwise).
|
||||
try std.testing.expect(idx.module_scopes.? == &scopes);
|
||||
try std.testing.expect(idx.import_graph.? == &graph);
|
||||
try std.testing.expectEqual(@as(u32, 0), idx.module_scopes.?.count());
|
||||
}
|
||||
Reference in New Issue
Block a user