Files
sx/current/CHECKPOINT-METATYPE.md
agra 12e2ff7ef4 docs+rename: erase the reify name everywhere — stream is METATYPE
The compiler concept is declare/define (comptime type construction); the
old "reify" framing is gone from the entire repo.

- Rename: PLAN-REIFY → PLAN-METATYPE, CHECKPOINT-REIFY → CHECKPOINT-METATYPE,
  PLAN-POST-REIFY → PLAN-POST-METATYPE (both rewritten around declare/define);
  examples 0614/0615/0617 → comptime-metatype-* (+ their expected/ triplets),
  headers rewritten.
- Scrub reify from design/execution-evolution-roadmap.md (§7 step 3 contracts,
  §8.1, §9 decisions, §10 gates) → declare/define / comptime type construction.
- core.sx prelude pointer + parser.test.zig surface lock updated to the
  declare/define builtins (define(handle, info) -> Type; EnumInfo.name).

No behavior change; renamed examples match their renamed snapshots. Full
suite green (673), all unit tests pass. Zero `reify` tokens remain in
src/docs/sx/examples.
2026-06-16 21:23:05 +03:00

4.2 KiB

CHECKPOINT-METATYPE — comptime type metaprogramming (declare / define)

Companion to PLAN-METATYPE.md. Update after every step (one step at a time, per the cadence rule).

Last completed step

The declare/define floor — the compiler's only type-construction surface. Two comptime #builtins mint types; every constructor (RecvResult, TryResult, the one-shot form) is plain sx built over them. The compiler has ZERO knowledge of any named constructor.

  • declare() -> Type mints an empty (undefined) nominal slot; define(handle, info) -> Type decodes the TypeInfo value (variant names + payload Type-tags), names the slot from EnumInfo.name, completes it byte-identical to a source enum, and returns the handle (so the one-shot form chains: T :: define(declare(), info)). Interp executes both against a mint TypeTable handle (setMintTable); defineEnum + decodeVariantElements in interp.zig.
  • A :: binding or type-fn body that calls a Type-returning fn is comptime-evaluated (evalComptimeType), running the declare/define builtins to mint the type — no constructor-name pattern-matching. decl.zig trigger = fnReturnsTypeValue; type-fn trigger = returnExprMintsType (return is a define(…) call or a bodied -> Type helper).
  • Nominal identity rides the type-fn instantiation cache (renameNominalType re-keys the minted type to the mangled name); RecvResult(i64) at two sites is ONE type.
  • The type NAME travels in EnumInfo.name — the compiler derives no name from a binding LHS.

Examples green on the floor: 0614 (one-shot define(declare(), …)), 0615 (type-fn identity), 0617 (channel result types). field_type reflection still green (0616). Full suite green (673 examples).

Current state

  • modules/std/meta.sx: EnumVariant / EnumInfo{ name, variants } / TypeInfo data types; declare / define / type_info / field_type #builtins; RecvResult($T) / TryResult($T) sx constructors over define(declare(), …).
  • Compiler primitives only: declare/define (construction), field_type (reflection). No constructor-name knowledge anywhere in the compiler — every named constructor is sx.
  • type_info still bails loudly (call.zig:tryLowerReflectionCall) — pending.

Decision (kept)

Meta lives in modules/std/meta.sx, not the prelude. Declaring its data types in the always-loaded prelude interns them into every module's type table and shifts every .ir snapshot. On-demand import keeps the prelude clean.

Next step

Self-reference (recursive / mutually-recursive enums). The two-statement form List :: declare(); define(List, .enum(.{ … payload = *List … })): declare binds the handle, define completes it, and *List resolves because a pointer to an undefined slot is legal. Needs the top-level define(…) statement form to run at comptime in the window before any use of the type's layout (a bare top-level call doesn't parse today — decide the surface). Pairs with a make_enum(variants: []EnumVariant) sx helper (a computed, non-literal variant list — exercises the interpreter decoding a value-arg slice).

Then: type_info($T) -> TypeInfo (reflect a type INTO a value — the inverse of define's decode; widen TypeInfo past `enum + construct a []EnumVariant value in the interp; its own focused effort) and validation + loud diagnostics (dup variants, by-value self-ref, never-defined declare, use-before-define).

Known issues

None.

Log

  • declare/define floor established. The comptime type-construction surface is two primitives (declare/define); all named constructors are sx. A :: binding or type-fn body that calls a Type-returning fn is comptime-evaluated (the builtins mint the type) — no syntactic constructor recognition in the compiler. Name travels in TypeInfo. Examples 0614 (one-shot) / 0615 (type-fn identity) / 0617 (channel results) run on the floor; field_type reflection (0616) unchanged. Full suite green (673).
  • Stream carved (earlier). Selected as the first async-first foundation: gates channel result types (RecvResult($T)) and race's synthesized union, fully validated, self-contained, testable in isolation (06xx comptime).