docs(reify): name Phase 4 self-reference pair declare()/define()

User picked the declaration-vs-definition split over reserve/complete.
declare() returns a forward nominal Type handle (named from the :: LHS);
define(handle, info) fills its body. reify(info) stays the one-shot
sugar. Updated PLAN-REIFY Phase 4 + Contract 5 + CHECKPOINT-REIFY.
This commit is contained in:
agra
2026-06-16 18:45:08 +03:00
parent ae5de1e687
commit 04e833a825
2 changed files with 27 additions and 25 deletions

View File

@@ -61,16 +61,17 @@ only at the `E :: reify(...)` const-decl site (`decl.zig`) and reads a LITERAL
(and likely generalize the literal-AST reader, or evaluate via the interpreter, for (and likely generalize the literal-AST reader, or evaluate via the interpreter, for
non-literal `TypeInfo`). non-literal `TypeInfo`).
SELF-REFERENCE = Phase 4, API DECIDED (user-directed): explicit **`reserve()` → SELF-REFERENCE = Phase 4, API DECIDED (user-directed): explicit **`declare()` →
`complete()`** (NOT a `reify_rec((self)=>…)` closure). `reserve()` returns a forward `define(h, info)`** (the declaration-vs-definition split; NOT a `reify_rec((self)=>…)`
nominal `Type` handle (named from the `::` LHS) usable freely in any later `TypeInfo` closure). `declare()` returns a forward nominal `Type` handle (named from the `::`
— `*List`, `[]List`, and across types for MUTUAL recursion the one-`self` closure LHS) usable freely in any later `TypeInfo` — `*List`, `[]List`, and across types for
couldn't express; `complete(handle, info)` fills the body. `reify(info)` stays as the MUTUAL recursion the one-`self` closure couldn't express; `define(handle, info)` fills
one-shot sugar. Maps onto existing machinery: reserve = empty nominal slot the body. `reify(info)` stays as the one-shot sugar. Maps onto existing machinery:
(`reserveShadowEnumSlot`-style), complete = `buildEnumInfo` + `updatePreservingKey`, declare = empty nominal slot (`reserveShadowEnumSlot`-style), define = `buildEnumInfo`
struct-stub→tagged_union re-key already handled (`internNamedTypeDecl`'s + `updatePreservingKey`, struct-stub→tagged_union re-key already handled
`adoptsForwardStructStub`). Loud invariants: never-completed reserve = hard error; (`internNamedTypeDecl`'s `adoptsForwardStructStub`). Loud invariants: never-defined
by-value self-inclusion rejected (infinite size). Full write-up in PLAN-REIFY Phase 4. declare = hard error; by-value self-inclusion rejected (infinite size). Full write-up
in PLAN-REIFY Phase 4.
## Known issues ## Known issues
None yet. None yet.

View File

@@ -25,9 +25,9 @@ tagged-union, and **replaces** a would-be `enum($T)` generic-enum language featu
3. **Validate loudly** at the `intern`/`internNominal` choke point (`types.zig:411-439`). 3. **Validate loudly** at the `intern`/`internNominal` choke point (`types.zig:411-439`).
4. **Comptime-only, JIT-free** — a type-table op in the interpreter; no S1 dependency. 4. **Comptime-only, JIT-free** — a type-table op in the interpreter; no S1 dependency.
5. **Reference-based self-reference** (`*Self`/`[]Self`) via an explicit 5. **Reference-based self-reference** (`*Self`/`[]Self`) via an explicit
**`reserve()``complete()`** pair (reserve-placeholder→complete reuse of **`declare()``define()`** pair (reserve-placeholder→complete reuse of
`nominal.zig:86/108/120`, `types.zig:442`); **by-value recursion rejected**. (See `nominal.zig:86/108/120`, `types.zig:442`); **by-value recursion rejected**. (See
Phase 4 — the `reserve`/`complete` API supersedes the earlier `reify_rec` closure.) Phase 4 — the `declare`/`define` API supersedes the earlier `reify_rec` closure.)
Surface follows the **`#builtin`** pattern of the existing reflection builtins Surface follows the **`#builtin`** pattern of the existing reflection builtins
(`type_of`/`field_count`/`field_name` in `library/modules/std/core.sx`, (`type_of`/`field_count`/`field_name` in `library/modules/std/core.sx`,
@@ -81,28 +81,29 @@ Examples: `06xx` (comptime, deterministic), `11xx` (diagnostics for loud failure
|---|---|---|---| |---|---|---|---|
| 3.0 | lock | `make_enum(variants) -> Type` (sx lib over `reify`); `RecvResult($T)`/`TryResult($T)` as type-fns. Behavior-lock: `RecvResult(i64)` constructs + matches. | `library/modules/std/*` | | 3.0 | lock | `make_enum(variants) -> Type` (sx lib over `reify`); `RecvResult($T)`/`TryResult($T)` as type-fns. Behavior-lock: `RecvResult(i64)` constructs + matches. | `library/modules/std/*` |
### Phase 4 — reference-based self-reference (explicit reserve → complete) ### Phase 4 — reference-based self-reference (explicit declare → define)
> **API decision (user-directed):** an explicit **`reserve()` / `complete()`** pair, > **API decision (user-directed):** an explicit **`declare()` / `define(h, info)`**
> NOT a `reify_rec((self) => …)` closure. `reserve()` returns a forward-declared > pair (the canonical declaration-vs-definition split), NOT a `reify_rec((self) => …)`
> nominal `Type` HANDLE — a real `Type` value usable freely in any later `TypeInfo` > closure. `declare()` returns a forward-declared nominal `Type` HANDLE — a real
> (`*List`, `[]List`, and across types for MUTUAL recursion, which the one-`self` > `Type` value usable freely in any later `TypeInfo` (`*List`, `[]List`, and across
> closure can't express). `complete(handle, info)` fills the body. `reify(info)` stays > types for MUTUAL recursion, which a one-`self` closure can't express).
> as the one-shot sugar (= reserve + complete + return) for the non-recursive case. > `define(handle, info)` fills the body. `reify(info)` stays as the one-shot sugar
> No special self-ref node in `TypeInfo` — a reserved type is just a `Type`. > (= declare + define + return) for the non-recursive case. No special self-ref node
> in `TypeInfo` — a declared type is just a `Type`.
> ```sx > ```sx
> List :: reserve(); // name from the `::` LHS > List :: declare(); // name from the `::` LHS
> complete(List, .enum(.{ variants = .[ > define(List, .enum(.{ variants = .[
> EnumVariant.{ name = "cons", payload = *List }, // reference it freely > EnumVariant.{ name = "cons", payload = *List }, // reference it freely
> EnumVariant.{ name = "nil", payload = void } ] })); > EnumVariant.{ name = "nil", payload = void } ] }));
> ``` > ```
> Loud invariants: (a) a `reserve()` never `complete()`d = hard error at end of > Loud invariants: (a) a `declare()` never `define()`d = hard error at end of
> comptime (no silent empty type); (b) by-VALUE self-inclusion (`payload = List`, not > comptime (no silent empty type); (b) by-VALUE self-inclusion (`payload = List`, not
> `*List`) rejected — infinite size, same check recursive source types get. > `*List`) rejected — infinite size, same check recursive source types get.
| Step | Commit | What | Files | | Step | Commit | What | Files |
|---|---|---|---| |---|---|---|---|
| 4.0 | xfail | `reserve()` returns a forward nominal `Type`; `complete()` fills it. Recursive enum via `*Self` (tree/list). Red. | `examples/06xx-*` | | 4.0 | xfail | `declare()` returns a forward nominal `Type`; `define()` fills it. Recursive enum via `*Self` (tree/list). Red. | `examples/06xx-*` |
| 4.1 | green | `reserve` = intern empty nominal slot (`reserveShadowEnumSlot`-style); `complete` = `buildEnumInfo` + `updatePreservingKey`; struct-stub→tagged_union re-key already handled by `internNamedTypeDecl` (`adoptsForwardStructStub`). | `src/ir/lower/nominal.zig`, `src/ir/lower/decl.zig`, `src/ir/types.zig` | | 4.1 | green | `declare` = intern empty nominal slot (`reserveShadowEnumSlot`-style); `define` = `buildEnumInfo` + `updatePreservingKey`; struct-stub→tagged_union re-key already handled by `internNamedTypeDecl` (`adoptsForwardStructStub`). | `src/ir/lower/nominal.zig`, `src/ir/lower/decl.zig`, `src/ir/types.zig` |
### Phase 5 — validation + loud diagnostics ### Phase 5 — validation + loud diagnostics
| Step | Commit | What | Files | | Step | Commit | What | Files |