feat(resolver): source-keyed alias/const/global caches, write-side only [stdlib E0]
Phase E0 of the unified resolver (R5 §#4): add the source-partitioned
analogues of the global `type_alias_map` / `module_const_map` /
`global_names`, keyed `source path -> name -> X`, and POPULATE them from
the existing scan. Purely additive and behavior-preserving — the global
maps remain the ONLY readers; the read-side cutover to
`selectedAuthor.source` is E1.
ProgramIndex:
- type_aliases_by_source / module_consts_by_source / globals_by_source
(StringHashMap of inner StringHashMap), owned + freed on deinit.
- put{TypeAlias,ModuleConst,Global}BySource + removeModuleConstBySource
helpers; retain `module.alloc` to lazily create inner per-source maps.
lower.zig scan: every global `type_alias_map`/`module_const_map`/
`global_names` write (and each module_const_map.remove) now mirrors into
its by-source analogue, keyed by the registering decl's source
(decl.source_file / current_source_file), the analogue of module_fns.
Tests:
- program_index.test.zig: same alias/const/global name under two sources
lands two distinct entries (not last-wins); compat globals stay
single-keyed; removeModuleConstBySource scoped to its source.
- lower.test.zig: end-to-end two-source namespace fixture — the scan
populates the by-source caches per declaring source while the global
maps stay single-keyed by name.
Gate: zig build + zig build test (423, incl. 2 new) + run_examples
(477, byte-identical) + m3te ios-sim build, all exit 0.
This commit is contained in:
@@ -581,6 +581,11 @@ pub const GlobalInfo = struct { id: inst.GlobalId, ty: TypeId };
|
||||
/// (set in `init`); the rest default to `page_allocator`. Written only by the
|
||||
/// declaration scan / registration code in `Lowering`; read everywhere else.
|
||||
pub const ProgramIndex = struct {
|
||||
/// The lowering/compilation allocator (`module.alloc`), retained so the
|
||||
/// source-keyed caches below can lazily create their inner per-source maps.
|
||||
/// Lives for the whole compilation; the inner maps are freed in `deinit`.
|
||||
alloc: std.mem.Allocator,
|
||||
|
||||
// ── Import / visibility ──
|
||||
/// Declaration name → is the function imported (declared `extern`)?
|
||||
import_flags: std.StringHashMap(bool),
|
||||
@@ -637,12 +642,30 @@ pub const ProgramIndex = struct {
|
||||
/// UFCS alias name → target function name.
|
||||
ufcs_alias_map: std.StringHashMap([]const u8) = std.StringHashMap([]const u8).init(std.heap.page_allocator),
|
||||
|
||||
// ── Source-keyed semantic caches (R5 §#4) ──
|
||||
// The source-partitioned analogues of `type_alias_map` / `module_const_map`
|
||||
// / `global_names`, keyed `source path → name → X`. Written by the same scan
|
||||
// (`scanDecls` in lower.zig), keyed by the registering decl's source. The
|
||||
// global maps above stay the ONLY readers for now; the read-side cutover to
|
||||
// `selectedAuthor.source` lands in a later phase. These maps OWN their inner
|
||||
// per-source maps and free them in `deinit`.
|
||||
/// Type alias name → target TypeId, partitioned by declaring source.
|
||||
type_aliases_by_source: std.StringHashMap(std.StringHashMap(TypeId)),
|
||||
/// Module-level value const → info, partitioned by declaring source.
|
||||
module_consts_by_source: std.StringHashMap(std.StringHashMap(ModuleConstInfo)),
|
||||
/// `#run` / top-level global name → GlobalInfo, partitioned by declaring source.
|
||||
globals_by_source: std.StringHashMap(std.StringHashMap(GlobalInfo)),
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator) ProgramIndex {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.import_flags = std.StringHashMap(bool).init(alloc),
|
||||
.fn_ast_map = std.StringHashMap(*const ast.FnDecl).init(alloc),
|
||||
.qualified_fn_source = std.StringHashMap([]const u8).init(alloc),
|
||||
.global_names = std.StringHashMap(GlobalInfo).init(alloc),
|
||||
.type_aliases_by_source = std.StringHashMap(std.StringHashMap(TypeId)).init(alloc),
|
||||
.module_consts_by_source = std.StringHashMap(std.StringHashMap(ModuleConstInfo)).init(alloc),
|
||||
.globals_by_source = std.StringHashMap(std.StringHashMap(GlobalInfo)).init(alloc),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -660,5 +683,42 @@ pub const ProgramIndex = struct {
|
||||
self.protocol_ast_map.deinit();
|
||||
self.module_const_map.deinit();
|
||||
self.ufcs_alias_map.deinit();
|
||||
deinitBySource(TypeId, &self.type_aliases_by_source);
|
||||
deinitBySource(ModuleConstInfo, &self.module_consts_by_source);
|
||||
deinitBySource(GlobalInfo, &self.globals_by_source);
|
||||
}
|
||||
|
||||
/// Free every inner per-source map, then the outer map.
|
||||
fn deinitBySource(comptime V: type, outer: *std.StringHashMap(std.StringHashMap(V))) void {
|
||||
var it = outer.valueIterator();
|
||||
while (it.next()) |inner| inner.deinit();
|
||||
outer.deinit();
|
||||
}
|
||||
|
||||
/// Insert `name → value` into the per-source map for `source`, creating the
|
||||
/// inner map on first use. OOM is swallowed to mirror the `catch {}` global
|
||||
/// writes this shadows.
|
||||
fn putBySource(comptime V: type, outer: *std.StringHashMap(std.StringHashMap(V)), alloc: std.mem.Allocator, source: []const u8, name: []const u8, value: V) void {
|
||||
const gop = outer.getOrPut(source) catch return;
|
||||
if (!gop.found_existing) gop.value_ptr.* = std.StringHashMap(V).init(alloc);
|
||||
gop.value_ptr.put(name, value) catch {};
|
||||
}
|
||||
|
||||
pub fn putTypeAliasBySource(self: *ProgramIndex, source: []const u8, name: []const u8, tid: TypeId) void {
|
||||
putBySource(TypeId, &self.type_aliases_by_source, self.alloc, source, name, tid);
|
||||
}
|
||||
|
||||
pub fn putModuleConstBySource(self: *ProgramIndex, source: []const u8, name: []const u8, info: ModuleConstInfo) void {
|
||||
putBySource(ModuleConstInfo, &self.module_consts_by_source, self.alloc, source, name, info);
|
||||
}
|
||||
|
||||
pub fn putGlobalBySource(self: *ProgramIndex, source: []const u8, name: []const u8, info: GlobalInfo) void {
|
||||
putBySource(GlobalInfo, &self.globals_by_source, self.alloc, source, name, info);
|
||||
}
|
||||
|
||||
/// Mirror a `module_const_map.remove` into the per-source map: drop `name`
|
||||
/// from `source`'s inner map (a no-op if the source/name is absent).
|
||||
pub fn removeModuleConstBySource(self: *ProgramIndex, source: []const u8, name: []const u8) void {
|
||||
if (self.module_consts_by_source.getPtr(source)) |inner| _ = inner.remove(name);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user