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:
@@ -97,6 +97,54 @@ test "ProgramIndex declaration maps round-trip (A1.1b)" {
|
||||
try std.testing.expectEqualStrings("list_len", idx.ufcs_alias_map.get("len").?);
|
||||
}
|
||||
|
||||
// E0 (R5 §#4): the source-keyed caches partition by declaring source, so the
|
||||
// SAME name authored in two different modules lands two DISTINCT entries under
|
||||
// two source keys — never last-wins. The legacy global maps stay single-keyed
|
||||
// by name (one entry per name), so the compat readers are untouched.
|
||||
test "ProgramIndex source-keyed caches partition same-name authors by source" {
|
||||
var idx = ProgramIndex.init(std.testing.allocator);
|
||||
defer idx.deinit();
|
||||
|
||||
var blk_a = ast.Node{ .span = .{ .start = 0, .end = 0 }, .data = .{ .block = .{ .stmts = &.{} } } };
|
||||
var blk_b = ast.Node{ .span = .{ .start = 1, .end = 1 }, .data = .{ .block = .{ .stmts = &.{} } } };
|
||||
|
||||
// SAME alias name `Foo` authored in two modules → two distinct TypeIds.
|
||||
idx.putTypeAliasBySource("a.sx", "Foo", .s64);
|
||||
idx.putTypeAliasBySource("b.sx", "Foo", .f64);
|
||||
try std.testing.expectEqual(@as(?types.TypeId, .s64), idx.type_aliases_by_source.get("a.sx").?.get("Foo"));
|
||||
try std.testing.expectEqual(@as(?types.TypeId, .f64), idx.type_aliases_by_source.get("b.sx").?.get("Foo"));
|
||||
try std.testing.expectEqual(@as(u32, 2), idx.type_aliases_by_source.count());
|
||||
|
||||
// SAME const name `K` authored in two modules → two distinct ModuleConstInfos.
|
||||
idx.putModuleConstBySource("a.sx", "K", .{ .value = &blk_a, .ty = .s32 });
|
||||
idx.putModuleConstBySource("b.sx", "K", .{ .value = &blk_b, .ty = .f32 });
|
||||
try std.testing.expect(idx.module_consts_by_source.get("a.sx").?.get("K").?.value == &blk_a);
|
||||
try std.testing.expect(idx.module_consts_by_source.get("b.sx").?.get("K").?.value == &blk_b);
|
||||
try std.testing.expectEqual(@as(?types.TypeId, .s32), idx.module_consts_by_source.get("a.sx").?.get("K").?.ty);
|
||||
try std.testing.expectEqual(@as(?types.TypeId, .f32), idx.module_consts_by_source.get("b.sx").?.get("K").?.ty);
|
||||
|
||||
// SAME global name `g` authored in two modules → two distinct GlobalInfos.
|
||||
idx.putGlobalBySource("a.sx", "g", .{ .id = inst.GlobalId.fromIndex(0), .ty = .s64 });
|
||||
idx.putGlobalBySource("b.sx", "g", .{ .id = inst.GlobalId.fromIndex(1), .ty = .f64 });
|
||||
try std.testing.expect(idx.globals_by_source.get("a.sx").?.get("g").?.id == inst.GlobalId.fromIndex(0));
|
||||
try std.testing.expect(idx.globals_by_source.get("b.sx").?.get("g").?.id == inst.GlobalId.fromIndex(1));
|
||||
|
||||
// Compat readers: the legacy global maps stay keyed by NAME alone, so a
|
||||
// same-name author is last-wins there — exactly ONE entry for `Foo` / `K`,
|
||||
// unchanged by the source-keyed writes above.
|
||||
idx.type_alias_map.put("Foo", .s64) catch unreachable;
|
||||
idx.type_alias_map.put("Foo", .f64) catch unreachable;
|
||||
try std.testing.expectEqual(@as(u32, 1), idx.type_alias_map.count());
|
||||
idx.module_const_map.put("K", .{ .value = &blk_a, .ty = .s32 }) catch unreachable;
|
||||
idx.module_const_map.put("K", .{ .value = &blk_b, .ty = .f32 }) catch unreachable;
|
||||
try std.testing.expectEqual(@as(u32, 1), idx.module_const_map.count());
|
||||
|
||||
// removeModuleConstBySource drops only the named entry under its source.
|
||||
idx.removeModuleConstBySource("a.sx", "K");
|
||||
try std.testing.expect(idx.module_consts_by_source.get("a.sx").?.get("K") == null);
|
||||
try std.testing.expect(idx.module_consts_by_source.get("b.sx").?.get("K").?.value == &blk_b);
|
||||
}
|
||||
|
||||
/// Stand-in for the leaf-name lookup both array-dimension resolvers pass to the
|
||||
/// shared `evalConstIntExpr`: `M`/`N` resolve to integers, everything else is
|
||||
/// genuinely non-comptime.
|
||||
|
||||
Reference in New Issue
Block a user