Commit Graph

3 Commits

Author SHA1 Message Date
agra
cd39316f5e fix(ir): evaluate constant-expression array dimensions (0083)
A constant-FOLDABLE expression array dimension (`[M + 1]`, `[M * N]`,
`[N - M]`, nested `[M + N - 1]`, parenthesised `[(M + 1) * 2]`, mixing
untyped and typed module consts) was wrongly rejected as "not a
compile-time integer constant" even though every operand is
compile-time-known. Attempts 1-3 resolved only a bare named-const dim or
a literal; an expression dim must be EVALUATED, not rejected.

Fix: the shared dim resolver now routes the dimension through a single
constant integer-expression evaluator (`program_index.evalConstIntExpr`)
that folds integer `+ - * / %` and unary negate over literals and
named/typed module consts, recursively (parentheses carry no AST node).
The leaf-name lookup is delegated via `ctx.lookupDimName`, so the
stateful body-lowering path (`Lowering`, which also sees comptime
constants and generic `$N` values) and the stateless registration path
(`type_bridge.StatelessInner`, module consts only) share the EXACT SAME
folding logic and cannot diverge — an expression dim via a type alias
resolves identically to the direct form.

No-fabrication discipline unchanged: a genuinely non-comptime dimension
(runtime local, non-comptime call, unbound name) or arithmetic that
overflows / divides by zero still yields null -> `.unresolved` -> the
same clean compile-halting diagnostic, never a fabricated length.

- examples/0144-types-const-expr-array-dim.sx: every expression form,
  direct vs alias, scalar / string / struct element types (fails on the
  pre-fix compiler, passes after).
- examples/1129 re-pointed at a genuinely non-const dimension
  (`[get()]s64`, a runtime call) so it still proves the stateless
  clean-halt (a foldable expression is no longer an error).
- program_index.test.zig: unit test for evalConstIntExpr folding and
  clean-halt-on-non-const.
2026-06-04 10:38:21 +03:00
agra
fb262e9e59 refactor(ir): move declaration maps into ProgramIndex (A1.1b)
Architecture phase A1.1b — mechanical storage relocation. Move the 9
declaration-fact maps out of the Lowering state bag into ProgramIndex:

  high-fanout:   fn_ast_map, foreign_class_map, global_names, type_alias_map
  medium-fanout: struct_template_map, protocol_decl_map, protocol_ast_map,
                 module_const_map, ufcs_alias_map

168 self.<map> sites in lower.zig repointed to self.program_index.<map>;
external readers repointed too (core.zig foreign_class_map iteration;
lower.test.zig fn_ast_map / foreign_class_map). No duplicate storage, no
fallback path; zig build enforces no missed reference.

The four maps whose value types were Lowering-private pull those types into
program_index.zig as pub (GlobalInfo, StructTemplate + TemplateParam,
ProtocolDeclInfo + ProtocolMethodInfo, ModuleConstInfo); lower.zig aliases
them at file scope so call sites are unchanged.

Behavior is preserved exactly:
- per-map allocator unchanged — import_flags/fn_ast_map/global_names use the
  lowering allocator (ProgramIndex.init), the other 7 keep their page_allocator
  inline defaults;
- ProgramIndex.deinit frees only the 10 owned maps, never the borrowed
  module_scopes / import_graph;
- TypeTable.aliases still borrows &self.program_index.type_alias_map, loaned at
  lowerRoot with the same late-binding lifetime.

Extends program_index.test.zig with declaration-map round-trips (fn AST, type
alias, global, module const, foreign class, protocol decl/AST, struct template,
ufcs alias).

Registration logic (registerStructDecl / registerProtocolDecl /
registerForeignClassDecl, ...) stays in Lowering, writing through the index.

Gate green: zig build, zig build test, bash tests/run_examples.sh
(350 passed, 0 failed). lower.zig 19433 -> 19393 lines.
2026-06-02 12:30:11 +03:00
agra
90520eefeb 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.
2026-06-02 12:04:31 +03:00