fix(KB-9): move Lowering/ProgramIndex maps off page_allocator defaults
16 Lowering map fields and 8 ProgramIndex map fields were declared with `= ....init(std.heap.page_allocator)` field defaults that init() never replaced — every instance really allocated page-at-a-time outside the compilation allocator, invisible to leak checking and never reclaimed. All 24 now init explicitly with the compilation allocator (module.alloc / the init alloc param), which is arena-backed in both the driver (main's arena) and the test suites (per-test arenas), so backing is reclaimed at teardown. ProgramIndex's struct doc no longer claims the page_allocator defaults. Six lower.test.zig tests that constructed Module with bare std.testing.allocator leaked once the checker could finally see these maps; they now use the same per-test ArenaAllocator idiom as the rest of the file and the facade test suites. Gate: zig build OK; zig build test 426/426 (6/6 steps, leak-clean); run_examples 541/0; zero expected/ snapshot churn.
This commit is contained in:
@@ -464,7 +464,9 @@ test "lower: objcDefinedStateStructType skips non-field members" {
|
||||
}
|
||||
|
||||
test "lower: objcTypeEncodingFromSignature emits @ for Obj-C class pointers" {
|
||||
const alloc = std.testing.allocator;
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
var module = ir_mod.Module.init(alloc);
|
||||
defer module.deinit();
|
||||
var lowering = Lowering.init(&module);
|
||||
@@ -496,7 +498,9 @@ test "lower: objcTypeEncodingFromSignature emits @ for Obj-C class pointers" {
|
||||
}
|
||||
|
||||
test "lower: objcTypeEncodingFromSignature unwraps optional to wire type" {
|
||||
const alloc = std.testing.allocator;
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
var module = ir_mod.Module.init(alloc);
|
||||
defer module.deinit();
|
||||
var lowering = Lowering.init(&module);
|
||||
@@ -663,7 +667,9 @@ test "lower: deriveObjcSelector — niladic / keyword / multi-keyword / override
|
||||
}
|
||||
|
||||
test "lower: isObjcClassPointer recognises pointer-to-foreign-Obj-C-class" {
|
||||
const alloc = std.testing.allocator;
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
var module = ir_mod.Module.init(alloc);
|
||||
defer module.deinit();
|
||||
var lowering = Lowering.init(&module);
|
||||
@@ -710,7 +716,9 @@ test "lower: isObjcClassPointer recognises pointer-to-foreign-Obj-C-class" {
|
||||
}
|
||||
|
||||
test "lower: objcPropertyKind defaults + explicit ARC modifiers" {
|
||||
const alloc = std.testing.allocator;
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
var module = ir_mod.Module.init(alloc);
|
||||
defer module.deinit();
|
||||
var lowering = Lowering.init(&module);
|
||||
@@ -783,7 +791,9 @@ fn protoMethod(name: []const u8) ast.ProtocolMethodDecl {
|
||||
}
|
||||
|
||||
test "pack projection: type-arg vs method namespace lookups" {
|
||||
const alloc = std.testing.allocator;
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
var module = ir_mod.Module.init(alloc);
|
||||
defer module.deinit();
|
||||
var lowering = Lowering.init(&module);
|
||||
@@ -808,7 +818,9 @@ test "pack projection: type-arg vs method namespace lookups" {
|
||||
}
|
||||
|
||||
test "pack projection: position-driven resolution (Decision 4)" {
|
||||
const alloc = std.testing.allocator;
|
||||
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
var module = ir_mod.Module.init(alloc);
|
||||
defer module.deinit();
|
||||
var lowering = Lowering.init(&module);
|
||||
|
||||
@@ -288,21 +288,21 @@ pub const Lowering = struct {
|
||||
/// visible ONLY within the source that declares it: an imported template's field
|
||||
/// resolution (run in the template's source context, E3 attempt-4) must NOT bind a
|
||||
/// name the CALLER declared block-local (E3 attempt-5).
|
||||
local_type_names: std.StringHashMap(std.StringHashMap(void)) = std.StringHashMap(std.StringHashMap(void)).init(std.heap.page_allocator),
|
||||
struct_defaults_map: std.StringHashMap([]const ?*const Node) = std.StringHashMap([]const ?*const Node).init(std.heap.page_allocator), // struct name → field defaults
|
||||
struct_instance_bindings: std.StringHashMap(std.StringHashMap(TypeId)) = std.StringHashMap(std.StringHashMap(TypeId)).init(std.heap.page_allocator), // mangled struct name → type param bindings
|
||||
struct_instance_template: std.StringHashMap([]const u8) = std.StringHashMap([]const u8).init(std.heap.page_allocator), // mangled struct name → template name
|
||||
struct_instance_author: std.StringHashMap(*const ast.StructDecl) = std.StringHashMap(*const ast.StructDecl).init(std.heap.page_allocator), // mangled struct name → authoring StructDecl (CP-2: body-author ≡ layout-author)
|
||||
local_type_names: std.StringHashMap(std.StringHashMap(void)),
|
||||
struct_defaults_map: std.StringHashMap([]const ?*const Node), // struct name → field defaults
|
||||
struct_instance_bindings: std.StringHashMap(std.StringHashMap(TypeId)), // mangled struct name → type param bindings
|
||||
struct_instance_template: std.StringHashMap([]const u8), // mangled struct name → template name
|
||||
struct_instance_author: std.StringHashMap(*const ast.StructDecl), // mangled struct name → authoring StructDecl (CP-2: body-author ≡ layout-author)
|
||||
comptime_value_bindings: ?std.StringHashMap(i64) = null, // comptime value bindings ($N → integer value)
|
||||
protocol_thunk_map: std.StringHashMap([]const FuncId) = std.StringHashMap([]const FuncId).init(std.heap.page_allocator), // "Proto\x00Type" → thunk FuncIds
|
||||
protocol_vtable_type_map: std.StringHashMap(TypeId) = std.StringHashMap(TypeId).init(std.heap.page_allocator), // protocol name → vtable struct TypeId
|
||||
protocol_vtable_global_map: std.StringHashMap(inst_mod.GlobalId) = std.StringHashMap(inst_mod.GlobalId).init(std.heap.page_allocator), // "Proto\x00Type" → vtable GlobalId
|
||||
param_impl_map: std.StringHashMap(std.ArrayList(ParamImplEntry)) = std.StringHashMap(std.ArrayList(ParamImplEntry)).init(std.heap.page_allocator), // "Proto\x00<arg_mangled>\x00<src_mangled>" → impl entries (parameterised protocols only; list lets Phase 4/5 detect cross-module overlap)
|
||||
protocol_thunk_map: std.StringHashMap([]const FuncId), // "Proto\x00Type" → thunk FuncIds
|
||||
protocol_vtable_type_map: std.StringHashMap(TypeId), // protocol name → vtable struct TypeId
|
||||
protocol_vtable_global_map: std.StringHashMap(inst_mod.GlobalId), // "Proto\x00Type" → vtable GlobalId
|
||||
param_impl_map: std.StringHashMap(std.ArrayList(ParamImplEntry)), // "Proto\x00<arg_mangled>\x00<src_mangled>" → impl entries (parameterised protocols only; list lets Phase 4/5 detect cross-module overlap)
|
||||
/// Pack-variadic impl entries — separate map keyed by `"Proto\x00<arg_mangled>"`
|
||||
/// (NO source suffix) so a single impl `Closure(..$args) -> $R` can be
|
||||
/// matched against many concrete source shapes. Concrete impls in
|
||||
/// `param_impl_map` win when both match (specificity rule).
|
||||
param_impl_pack_map: std.StringHashMap(std.ArrayList(PackParamImplEntry)) = std.StringHashMap(std.ArrayList(PackParamImplEntry)).init(std.heap.page_allocator),
|
||||
param_impl_pack_map: std.StringHashMap(std.ArrayList(PackParamImplEntry)),
|
||||
/// Active pack bindings during monomorphisation. Mirrors `type_bindings`
|
||||
/// but for variadic pack names: `args → [T1, T2, ...]`. Read by
|
||||
/// `resolveTypeWithBindings` on closure_type_expr to substitute
|
||||
@@ -346,26 +346,26 @@ pub const Lowering = struct {
|
||||
/// `xs[i].<m>` is rejected unless `<m>` is one of the protocol's methods.
|
||||
/// Null / absent for the comptime `..$args` pack (no constraint).
|
||||
pack_constraint: ?std.StringHashMap([]const u8) = null,
|
||||
struct_const_map: std.StringHashMap(StructConstInfo) = std.StringHashMap(StructConstInfo).init(std.heap.page_allocator), // "Struct.CONST" → value info
|
||||
foreign_name_map: std.StringHashMap([]const u8) = std.StringHashMap([]const u8).init(std.heap.page_allocator), // sx name → C name for #foreign renames
|
||||
struct_const_map: std.StringHashMap(StructConstInfo), // "Struct.CONST" → value info
|
||||
foreign_name_map: std.StringHashMap([]const u8), // sx name → C name for #foreign renames
|
||||
target_config: ?@import("../target.zig").TargetConfig = null, // compilation target (for inline if)
|
||||
comptime_constants: std.StringHashMap(ComptimeValue) = std.StringHashMap(ComptimeValue).init(std.heap.page_allocator), // compile-time known constants (e.g. OS, ARCH)
|
||||
comptime_constants: std.StringHashMap(ComptimeValue), // compile-time known constants (e.g. OS, ARCH)
|
||||
diagnostics: ?*errors.DiagnosticList = null, // error reporting with source locations
|
||||
xx_reentrancy: std.AutoHashMap(u64, void) = std.AutoHashMap(u64, void).init(std.heap.page_allocator), // (src_ty, dst_ty) pairs currently being resolved through user-space Into; prevents infinite monomorphisation when a convert body re-enters the same xx
|
||||
xx_reentrancy: std.AutoHashMap(u64, void), // (src_ty, dst_ty) pairs currently being resolved through user-space Into; prevents infinite monomorphisation when a convert body re-enters the same xx
|
||||
/// Whole-program-converged inferred error sets (ERR E1.4b): top-level
|
||||
/// bare-`!` function name → its sorted escape-tag ids (literal raises +
|
||||
/// pure-failable `try` edges, fix-pointed across the call graph). The
|
||||
/// shared `!` placeholder TypeId stays empty; this side map holds the real
|
||||
/// per-function sets (sidesteps the name-only error-set interning). Read by
|
||||
/// `lowerTry`'s named-caller widening and the empty-inferred warning.
|
||||
inferred_error_sets: std.StringHashMap([]const u32) = std.StringHashMap([]const u32).init(std.heap.page_allocator),
|
||||
inferred_error_sets: std.StringHashMap([]const u32),
|
||||
/// Whole-program-converged inferred error sets keyed by closure/function
|
||||
/// VALUE-signature shape (ERR E5.1 sub-feature 2): every occurrence of
|
||||
/// `Closure(<sig>) -> (T, !)` with a structurally identical value-signature
|
||||
/// shares one node; each bare-`!` closure literal of that shape unions its
|
||||
/// escape tags in. Read by `checkEscapeWidening` when a `try` operand is a
|
||||
/// closure/fn-type SLOT call (no static fn name). Key = `closureShapeKey`.
|
||||
shape_inferred_sets: std.StringHashMap([]const u32) = std.StringHashMap([]const u32).init(std.heap.page_allocator),
|
||||
shape_inferred_sets: std.StringHashMap([]const u32),
|
||||
|
||||
pub const ComptimeValue = union(enum) {
|
||||
int_val: i64,
|
||||
@@ -496,6 +496,22 @@ pub const Lowering = struct {
|
||||
.fn_decl_fids = std.AutoHashMap(*const ast.FnDecl, FuncId).init(module.alloc),
|
||||
.lowered_fids = std.AutoHashMap(FuncId, void).init(module.alloc),
|
||||
.nominal_name_authors = std.AutoHashMap(types.StringId, []const u8).init(module.alloc),
|
||||
.local_type_names = std.StringHashMap(std.StringHashMap(void)).init(module.alloc),
|
||||
.struct_defaults_map = std.StringHashMap([]const ?*const Node).init(module.alloc),
|
||||
.struct_instance_bindings = std.StringHashMap(std.StringHashMap(TypeId)).init(module.alloc),
|
||||
.struct_instance_template = std.StringHashMap([]const u8).init(module.alloc),
|
||||
.struct_instance_author = std.StringHashMap(*const ast.StructDecl).init(module.alloc),
|
||||
.protocol_thunk_map = std.StringHashMap([]const FuncId).init(module.alloc),
|
||||
.protocol_vtable_type_map = std.StringHashMap(TypeId).init(module.alloc),
|
||||
.protocol_vtable_global_map = std.StringHashMap(inst_mod.GlobalId).init(module.alloc),
|
||||
.param_impl_map = std.StringHashMap(std.ArrayList(ParamImplEntry)).init(module.alloc),
|
||||
.param_impl_pack_map = std.StringHashMap(std.ArrayList(PackParamImplEntry)).init(module.alloc),
|
||||
.struct_const_map = std.StringHashMap(StructConstInfo).init(module.alloc),
|
||||
.foreign_name_map = std.StringHashMap([]const u8).init(module.alloc),
|
||||
.comptime_constants = std.StringHashMap(ComptimeValue).init(module.alloc),
|
||||
.xx_reentrancy = std.AutoHashMap(u64, void).init(module.alloc),
|
||||
.inferred_error_sets = std.StringHashMap([]const u32).init(module.alloc),
|
||||
.shape_inferred_sets = std.StringHashMap([]const u32).init(module.alloc),
|
||||
.program_index = ProgramIndex.init(module.alloc),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -592,9 +592,9 @@ pub const GlobalInfo = struct { id: inst.GlobalId, ty: TypeId };
|
||||
/// (pointers into maps owned by the compilation driver, `core.zig`) — those are
|
||||
/// read-only views and are never freed here.
|
||||
///
|
||||
/// Per-map allocators are preserved exactly as they were on `Lowering`:
|
||||
/// `import_flags` / `fn_ast_map` / `global_names` use the lowering allocator
|
||||
/// (set in `init`); the rest default to `page_allocator`. Written only by the
|
||||
/// Every owned map allocates through the compilation allocator passed to
|
||||
/// `init` (arena-backed in both the driver and the tests — KB-9 removed the
|
||||
/// old `page_allocator` field defaults). 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
|
||||
@@ -639,27 +639,27 @@ pub const ProgramIndex = struct {
|
||||
/// resolve (issue 0100 F1). Keyed/allocated with the lowering allocator.
|
||||
qualified_fn_source: std.StringHashMap([]const u8),
|
||||
/// sx alias → ForeignClassDecl (jni_class / objc_class / swift_class / ... — registered in scan pass).
|
||||
foreign_class_map: std.StringHashMap(*const ast.ForeignClassDecl) = std.StringHashMap(*const ast.ForeignClassDecl).init(std.heap.page_allocator),
|
||||
foreign_class_map: std.StringHashMap(*const ast.ForeignClassDecl),
|
||||
/// `#run` global name → GlobalId.
|
||||
global_names: std.StringHashMap(GlobalInfo),
|
||||
/// Type alias name → target TypeId. The single-source alias table; passed
|
||||
/// explicitly to `TypeResolver` / `type_bridge` resolution (no borrow).
|
||||
type_alias_map: std.StringHashMap(TypeId) = std.StringHashMap(TypeId).init(std.heap.page_allocator),
|
||||
type_alias_map: std.StringHashMap(TypeId),
|
||||
/// Generic struct name → template.
|
||||
struct_template_map: std.StringHashMap(StructTemplate) = std.StringHashMap(StructTemplate).init(std.heap.page_allocator),
|
||||
struct_template_map: std.StringHashMap(StructTemplate),
|
||||
/// `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),
|
||||
struct_template_by_decl: std.AutoHashMap(imports.DeclId, StructTemplate),
|
||||
/// Protocol name → protocol info.
|
||||
protocol_decl_map: std.StringHashMap(ProtocolDeclInfo) = std.StringHashMap(ProtocolDeclInfo).init(std.heap.page_allocator),
|
||||
protocol_decl_map: std.StringHashMap(ProtocolDeclInfo),
|
||||
/// Protocol name → AST node.
|
||||
protocol_ast_map: std.StringHashMap(*const ast.ProtocolDecl) = std.StringHashMap(*const ast.ProtocolDecl).init(std.heap.page_allocator),
|
||||
protocol_ast_map: std.StringHashMap(*const ast.ProtocolDecl),
|
||||
/// Module-level value constants (e.g. AF_INET :s32: 2).
|
||||
module_const_map: std.StringHashMap(ModuleConstInfo) = std.StringHashMap(ModuleConstInfo).init(std.heap.page_allocator),
|
||||
module_const_map: std.StringHashMap(ModuleConstInfo),
|
||||
/// UFCS alias name → target function name.
|
||||
ufcs_alias_map: std.StringHashMap([]const u8) = std.StringHashMap([]const u8).init(std.heap.page_allocator),
|
||||
ufcs_alias_map: std.StringHashMap([]const u8),
|
||||
|
||||
// ── Source-keyed semantic caches (R5 §#4) ──
|
||||
// The source-partitioned analogues of `type_alias_map` / `module_const_map`
|
||||
@@ -682,6 +682,14 @@ pub const ProgramIndex = struct {
|
||||
.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),
|
||||
.foreign_class_map = std.StringHashMap(*const ast.ForeignClassDecl).init(alloc),
|
||||
.type_alias_map = std.StringHashMap(TypeId).init(alloc),
|
||||
.struct_template_map = std.StringHashMap(StructTemplate).init(alloc),
|
||||
.struct_template_by_decl = std.AutoHashMap(imports.DeclId, StructTemplate).init(alloc),
|
||||
.protocol_decl_map = std.StringHashMap(ProtocolDeclInfo).init(alloc),
|
||||
.protocol_ast_map = std.StringHashMap(*const ast.ProtocolDecl).init(alloc),
|
||||
.module_const_map = std.StringHashMap(ModuleConstInfo).init(alloc),
|
||||
.ufcs_alias_map = std.StringHashMap([]const u8).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),
|
||||
|
||||
Reference in New Issue
Block a user