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.
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() -> Typemints an empty (undefined) nominal slot;define(handle, info) -> Typedecodes theTypeInfovalue (variant names + payload Type-tags), names the slot fromEnumInfo.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 amintTypeTable handle (setMintTable);defineEnum+decodeVariantElementsininterp.zig.- A
::binding or type-fn body that calls aType-returning fn is comptime-evaluated (evalComptimeType), running thedeclare/definebuiltins to mint the type — no constructor-name pattern-matching.decl.zigtrigger =fnReturnsTypeValue; type-fn trigger =returnExprMintsType(return is adefine(…)call or a bodied-> Typehelper). - Nominal identity rides the type-fn instantiation cache (
renameNominalTypere-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 }/TypeInfodata types;declare/define/type_info/field_type#builtins;RecvResult($T)/TryResult($T)sx constructors overdefine(declare(), …).- Compiler primitives only:
declare/define(construction),field_type(reflection). No constructor-name knowledge anywhere in the compiler — every named constructor is sx. type_infostill 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 aType-returning fn is comptime-evaluated (the builtins mint the type) — no syntactic constructor recognition in the compiler. Name travels inTypeInfo. Examples 0614 (one-shot) / 0615 (type-fn identity) / 0617 (channel results) run on the floor;field_typereflection (0616) unchanged. Full suite green (673). - Stream carved (earlier). Selected as the first async-first foundation: gates
channel result types (
RecvResult($T)) andrace's synthesized union, fully validated, self-contained, testable in isolation (06xxcomptime).