Commit Graph

16 Commits

Author SHA1 Message Date
agra
18af8eb845 comptime-API: strip the byte-weld; pivot to a flat-memory comptime VM
The byte-weld (sx structs whose layout was validated to mirror the
compiler's Zig records) plus the serialization/marshaling bridge was the
wrong direction: it bolted a parallel layout regime and hand-built
byte-copies onto a comptime value model that fundamentally isn't bytes.

Strip the struct-weld machinery:
- compiler_lib.zig loses the type registry (weldStruct / bound_types /
  BoundType / FieldLayout / findType / SxField / LayoutMismatch /
  validateStructLayout); it is now just the intern/text_of function
  host-call bridge (kept as the Phase-3 compiler-call seed).
- nominal.zig loses validateWeldedStruct / weldedFieldOrderStr + the
  sd.abi == .zig validation call.
- Remove the struct-weld unit tests and examples 0625/0627 (welded
  structs) + 1183/1186 (weld-layout diagnostics).
- The #library / abi / extern syntax stays.

Record the new direction: a bytecode VM over flat, byte-addressable
memory so comptime values are native bytes (no weld/validation/marshal),
target-aware (preserves cross-compilation) and sandboxed. See
current/PLAN-COMPILER-VM.md (Phase 0 strip -> Phase 1 flat-memory value
model -> Phase 2 bytecode -> Phase 3 compiler-API on flat memory).
design/comptime-compiler-api.md gets a SUPERSEDED banner. Also drop the
"~500 lines / split the step" rule from CLAUDE.md.
2026-06-17 19:29:36 +03:00
agra
40d075ca98 compiler-API: welded structs by reflection + memory-order validation
Replace the explored byte-layout-override engine (offset-ordered LLVM structs /
weld plans / byte-blobs — all unnecessary) with a much simpler design: a welded
`struct abi(.zig) extern compiler { … }` is a bodied header declaring its fields
in the bound compiler type's MEMORY order. The compiler reflects the real Zig
type (field names via @typeInfo, offsets via @offsetOf, size via @sizeOf —
nothing hand-maintained) and validates the header matches, with loud diagnostics.

On pass it is an ordinary struct whose natural layout already equals the Zig
layout — no reorder, no padding, no index/remap tables, no special LLVM path — so
@ptrCast'ing it to the compiler's own type and dereferencing is byte-identical.
When types.zig shifts, the header stops matching and the developer gets a specific
message to fix it.

- compiler_lib.zig: weldStruct reflects field names and bakes bound_types fields
  in ascending-offset (memory) order; deleted computeWeldPlan/WeldPlan/WeldElement.
- nominal.zig validateWeldedStruct: precise diagnostics — field-not-found,
  wrong-field-order (+ expected memory order), type-layout (size) mismatch,
  total-size mismatch.
- Examples: 0627 (StructInfo in memory order, byte-identical, usable),
  1186 (source-order StructInfo -> wrong-field-order diagnostic); 1183 refreshed.
- Design doc + checkpoint updated.
2026-06-17 15:45:23 +03:00
agra
cd5b958d19 comptime compiler-API: Phase 1 foundation + Phase 2.1 weld plan
Introduce the welded comptime `compiler` library (`#library "compiler"` +
`abi(.zig) extern compiler`), per design/comptime-compiler-api.md, and unify
`callconv(...)` into the new `abi(...)` annotation.

abi(...) replaces callconv(...):
- New ABI enum { default, c, zig, pure }; `abi(.c|.zig|.pure)` parses in the
  postfix slot before extern/export (and standalone). `kw_callconv` -> `kw_abi`.
- Migrated 52 sx files, the call-convention-mismatch diagnostic, and docs
  (readme/specs) from `callconv(.c)` to `abi(.c)`.

Phase 1 — welded compiler library (parse -> registry -> validation -> bridge):
- `abi(.zig) extern compiler` parses on fn decls (carries abi/extern_lib) and
  struct decls (StructDecl.abi/extern_lib).
- `#library "compiler"` is the comptime-only internal surface — never dlopen'd.
- src/ir/compiler_lib.zig: the binding registry (the safety boundary). `Field`
  welded to StructInfo.Field with layout baked from the real Zig type
  (@offsetOf/@sizeOf); `findType`/`findFn`. Welded structs are layout-validated
  at registration (field set + total size) as a header checked against the impl.
- Host-call bridge: a `fn abi(.zig) extern compiler` dispatches under the
  comptime interp to its registered Zig handler (intern/text_of round-trip),
  never dlsym. IR Function.compiler_welded; validated in declareFunction.
- Comptime-only enforcement: a runtime call to a welded fn is a clean
  build-gating error (emitCall), not an undefined-symbol link failure.

Phase 2.1 — byte-layout weld foundation:
- Decision: full byte-layout weld (sx struct laid out byte-identically to the
  bound Zig type). Registered StructInfo (first non-natural / Zig-reordered
  layout). `computeWeldPlan` — pure offset-ordered element plan + padding +
  sx-field->LLVM-element remap; unit-tested. Emit/interp wiring is the next
  sub-step (2.2+, see current/CHECKPOINT-COMPILER-API.md).

Examples: 0625/0626 (welded struct + fn round-trip), 1183/1184/1185
(layout-mismatch, unexported-fn, runtime-call diagnostics).
2026-06-17 13:31:11 +03:00
agra
8ae655687a green(reify): type-fn bodies comptime-evaluated; reify fully removed from the compiler
Second slice of the re-architecture — the compiler now has ZERO type-
construction code beyond declare/define.

- instantiateTypeFunction: a type-fn body returning a computed Type (a call
  to a non-generic, bodied, Type-returning fn) is comptime-evaluated with the
  type bindings active, then renamed to the mangled instantiation name for
  identity (renameNominalType). Replaces the old reify-call pattern-matching.
- DELETED: reifyType (lower/nominal.zig), findReturnReifyCall (lower/generic.zig),
  and the stale inline-position reify gate in resolveTypeCallWithBindings.
- evalComptimeType (was evalComptimeTypeNamed): pure eval, no rename; the
  type-fn caller renames explicitly. renameReifiedType → renameNominalType.
- The TYPE NAME now travels in the data: EnumInfo gains `name`, and define()
  names the slot from it (the compiler derives no name from a binding LHS).
  examples/0614/0615 carry `name = "..."`; RecvResult/TryResult set it too.
- field_type stays a reflection #builtin (reads a type); only construction
  moved out. All reify mentions stripped from compiler source.

examples 0614/0615/0617 run on the floor. Full suite green (673).
2026-06-16 21:03:16 +03:00
agra
353109206b green(reify): implement reify(.enum) — mint a flat enum from TypeInfo
REIFY Phase 0.2 (Phase 0 complete). Lowering.reifyType (lower/nominal.zig)
reads the flat-enum TypeInfo literal off the AST, synthesizes an
ast.EnumDecl, and feeds it through the SAME type_bridge.buildEnumInfo
path source enums use — so the minted type is byte-identical to a
hand-written `enum { value: i64; closed; }` and flows through enum
codegen (layout / construct / match) UNMODIFIED (Contract 2).

Wired at the `E :: reify(...)` const-decl hook in lower/decl.zig
(replacing the Phase-0.0 loud bail). Unsupported argument shapes bail
loudly via reifyBail — never a silent default. The generic.zig inline
reify path now reports it's only supported in a `::` binding (Phase 0).

examples/0614 green: reify a {value: i64, closed} enum, construct
.value(3) and .closed, match both -> "value 3" / "closed". Full suite
green (670 examples, 447 unit).
2026-06-16 18:32:05 +03:00
agra
dc51c4b5bf refactor(ffi-linkage): Phase 9.3-src — purge 'foreign' from src/ comments + a user-facing diagnostic
Reword every 'foreign' comment to the extern/runtime-class vocabulary matching the
renamed identifiers (foreign call→extern call, foreign class→runtime class, foreign
path→runtime path, the #foreign-literal comment mentions → extern, etc.). Also fixes
two USER-FACING issues: the 'expected … #foreign … after type annotation' parse error
no longer advertises the removed keyword, and the Android 'no #jni_main' help
diagnostic now shows '#jni_class(…) extern' instead of the rejected '#foreign
#jni_class'. Removed the now-dead prefix-#foreign-vs-postfix conflict branch in
parseRuntimeClassDecl (the caller rejects #foreign before it runs).

src/ now contains 'foreign' ONLY in the hash_foreign token machinery + its 4
rejection messages — the deprecation mechanism (kept per the 9.0 recommendation; the
message MUST name #foreign to guide migration). Snapshot-neutral; suite green
(646 corpus / 444 unit, 0 failed).
2026-06-15 09:35:00 +03:00
agra
5c8af6eb73 refactor(ffi-linkage): Phase 9.2b — rename runtime-class fns + state → runtime_* / is_reference
The runtime-class object-model identifiers (Decision 5): parse/lower/find/resolve/
register/stamp fns Foreign→Runtime (parseRuntimeClassDecl, lowerRuntimeMethodCall,
findRuntimeMethodInChain, resolveRuntimeMethodReturnType, registerRuntimeClassDecl,
runtimeClassStructType, runtimeKindForOffset, …); state foreign_class_map→
runtime_class_map, current_foreign_class/_method→current_runtime_*, the
foreign_class_decl union variant→runtime_class_decl, foreign_method/static/instance/
class→runtime_*; and the reference-vs-define flag is_foreign→is_reference (+
is_foreign_eff→is_reference_eff) now that it only lives on RuntimeClassDecl.
Snapshot-neutral; suite green (646/444).

Remaining 9.2: the foreign_path family (coupled .sx hooks: jni_main_foreign_path_at
spans build.sx/bundle.sx/compiler_hooks.zig/specs.md) + the extern-ref validators
(checkForeignRefs etc. → Extern, linkage not runtime) + bare 'foreign' comments.
2026-06-15 09:01:04 +03:00
agra
f13f4abfb1 fix: visibility-aware type-name resolution at registration time
Enum payloads, union fields, inline struct/enum/union field types, and
named error-set references now resolve through the visibility-aware
`inner` recursion hook (the same seam `resolveCompound` uses) instead of
the flat `findByName`. A bare type name in any of these positions now
selects the querying module's OWN author over a same-name namespaced
import -- the own-wins rule already applied to top-level named references
and struct fields.

- buildEnumInfo / buildUnionInfo / resolveInlineEnum / resolveInlineStruct
  / resolveInlineUnion / resolveErrorType take the `inner: anytype` seam;
  registerEnumDecl / registerUnionDecl and the struct-const annotation
  pass `self` (visibility-aware); resolveAstType passes the stateless `si`.
- resolveTypeWithBindings routes inline type decls and named error refs
  through `self` instead of delegating to flat resolveAstType.

Regression tests: examples/0781 (top-level enum payload over a namespaced
import), examples/0784 (inline struct field). Addresses issue 0132's
broader latent class; the protocol-return case (0132 primary) is a
separate registerProtocolDecl fix and stays open. The error-set reference
path is in place but dormant pending error-set per-decl nominal identity
(issue 0134).
2026-06-13 13:41:11 +03:00
agra
d8076b9333 lang: rename signed integer types sN -> iN
Surface rename of the signed integer family: s1..s64 become i1..i64
(u1..u64, usize, isize unchanged). 'string' keeps the s-prefix arm in
name classification; width parsing moves to the i-prefix arm next to
isize.

Internal TypeId tags follow the surface (.s8/.s16/.s32/.s64 ->
.i8/.i16/.i32/.i64), as do mono-key mangle fragments (ptr_i64,
tu_i64_bool) and all display/diagnostic formatting (i{d}).

Migrated in the same sweep: stdlib + examples + issue repros + FFI C
companions (shared symbol names like ffi_id_i64), expected
stdout/stderr/ir snapshots, specs.md, readme.md, CLAUDE.md/AGENTS.md,
implementation_plan.md, docs/, issue writeups. Vendored stb_image and
historical flow state left untouched.

zig build test: 426/426; examples suite: 595/595.
2026-06-12 09:31:53 +03:00
agra
721369a711 lang: fn aliases dispatch like their target (fix 0121) — scan-time registration through the shared alias-chain walk
Renamed fn aliases failed for EVERY kind (the filed pack-only scope was
a same-name confound: same-name re-exports already resolved through the
name-keyed fn_ast_map). scanDecls now follows ident-/ns.X-RHS const
alias chains (aliasedFnDecl; 0120's hop walk extracted as
followAliasChain) and registers the alias name in fn_ast_map
(absent-only), so every dispatch path — early pack/comptime/generic,
plain lazy-lower, plan-side typing — sees the target decl unchanged.
my_print :: s.print; / my_format :: s.format; now work (the std.sx
re-export shape). Regression: examples/0546 (+rich). Gates: zig build
test 0, suite 588/588.
2026-06-11 18:47:16 +03:00
agra
f2db8ecc53 lang: generic struct head aliases bind the template (fix 0120) — alias-follow from each author's source in head selection; loud unknown-type on the .call type tail
BoxAlias :: Box; / Box :: r.Box; now resolve instantiation, methods,
annotations, and chains through the aliased template, and re-export one
flat-import level as ordinary own decls (the facade shape the std.sx
restructure needs). selectGenericStructHead consults aliasedStructTemplate
(nominal.zig) before the global template map — own-wins/single-flat alias
author, each hop pinned to the alias author's source, ns.X RHS through
namespaceAliasVerdictFrom, depth-capped. resolveTypeCallWithBindings'
silent .unresolved tail (panicked in LLVM emission) now diagnoses
"unknown type". Also aligns the stale pre-existing calls.test.zig UFCS
plan test with the opt-in model (a47ea14). Regression: examples/0211
(+rich/+facade). Gates: zig build test 426/426, suite 587/587.
2026-06-11 18:09:01 +03:00
agra
0b13498e25 fix(0115): source-aware global selection — own-wins for module globals
The globals registry (global_names) was last-wins across modules with no
per-importer gate: any module's bare K could read/write/type against an
unrelated module's same-named global (hash.sx's K table hijacked every
user K once std's namespace tail pulled hash into the program), and an
own const of an unsupported shape borrowed another module's const and
panicked at the unresolved-type tripwire.

- var_decl joins RawDeclRef: module globals are selectable raw authors.
- selectGlobalAuthor (the globals analogue of F2's selectModuleConst):
  own author wins, one flat-visible author resolves, >=2 distinct flat
  authors diagnose loudly, authored-but-not-visible diagnoses, and a
  compiler-synthesized global (no raw author) emits untracked. A var_decl
  author whose per-source registration was deduped at flat-merge (two
  modules declaring the same extern symbol) serves the symbol's
  registration.
- All bare-identifier global sites route through it: value read, addr-of,
  assignment (store + compound), lvalue address, fn-ptr call, call param
  typing, and expression type inference.
- selectModuleConst gains .own_opaque: an own const author with no
  materialized per-source value (e.g. an array '::' const) blocks
  borrowing another module's same-named const — the read diagnoses
  cleanly instead of panicking.
- The fn-as-VALUE arm admits raw-facts-only authors: an own fn whose name
  a flat-merge collision dropped from the global decl list (first-wins)
  now resolves via author selection for func_ref/closure/Any shapes too.

Regressions: examples 0835 (own const vs flat array global), 0836 (main
const vs namespaced array global, incl. inference), 0837 (own array
const never borrows cross-module — clean unresolved).
2026-06-11 10:47:30 +03:00
agra
ee00db849c lang: qualified namespace members in value position + alias carry
Two coupled capabilities on the road to the std restructure
(current/PLAN-STDLIB.md, issue 0114):

1. alias.Type.method() / alias.Type as a call head, alias.CONST, and
   alias.Enum.variant now resolve — previously only alias.fn() and
   type-position alias.Type worked. objectIsValue treats an
   alias-rooted field_access as a type head; the call path strips the
   alias to the existing Type.method machinery; lowerFieldAccess
   resolves alias.CONST pinned to the target module and alias.Enum.x
   as a typed enum literal; resolveTypeWithBindings resolves qualified
   type_exprs pinned to the target.

2. The carry rule: namespaceAliasTarget resolves an alias from the
   file's own edges first, then from DIRECT flat imports (one level),
   diagnosing two distinct carried targets as ambiguous. All qualified
   shapes work through a carried alias — the std.sx namespace tail
   (mem.GPA.init() etc.) is now expressible.

Regression: examples/0831-modules-namespace-alias-carry.sx (direct +
carried, all seven shapes).
2026-06-11 05:52:10 +03:00
agra
2b8041a828 cleanup: drop resolved-issue citations from src comments
Sweep all src/**.zig comments that cite resolved issues (issue NNNN /
fix-NNNN / KB-N): the invariant or mechanism each comment states is
kept; the historical citation is dropped, per the no-conclusion-comments
rule. Pure-history parentheticals are removed outright. References to
the 16 still-open issues (0030, 0041-0056) are untouched, as are test
NAMES carrying regression provenance (matching the sanctioned
"Regression (issue NNNN)" example-header convention).

Also removes the issues/0019-import-non-transitive-c-scope/ fixture dir
— the issue is superseded and its behavior is covered by
examples/0706-modules-import-non-transitive.sx (the .md writeup stays).
issues/0030's repro .sx stays: that issue is an open feature request.

Gate: zig build OK; zig build test 426/426; run_examples 541/0; zero
expected/ snapshot churn.
2026-06-10 16:34:17 +03:00
agra
82500931ce cleanup(B-review): fix stale section banners, merge alias block, prune imports
Review follow-up to the ARCH-B split (comment/import hygiene only, no
code changes):

- Section banners that travelled to the wrong file with the B1-B8 cuts
  are reworded to describe the section that actually follows (e.g.
  stmt.zig's trailing "Expression lowering", expr.zig's "Control flow"
  before lowerChainedComparison) or deleted where nothing follows
  (4 trailing-at-EOF banners). ffi.zig's facade note no longer claims
  the IMP builders "stay here" (they live in lower/objc_class.zig);
  protocol.zig's namespace-lookup banner now points at
  pack.zig:resolvePackProjection for the orchestrator.
- lower.zig's two lower/expr.zig alias blocks (B8.1 + B8.2 appends)
  merged into one.
- 448 unused header decls pruned from the 15 lower/*.zig files (each
  had inherited lower.zig's full import block; pruned to fixpoint so
  cascading type-extraction consts went too).

Gate: zig build OK; zig build test 426/426; run_examples 541/0; zero
expected/ snapshot churn.
2026-06-10 16:09:24 +03:00
agra
5928d9f067 refactor(B4.2): move nominal-type registration to lower/nominal.zig
Verbatim relocation of the 23-method nominal-type cluster (struct/enum/
union/error-set registration, anon-type qualification, nominal-id
stamping, shadow-slot reservation, named-type interning, generic struct
templates + alias registration) plus the nested ShadowTypeDecl union
into src/ir/lower/nominal.zig. 23 aliases on Lowering keep all call
sites unchanged.

Method pub-flip: instantiateGenericStruct. nominal.zig reaches
VisibleStructAuthor and structDeclOfRaw (both relocated to decl.zig in
B4.1) via Lowering-namespace alias consts.

Gate: zig build OK; zig build test 426/426; run_examples 541/0; zero
expected/ snapshot churn.
2026-06-10 13:51:15 +03:00