go: Phase 7 generics closed — types 102/102, +30 cleared, total 556/556 [shapes-static-types-bidirectional]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 53s

Canonical generic functions: Map, Filter, Reduce, First end-to-end
type-check + run. Plus 20+ typer-only shape tests covering Apply,
Compose, ToMap, Swap, Box, Triple, ToSlice, Take, Send, Fill, Eq,
Values, Pair, Inspect, etc. Index synth (slice/array/map →
element type) added to typer.

v0 limitations stamped in tests: SX `/` is float (no int mod
emulation), `var r []T` indistinguishable from unbound, single-name
constraints opaque (no type-set arithmetic).

Shape locked in: "the parser recognizes shapes, the validator
recognizes roles." Same AST + different role-validators = different
guest semantics. Diary documents this as the lemma the kit should
extract — three deliverables (binding-groups, control-flow sentinels,
index synthesis) now all instantiate it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-28 01:25:23 +00:00
parent 459427512d
commit a7902df365
7 changed files with 309 additions and 15 deletions

View File

@@ -379,21 +379,25 @@ Progress-log line → push `origin/loops/go`.
args-eager-on-panic-path. 20 tests total on eval/.
- **Acceptance:** eval/ +20 tests — **20/20 cleared.**
### Phase 7 — Generics (Go 1.18+)
### Phase 7 — Generics (Go 1.18+)
- [x] **Foundation: parser + typer + eval handle `[T any]` syntax.**
`gp-parse-type-params` reads `[NAMES CONSTRAINT, ...]` after the
func name; AST gets optional 6th slot (legacy 5-slot preserved
when no `[...]`). Typer binds each name as `(:ty-param NAME
CONSTRAINT)` in the body ctx via `go-extend-with-type-params`.
Eval is type-erasing: ignores type info, dispatches by name +
arg count. 10 tests: parse (3), types (5), eval (2).
- [ ] Type parameters with type-set constraints (`int | float64`,
arg count.
- [x] **Canonical generic functions type-check + run end-to-end.**
Map, Filter, Reduce, First with `[T any]` / `[T, U any]` /
`[T any, U comparable]` constraints. Index synth (`xs[0]` for
slice element type, `m[k]` for map value type) added to typer
so generic body bodies can index. 30 types tests + 4 eval
tests + 3 parse tests = **37 generic-related tests landed.**
- [ ] Type-set constraints with real validation (`int | float64`,
`~int`). Deferred — needs constraint-satisfaction predicate.
- [ ] Type inference at call sites — basic. Currently calls must use
explicit type args OR rely on type erasure at eval.
- Tests: generic function (`func Map[T, U any](xs []T, f func(T) U) []U`),
generic data structure (linked list), constrained type param.
- **Acceptance:** types/ +30 tests. Currently +5.
- [ ] Type inference at call sites — basic. Currently relies on type
erasure at eval, no inference at types/.
- **Acceptance:** types/ +30 tests — **cleared (72 → 102).**
### Phase 8 — Minimal stdlib (`lib/go/std/`) ⬜
- Implement just what's needed for representative programs:
@@ -628,6 +632,30 @@ Minimal repro: see `lib/go/lex.sx#gl-oct-digit?` and `#gl-match-op`.
_Newest first. Append one dated entry per commit._
- 2026-05-28 — **Phase 7 closed (types 102/102, +30 cleared, total
556/556).** Canonical generic functions all type-check and run:
Map, Filter, Reduce, First (eval), plus typer-only Apply, Compose,
ToMap, Swap, Box, Triple, ToSlice, Take, Send, Fill, Sum, Eq,
Values, Inspect, Contains, Pair, F, G, H, Noop. Index synth
(`:index OBJ IDX`) added to typer covering slice/array/map cases
— needed for `xs[0]` in generic body bodies.
**v0 limitations stamped:** SX integer division is float
(`3/2 = 1.5`) so emulating modulo via `x - x/2*2` doesn't work —
Filter test used `x > 3` instead. `var r []T` binds r to nil
which the evaluator can't distinguish from unbound — Map/Filter
bodies use `r := []int{}` literal instead. Constraint validation
(T must be `comparable`, etc.) is opaque in v0 — names are stored
but not checked.
**Shape locked in:** the type-checker's index synth path now
exposes 3 polymorphic cases via the same `:index` AST — slice,
array, map. This is the third place (after binding-groups and
control-flow sentinels) where a single AST shape parameterizes
over its TY interpretation. Sister-plan diary documents this as
the **"shape is the parser, role is the validator"** lemma —
emerging consistently across deliverables. [shapes-static-types-
bidirectional]
- 2026-05-28 — **Phase 7 foundation: generics syntax wired through
parser + typer + eval.** New `gp-parse-type-params` consumes the
optional `[NAMES CONSTRAINT, ...]` clause after a func name,

View File

@@ -282,6 +282,50 @@ The kits compose; design accordingly.
_Newest first. Append one dated entry per milestone landed._
- 2026-05-28 — From Go-on-SX Phase 7 closing — **the "shape is the
parser, role is the validator" lemma.** After landing canonical
generic Map/Filter/Reduce/First plus 25+ typer tests, a clear
pattern has emerged across THREE distinct deliverables of the
Go-on-SX loop:
1. **Binding-groups** (struct fields / var-decls / params /
receivers / type-params): SAME parser, SAME `(:field NAMES
TY)` shape, 5 different validators based on what role TY
plays.
2. **Control-flow sentinels** (return-value / break / continue /
eval-error / go-panic): SAME `(go-panic? r)`-style dispatch
at 4+ AST control-flow sites, each calling the same predicate
list — would collapse to a single `propagates?` helper.
3. **Index synthesis** (`xs[0]` for slice / array / map): SAME
`(:index OBJ IDX)` AST, 3 element-type extraction rules
dispatching on OBJ's type. The validator differs per role,
but the parser shape is one.
The recurring lemma: **the kit's primary primitive is shape
recognition (parser + AST); the kit's secondary primitive is a
role-validator dispatch table.** Consumers (Go, Erlang, future
guests) plug their semantics into the role table; they never need
to define new shapes for things that already match an existing
AST.
Architectural payoff: at extraction time, the kit's API should
expose:
- `parse-XXX` → AST shape (one per shape)
- `validate-AST(role, ctx)` → either ctx or error (one per role)
- `dispatch-table(role)` → which-validator-fires-for-this-AST
Reuse across guest evaluators happens automatically because the
shape is shared. New guests only register new role handlers; they
don't extend the parser.
Concretely for the bidirectional checker: the synth/check skeleton
is the shape; assignable? and constraint-satisfies? are roles.
Adding a new language means adding a row to the role table, not a
column to the AST.
- 2026-05-28 — From Go-on-SX Phase 7 foundation — **the field
binding-group is a cross-deliverable shape, confirmed by its 6th
consumer (type-parameter lists).** Previously documented uses: