diff --git a/src/ir/lower.test.zig b/src/ir/lower.test.zig index c135187..4010820 100644 --- a/src/ir/lower.test.zig +++ b/src/ir/lower.test.zig @@ -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); diff --git a/src/ir/lower.zig b/src/ir/lower.zig index 6590ce4..d292c28 100644 --- a/src/ir/lower.zig +++ b/src/ir/lower.zig @@ -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\x00" → 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\x00" → impl entries (parameterised protocols only; list lets Phase 4/5 detect cross-module overlap) /// Pack-variadic impl entries — separate map keyed by `"Proto\x00"` /// (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].` is rejected unless `` 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() -> (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), }; } diff --git a/src/ir/program_index.zig b/src/ir/program_index.zig index 1d4b90d..a5efd7e 100644 --- a/src/ir/program_index.zig +++ b/src/ir/program_index.zig @@ -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),