go: types.sx scaffold — synth/check skeleton + 12 tests; Phase 3 starts [shapes-static-types-bidirectional]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 24s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 24s
First slice of Phase 3 (bidirectional type checker).
lib/go/types.sx defines:
* go-ctx-empty / go-ctx-extend / go-ctx-lookup — context as a value.
* go-ctx-extend-field — consumes the (:field NAMES TYPE) shape from
the parser, binding every name to the shared type. This is the
cross-deliverable validation of the :field binding-group
observation made during Phase 2 func decls: parser produces it,
type checker consumes it, same shape end-to-end.
* go-predeclared — true / false / nil baked in. Full list expanded
on demand.
* go-synth — currently handles variable lookup; literals / calls /
binops follow in subsequent iterations.
* go-check — v0 defers to synth + structural type equality. Untyped-
constant flow and assignment-compatibility relations land later.
* Type errors carry first-class tags (:unbound, :mismatch,
:unsupported-synth) so consumers and tooling can dispatch.
Conformance.sh wired with new types suite. Scoreboard cleanup: drop
the "pending" types row since the suite is now real.
types 12/12, total 317/317. Phase 3 underway.
Sister-plan static-types-bidirectional diary updated with the
synth/check shape: judgment skeleton, error tag structure, and the
proposal that `check` should accept a `subtype?` predicate parameter
so each consumer (Go untyped-constants, TS variance, Rust lifetimes)
plugs in its own variance discipline without rewriting the judgment.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,7 @@ trap "rm -f $TMPFILE $OUTFILE" EXIT
|
|||||||
SUITES=(
|
SUITES=(
|
||||||
"lex|go-test-pass|go-test-count"
|
"lex|go-test-pass|go-test-count"
|
||||||
"parse|go-parse-test-pass|go-parse-test-count"
|
"parse|go-parse-test-pass|go-parse-test-count"
|
||||||
|
"types|go-types-test-pass|go-types-test-count"
|
||||||
)
|
)
|
||||||
|
|
||||||
cat > "$TMPFILE" <<'EPOCHS'
|
cat > "$TMPFILE" <<'EPOCHS'
|
||||||
@@ -38,8 +39,10 @@ cat > "$TMPFILE" <<'EPOCHS'
|
|||||||
(load "lib/guest/pratt.sx")
|
(load "lib/guest/pratt.sx")
|
||||||
(load "lib/go/lex.sx")
|
(load "lib/go/lex.sx")
|
||||||
(load "lib/go/parse.sx")
|
(load "lib/go/parse.sx")
|
||||||
|
(load "lib/go/types.sx")
|
||||||
(load "lib/go/tests/lex.sx")
|
(load "lib/go/tests/lex.sx")
|
||||||
(load "lib/go/tests/parse.sx")
|
(load "lib/go/tests/parse.sx")
|
||||||
|
(load "lib/go/tests/types.sx")
|
||||||
EPOCHS
|
EPOCHS
|
||||||
|
|
||||||
idx=0
|
idx=0
|
||||||
@@ -104,7 +107,6 @@ cat > lib/go/scoreboard.json <<JSON
|
|||||||
"total_pass": $TOTAL_PASS,
|
"total_pass": $TOTAL_PASS,
|
||||||
"total": $TOTAL_COUNT,
|
"total": $TOTAL_COUNT,
|
||||||
"suites": [$JSON_SUITES,
|
"suites": [$JSON_SUITES,
|
||||||
{"name":"types","pass":0,"total":0,"status":"pending"},
|
|
||||||
{"name":"eval","pass":0,"total":0,"status":"pending"},
|
{"name":"eval","pass":0,"total":0,"status":"pending"},
|
||||||
{"name":"runtime","pass":0,"total":0,"status":"pending"},
|
{"name":"runtime","pass":0,"total":0,"status":"pending"},
|
||||||
{"name":"stdlib","pass":0,"total":0,"status":"pending"},
|
{"name":"stdlib","pass":0,"total":0,"status":"pending"},
|
||||||
@@ -120,8 +122,7 @@ cat > lib/go/scoreboard.md <<MD
|
|||||||
|
|
||||||
| | Suite | Pass | Total |
|
| | Suite | Pass | Total |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
$MD_ROWS| ⬜ | types | 0 | 0 |
|
$MD_ROWS| ⬜ | eval | 0 | 0 |
|
||||||
| ⬜ | eval | 0 | 0 |
|
|
||||||
| ⬜ | runtime | 0 | 0 |
|
| ⬜ | runtime | 0 | 0 |
|
||||||
| ⬜ | stdlib | 0 | 0 |
|
| ⬜ | stdlib | 0 | 0 |
|
||||||
| ⬜ | e2e | 0 | 0 |
|
| ⬜ | e2e | 0 | 0 |
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"language": "go",
|
"language": "go",
|
||||||
"total_pass": 305,
|
"total_pass": 317,
|
||||||
"total": 305,
|
"total": 317,
|
||||||
"suites": [
|
"suites": [
|
||||||
{"name":"lex","pass":129,"total":129,"status":"ok"},
|
{"name":"lex","pass":129,"total":129,"status":"ok"},
|
||||||
{"name":"parse","pass":176,"total":176,"status":"ok"},
|
{"name":"parse","pass":176,"total":176,"status":"ok"},
|
||||||
{"name":"types","pass":0,"total":0,"status":"pending"},
|
{"name":"types","pass":12,"total":12,"status":"ok"},
|
||||||
{"name":"eval","pass":0,"total":0,"status":"pending"},
|
{"name":"eval","pass":0,"total":0,"status":"pending"},
|
||||||
{"name":"runtime","pass":0,"total":0,"status":"pending"},
|
{"name":"runtime","pass":0,"total":0,"status":"pending"},
|
||||||
{"name":"stdlib","pass":0,"total":0,"status":"pending"},
|
{"name":"stdlib","pass":0,"total":0,"status":"pending"},
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Go-on-SX Scoreboard
|
# Go-on-SX Scoreboard
|
||||||
|
|
||||||
**Total: 305 / 305 tests passing**
|
**Total: 317 / 317 tests passing**
|
||||||
|
|
||||||
| | Suite | Pass | Total |
|
| | Suite | Pass | Total |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ✅ | lex | 129 | 129 |
|
| ✅ | lex | 129 | 129 |
|
||||||
| ✅ | parse | 176 | 176 |
|
| ✅ | parse | 176 | 176 |
|
||||||
| ⬜ | types | 0 | 0 |
|
| ✅ | types | 12 | 12 |
|
||||||
| ⬜ | eval | 0 | 0 |
|
| ⬜ | eval | 0 | 0 |
|
||||||
| ⬜ | runtime | 0 | 0 |
|
| ⬜ | runtime | 0 | 0 |
|
||||||
| ⬜ | stdlib | 0 | 0 |
|
| ⬜ | stdlib | 0 | 0 |
|
||||||
|
|||||||
111
lib/go/tests/types.sx
Normal file
111
lib/go/tests/types.sx
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
;; Go type-checker tests.
|
||||||
|
|
||||||
|
(define go-types-test-count 0)
|
||||||
|
(define go-types-test-pass 0)
|
||||||
|
(define go-types-test-fails (list))
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-types-test
|
||||||
|
(fn
|
||||||
|
(name actual expected)
|
||||||
|
(set! go-types-test-count (+ go-types-test-count 1))
|
||||||
|
(if
|
||||||
|
(= actual expected)
|
||||||
|
(set! go-types-test-pass (+ go-types-test-pass 1))
|
||||||
|
(append! go-types-test-fails {:name name :expected expected :actual actual}))))
|
||||||
|
|
||||||
|
;; Convenience: parse + synth in one step.
|
||||||
|
(define gtsy (fn (ctx src) (go-synth ctx (go-parse src))))
|
||||||
|
(define gtchk (fn (ctx src ty) (go-check ctx (go-parse src) ty)))
|
||||||
|
|
||||||
|
;; ── context helpers ──────────────────────────────────────────────
|
||||||
|
(go-types-test
|
||||||
|
"ctx: empty lookup returns nil"
|
||||||
|
(go-ctx-lookup go-ctx-empty "x")
|
||||||
|
nil)
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"ctx: extend then lookup"
|
||||||
|
(go-ctx-lookup (go-ctx-extend go-ctx-empty "x" (list :ty-name "int")) "x")
|
||||||
|
(list :ty-name "int"))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"ctx: shadow via extend"
|
||||||
|
(go-ctx-lookup
|
||||||
|
(go-ctx-extend
|
||||||
|
(go-ctx-extend go-ctx-empty "x" (list :ty-name "int"))
|
||||||
|
"x"
|
||||||
|
(list :ty-name "string"))
|
||||||
|
"x")
|
||||||
|
(list :ty-name "string"))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"ctx: extend-field binds all names"
|
||||||
|
(let
|
||||||
|
((ctx (go-ctx-extend-field go-ctx-empty (list :field (list "a" "b" "c") (list :ty-name "int")))))
|
||||||
|
(list
|
||||||
|
(go-ctx-lookup ctx "a")
|
||||||
|
(go-ctx-lookup ctx "b")
|
||||||
|
(go-ctx-lookup ctx "c")
|
||||||
|
(go-ctx-lookup ctx "d")))
|
||||||
|
(list
|
||||||
|
(list :ty-name "int")
|
||||||
|
(list :ty-name "int")
|
||||||
|
(list :ty-name "int")
|
||||||
|
nil))
|
||||||
|
|
||||||
|
;; ── predeclared identifiers ──────────────────────────────────────
|
||||||
|
(go-types-test
|
||||||
|
"predeclared: true"
|
||||||
|
(gtsy go-ctx-empty "true")
|
||||||
|
(list :ty-name "bool"))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"predeclared: false"
|
||||||
|
(gtsy go-ctx-empty "false")
|
||||||
|
(list :ty-name "bool"))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"predeclared: nil"
|
||||||
|
(gtsy go-ctx-empty "nil")
|
||||||
|
(list :ty-untyped-nil))
|
||||||
|
|
||||||
|
;; ── synth: variable lookup ──────────────────────────────────────
|
||||||
|
(go-types-test
|
||||||
|
"synth: bound variable returns its type"
|
||||||
|
(go-synth
|
||||||
|
(go-ctx-extend go-ctx-empty "x" (list :ty-name "int"))
|
||||||
|
(go-parse "x"))
|
||||||
|
(list :ty-name "int"))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"synth: unbound variable is a type error"
|
||||||
|
(go-synth go-ctx-empty (go-parse "ghost"))
|
||||||
|
(list :type-error :unbound "ghost"))
|
||||||
|
|
||||||
|
;; ── check: structural type equality ─────────────────────────────
|
||||||
|
(go-types-test
|
||||||
|
"check: ident vs declared type — matching"
|
||||||
|
(go-check
|
||||||
|
(go-ctx-extend go-ctx-empty "x" (list :ty-name "int"))
|
||||||
|
(go-parse "x")
|
||||||
|
(list :ty-name "int"))
|
||||||
|
:ok)
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"check: ident vs declared type — mismatch"
|
||||||
|
(go-check
|
||||||
|
(go-ctx-extend go-ctx-empty "x" (list :ty-name "int"))
|
||||||
|
(go-parse "x")
|
||||||
|
(list :ty-name "string"))
|
||||||
|
(list :type-error :mismatch (list :ty-name "string") (list :ty-name "int")))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"check: unbound propagates the synth error"
|
||||||
|
(go-check go-ctx-empty (go-parse "ghost") (list :ty-name "int"))
|
||||||
|
(list :type-error :unbound "ghost"))
|
||||||
|
|
||||||
|
;; ── report ──────────────────────────────────────────────────────
|
||||||
|
(define
|
||||||
|
go-types-test-summary
|
||||||
|
(str "types " go-types-test-pass "/" go-types-test-count))
|
||||||
125
lib/go/types.sx
Normal file
125
lib/go/types.sx
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
;; lib/go/types.sx — Go bidirectional type checker.
|
||||||
|
;;
|
||||||
|
;; Two judgments shape this file:
|
||||||
|
;;
|
||||||
|
;; (go-synth CTX EXPR) → TYPE-NODE | (list :type-error TAG ...)
|
||||||
|
;; Given a context and an expression, produce a type.
|
||||||
|
;;
|
||||||
|
;; (go-check CTX EXPR EXPECTED) → :ok | (list :type-error TAG ...)
|
||||||
|
;; Given a context, expression, and expected type, verify compatibility.
|
||||||
|
;;
|
||||||
|
;; The two judgments are mutually recursive. Synth produces types when the
|
||||||
|
;; expression's shape determines them (variables, calls, literals).
|
||||||
|
;; Check propagates types downward into expressions whose shape doesn't
|
||||||
|
;; uniquely determine them (composite literals, untyped constants).
|
||||||
|
;;
|
||||||
|
;; Type representations reuse the parser's :ty-* AST nodes from
|
||||||
|
;; lib/go/parse.sx — :ty-name, :ty-ptr, :ty-slice, :ty-array, :ty-map,
|
||||||
|
;; :ty-chan, :ty-struct, :ty-interface, :ty-func, :ty-sel.
|
||||||
|
;;
|
||||||
|
;; Context: an association list of (NAME TYPE) bindings. Per-block scope
|
||||||
|
;; via a fresh extension on entry.
|
||||||
|
;;
|
||||||
|
;; **Independent implementation.** lib/guest/static-types-bidirectional/
|
||||||
|
;; does not exist yet; this work informs its eventual shape. Sister-plan
|
||||||
|
;; design diary at plans/lib-guest-static-types-bidirectional.md tracks
|
||||||
|
;; the chiselling insights as Phase 3 progresses.
|
||||||
|
|
||||||
|
;; ── context ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
(define go-ctx-empty (list))
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-ctx-lookup
|
||||||
|
(fn
|
||||||
|
(ctx name)
|
||||||
|
(cond
|
||||||
|
(= (len ctx) 0)
|
||||||
|
nil
|
||||||
|
(= (first (first ctx)) name)
|
||||||
|
(nth (first ctx) 1)
|
||||||
|
:else (go-ctx-lookup (rest ctx) name))))
|
||||||
|
|
||||||
|
(define go-ctx-extend (fn (ctx name type) (cons (list name type) ctx)))
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-ctx-extend-field
|
||||||
|
(fn
|
||||||
|
(ctx field)
|
||||||
|
(let
|
||||||
|
((names (nth field 1)) (ty (nth field 2)))
|
||||||
|
(cond
|
||||||
|
(= (len names) 0)
|
||||||
|
ctx
|
||||||
|
:else (let
|
||||||
|
((rest-ctx (go-ctx-extend ctx (first names) ty)))
|
||||||
|
(cond
|
||||||
|
(= (len names) 1)
|
||||||
|
rest-ctx
|
||||||
|
:else (go-ctx-extend-field rest-ctx (list :field (rest names) ty))))))))
|
||||||
|
|
||||||
|
;; ── predeclared identifiers ──────────────────────────────────────
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-predeclared
|
||||||
|
(list
|
||||||
|
(list "true" (list :ty-name "bool"))
|
||||||
|
(list "false" (list :ty-name "bool"))
|
||||||
|
(list "nil" (list :ty-untyped-nil))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-predeclared-lookup
|
||||||
|
(fn
|
||||||
|
(name)
|
||||||
|
(cond
|
||||||
|
(= (len go-predeclared) 0)
|
||||||
|
nil
|
||||||
|
:else (go-ctx-lookup go-predeclared name))))
|
||||||
|
|
||||||
|
;; ── type predicates ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-type-error?
|
||||||
|
(fn
|
||||||
|
(x)
|
||||||
|
(and
|
||||||
|
(list? x)
|
||||||
|
(not (= (len x) 0))
|
||||||
|
(= (first x) :type-error))))
|
||||||
|
|
||||||
|
(define go-type-equal? (fn (a b) (= a b)))
|
||||||
|
|
||||||
|
;; ── synth ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-synth
|
||||||
|
(fn
|
||||||
|
(ctx expr)
|
||||||
|
(cond
|
||||||
|
(and (list? expr) (= (first expr) :var))
|
||||||
|
(let
|
||||||
|
((name (nth expr 1)))
|
||||||
|
(let
|
||||||
|
((pre (go-predeclared-lookup name)))
|
||||||
|
(cond
|
||||||
|
(not (= pre nil))
|
||||||
|
pre
|
||||||
|
:else (let
|
||||||
|
((t (go-ctx-lookup ctx name)))
|
||||||
|
(cond (= t nil) (list :type-error :unbound name) :else t)))))
|
||||||
|
:else (list :type-error :unsupported-synth expr))))
|
||||||
|
|
||||||
|
;; ── check ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-check
|
||||||
|
(fn
|
||||||
|
(ctx expr expected)
|
||||||
|
(let
|
||||||
|
((got (go-synth ctx expr)))
|
||||||
|
(cond
|
||||||
|
(go-type-error? got)
|
||||||
|
got
|
||||||
|
(go-type-equal? got expected)
|
||||||
|
:ok :else
|
||||||
|
(list :type-error :mismatch expected got)))))
|
||||||
@@ -214,22 +214,28 @@ Progress-log line → push `origin/loops/go`.
|
|||||||
deferred to a follow-up; it doesn't gate Phase 3.
|
deferred to a follow-up; it doesn't gate Phase 3.
|
||||||
|
|
||||||
### Phase 3 — Bidirectional type checker, MVP (`lib/go/types.sx`) ⬜
|
### Phase 3 — Bidirectional type checker, MVP (`lib/go/types.sx`) ⬜
|
||||||
- **Independent implementation.** Do NOT use lib/guest/static-types-
|
- [x] Scaffold: `go-synth` / `go-check` skeletons; context-as-value
|
||||||
bidirectional/ — that kit doesn't exist yet and depends on this work
|
(`go-ctx-empty` / `-extend` / `-lookup` / `-extend-field`);
|
||||||
for its design. See `plans/lib-guest-static-types-bidirectional.md`.
|
predeclared `true`/`false`/`nil`; structural type equality.
|
||||||
- Synth + check judgments. Context as a value (per-block scope).
|
- [ ] Literal kinds in AST (parser change: `(:literal KIND VALUE)`)
|
||||||
- Coverage MVP: declared-type variables, function signatures (params +
|
+ literal synth (`:ty-untyped-int`/`-float`/`-string`/`-rune`).
|
||||||
returns), call type-checking, simple composite types (slice, map, chan
|
- [ ] Binary-op synth with untyped-constant flow (canonical pitfall:
|
||||||
element), interface satisfaction (structural match against method sets),
|
`var x float64 = 42 / 7` must compute as untyped int / int = 6,
|
||||||
short variable declaration `:=` (synth from RHS).
|
then convert to float64).
|
||||||
- **Untyped constants.** `42` has type `untyped int` until contextualised;
|
- [ ] Var/const declaration checking (`var x T = expr`, `var x = expr`,
|
||||||
this is the canonical pitfall (see Gotchas below).
|
`const Pi = 3.14`).
|
||||||
- Defer: generics (Phase 7), full conversion rules.
|
- [ ] Function declaration: extend ctx with params via `:field` group,
|
||||||
- Tests: positive (type-correct programs check) + negative (mismatched
|
check body, verify return-list types match signature.
|
||||||
types fail with informative errors carrying AST paths).
|
- [ ] Call type-checking (synth callee, check args against param types,
|
||||||
- **Acceptance:** types/ suite at 60+ tests. Chisel note `shapes-static-
|
synth result).
|
||||||
types-bidirectional` — append a paragraph to the sister plan's design
|
- [ ] Composite type element checking (slice / map / chan).
|
||||||
diary describing what synth/check shape emerged.
|
- [ ] Interface satisfaction (structural match against method sets).
|
||||||
|
- [ ] Short variable declaration `:=` (synth RHS into LHS bindings).
|
||||||
|
- Defer: generics (Phase 7), full conversion rules, type assertions,
|
||||||
|
type switches.
|
||||||
|
- **Acceptance:** types/ suite at 60+ tests. Current: 12/12. Chisel note
|
||||||
|
`shapes-static-types-bidirectional` — sister-plan design diary is the
|
||||||
|
cross-language record.
|
||||||
|
|
||||||
### Phase 4 — Tree-walk evaluator (`lib/go/eval.sx`) ⬜
|
### Phase 4 — Tree-walk evaluator (`lib/go/eval.sx`) ⬜
|
||||||
- AST-walking interpreter over CEK. Each Go statement maps to one step
|
- AST-walking interpreter over CEK. Each Go statement maps to one step
|
||||||
@@ -528,6 +534,16 @@ Minimal repro: see `lib/go/lex.sx#gl-oct-digit?` and `#gl-match-op`.
|
|||||||
|
|
||||||
_Newest first. Append one dated entry per commit._
|
_Newest first. Append one dated entry per commit._
|
||||||
|
|
||||||
|
- 2026-05-27 — **Phase 3 scaffold.** First `lib/go/types.sx` cut: context
|
||||||
|
as an association list (`go-ctx-empty` + `-extend` + `-lookup`), a
|
||||||
|
load-bearing `go-ctx-extend-field` that consumes the `:field` binding-
|
||||||
|
group shape (validating the Phase 2 cross-deliverable observation),
|
||||||
|
predeclared `true`/`false`/`nil`, `go-synth` for identifier lookup,
|
||||||
|
`go-check` deferring to synth + structural equality. types suite
|
||||||
|
12/12, total 317/317. Literal kinds (untyped int/float/string/rune)
|
||||||
|
+ binop synth + var-decl checking next. `[shapes-static-types-
|
||||||
|
bidirectional]` — sister-plan diary updated with the synth/check
|
||||||
|
Go-side surface as it emerges.
|
||||||
- 2026-05-27 — **Phase 2 complete.** End-to-end multi-form file parsing.
|
- 2026-05-27 — **Phase 2 complete.** End-to-end multi-form file parsing.
|
||||||
`go-parse` now returns single forms for backward compat (~169 tests
|
`go-parse` now returns single forms for backward compat (~169 tests
|
||||||
unchanged) or `(list :file FORMS)` for multi-form input. Tests cover
|
unchanged) or `(list :file FORMS)` for multi-form input. Tests cover
|
||||||
|
|||||||
@@ -282,6 +282,36 @@ The kits compose; design accordingly.
|
|||||||
|
|
||||||
_Newest first. Append one dated entry per milestone landed._
|
_Newest first. Append one dated entry per milestone landed._
|
||||||
|
|
||||||
|
- 2026-05-27 — From Go-on-SX Phase 3 scaffold (`lib/go/types.sx` first
|
||||||
|
cut): the **independent synth/check shape** has landed. Two judgments,
|
||||||
|
both consuming a context-as-value:
|
||||||
|
|
||||||
|
```
|
||||||
|
(go-synth CTX EXPR) → TYPE-NODE | (:type-error TAG ...)
|
||||||
|
(go-check CTX EXPR EXPECTED) → :ok | (:type-error TAG ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
Context is an association list of `(NAME TYPE)` bindings; the
|
||||||
|
load-bearing extension primitive is `go-ctx-extend-field` which takes
|
||||||
|
a `(:field NAMES TYPE)` binding-group node and binds every NAME to
|
||||||
|
TYPE. This validates the earlier cross-deliverable observation: the
|
||||||
|
parser produces `:field` once, the type checker consumes it once,
|
||||||
|
same shape across struct fields / func params / var-decls.
|
||||||
|
|
||||||
|
**Design insight for the kit**: the synth/check pair is the canonical
|
||||||
|
judgment skeleton. `check` deferring to `synth + structural-equality`
|
||||||
|
is the v0 default that every consumer overrides for subtype-ish
|
||||||
|
relationships. The kit's `check` should accept a `subtype?` predicate
|
||||||
|
parameter so Go (untyped-constant flow), TS (variance), and Rust
|
||||||
|
(lifetime subtyping) each plug in their own variance discipline
|
||||||
|
without rewriting the whole judgment. The kit's `synth` stays uniform.
|
||||||
|
|
||||||
|
Error shape `(:type-error TAG ...)` with first-class tags
|
||||||
|
(`:unbound`, `:mismatch`, `:unsupported-synth`) gives consumers and
|
||||||
|
IDE tooling structured errors to dispatch on. Untyped-constant flow
|
||||||
|
and binop-synth — the canonical Go pitfall (`var x float64 = 42 / 7`)
|
||||||
|
— arrive next. Source: Go-on-SX commit landing `lib/go/types.sx`.
|
||||||
|
|
||||||
- 2026-05-27 — From Go-on-SX Phase 2 (func decls landing): parser-side
|
- 2026-05-27 — From Go-on-SX Phase 2 (func decls landing): parser-side
|
||||||
observation that's load-bearing for any bidirectional checker. Go's
|
observation that's load-bearing for any bidirectional checker. Go's
|
||||||
parser ended up with a single shape — `(list :field NAMES TYPE)` —
|
parser ended up with a single shape — `(list :field NAMES TYPE)` —
|
||||||
|
|||||||
Reference in New Issue
Block a user