docs(metatype): declare(name) + self-reference done; update plan/checkpoint
This commit is contained in:
@@ -4,10 +4,11 @@
|
||||
|
||||
Comptime type metaprogramming with the smallest possible compiler surface:
|
||||
|
||||
- **`declare() -> Type`** — mint a NEW empty (undefined) nominal type, returned as
|
||||
a first-class `Type` handle.
|
||||
- **`declare(name) -> Type`** — mint a NEW empty (undefined) nominal type NAMED
|
||||
`name`, returned as a first-class `Type` handle. The compiler registers the
|
||||
forward type at compile time, so the body can reference it (`*Name`).
|
||||
- **`define(handle, info) -> Type`** — fill a declared handle's body from a
|
||||
`TypeInfo` *value* (which carries the type's name), and return the handle.
|
||||
`TypeInfo` *value*, and return the handle (so the one-shot form chains).
|
||||
- **`type_info($T) -> TypeInfo`** — reflect a type INTO data (the inverse of
|
||||
`define`'s decode). *Pending.*
|
||||
- **`field_type($T, i) -> Type`** — the i-th field / variant-payload / element
|
||||
@@ -19,17 +20,20 @@ compiler surface. Every higher-level constructor is **plain sx built over
|
||||
|
||||
```sx
|
||||
// one-shot (non-recursive): declare + define chained, define returns the handle
|
||||
T :: define(declare(), .enum(.{ name = "T", variants = .[ … ] }));
|
||||
T :: define(declare("T"), .enum(.{ variants = .[ … ] }));
|
||||
|
||||
// recursive / mutually-recursive: keep the handle, reference it in its own body
|
||||
List :: declare();
|
||||
define(List, .enum(.{ name = "List", variants = .[
|
||||
EnumVariant.{ name = "cons", payload = *List },
|
||||
EnumVariant.{ name = "nil", payload = void } ] }));
|
||||
// recursive: a ctor fn names the forward type via declare, references it as *Name
|
||||
List :: make_list();
|
||||
make_list :: () -> Type {
|
||||
h := declare("List");
|
||||
return define(h, .enum(.{ variants = .[
|
||||
EnumVariant.{ name = "cons", payload = *List }, // self-reference
|
||||
EnumVariant.{ name = "nil", payload = void } ] }));
|
||||
}
|
||||
|
||||
// type-fns are ordinary sx (channel result types, etc.)
|
||||
RecvResult :: ($T: Type) -> Type {
|
||||
return define(declare(), .enum(.{ name = "RecvResult", variants = .[
|
||||
return define(declare("RecvResult"), .enum(.{ variants = .[
|
||||
EnumVariant.{ name = "value", payload = T },
|
||||
EnumVariant.{ name = "closed", payload = void } ] }));
|
||||
}
|
||||
@@ -52,8 +56,13 @@ tagged-union (design [../design/execution-evolution-roadmap.md](../design/execut
|
||||
`-> Type` fn call; `instantiateTypeFunction` triggers on a type-fn body that
|
||||
returns a `define(…)` call (or a bodied `-> Type` helper) — see
|
||||
`generic.zig:returnExprMintsType`.
|
||||
3. **Name travels in the data.** `define` names the slot from `EnumInfo.name`; the
|
||||
compiler derives no name from a binding LHS. `type_info` round-trips it.
|
||||
3. **Name on `declare`.** `declare("Name")` carries the name as a compile-time
|
||||
string so `preregisterForwardTypes` (in `evalComptimeType`) can register the
|
||||
forward type — and bind it as a type alias — BEFORE the body lowers. That's
|
||||
what makes a `*Name` self-reference resolve (a `Name :: ctor()` decl makes
|
||||
`Name` a const_decl author, so `*Name` resolves through the forward-ALIAS path;
|
||||
the alias binding, not just the table registration, is what satisfies it). The
|
||||
interp's `declare` returns the same slot by name; `define` fills it in place.
|
||||
4. **Nominal identity** rides the existing type-fn mangled-name instantiation cache:
|
||||
`RecvResult(i64)` at two sites memoizes to ONE `TypeId` (the body runs once;
|
||||
`renameNominalType` re-keys the minted type to the mangled name).
|
||||
@@ -92,11 +101,14 @@ while red. Examples: `06xx` (comptime), `11xx` (diagnostics).
|
||||
- [x] `field_type` reflection (`examples/0616`).
|
||||
- [x] Examples green on the floor: `0614` (one-shot), `0615` (type-fn identity),
|
||||
`0617` (channel result types).
|
||||
- [ ] **Self-reference** — the top-level `List :: declare(); define(List, …)`
|
||||
two-statement form with a `*Self` payload (recursive / mutually-recursive
|
||||
enums). Needs the `define(…)` top-level statement form to run at comptime in
|
||||
the right window. Pairs with a `make_enum(variants: []EnumVariant)` sx helper
|
||||
(computed variant list).
|
||||
- [x] **Self-reference** — recursive enums via `declare("Name")` + `*Name` in a
|
||||
constructor fn (`preregisterForwardTypes` registers the forward type + alias
|
||||
before the body lowers). `examples/0618` (recursive `*List`: construct, match
|
||||
through the pointer, recursive traversal). Mutual recursion / by-value-self-ref
|
||||
rejection fall out of the same mechanism (F5 adds the loud by-value check).
|
||||
- [ ] **`make_enum(variants: []EnumVariant)`** sx helper over a COMPUTED
|
||||
(non-literal) variant list — exercises the interpreter decoding a value-arg
|
||||
slice in `define`.
|
||||
- [ ] **`type_info($T) -> TypeInfo`** — reflect a type INTO a value (inverse of
|
||||
`define`'s decode): widen `TypeInfo` past `` `enum `` (struct/tuple) AND
|
||||
construct a `[]EnumVariant`-style value in the interpreter. Bails loudly today
|
||||
|
||||
Reference in New Issue
Block a user