go: types.sx — composite-literal element checking; Phase 3 bar crossed + 10 tests [nothing]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 32s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 32s
Phase 3 cont. Adds composite-literal type-checking via go-synth-composite:
[]T{...} — go-check-composite-elems with VAL-TY=T, KEY-TY=nil.
Each plain elem assignable to T; :kv element accepted
(Go's index-keyed shorthand: `[]int{0: 5, 1: 10}`)
with only the value checked.
[N]T{...} — same as slice; result :ty-array N T.
map[K]V{...} — KEY-TY=K, VAL-TY=V. Each :kv pair: key assignable
to K, value to V. Non-:kv elements in maps are
(:type-error :map-elem-missing-key).
The literal's *synthesised* type is the type expression itself, so
nested composites fall out by recursion:
[][]int{[]int{1,2}, []int{3,4}}
→ outer: go-check-composite-elems with VAL-TY=[]int
→ each inner []int{1,2} goes through go-synth-composite recursively,
yielding :ty-slice :ty-name "int" — assignable-equal to VAL-TY.
Coverage: positive cases (homogeneous slices/arrays/maps, empty
slice, nested), and three negative cases (slice element mismatch,
map key mismatch, map value mismatch). Also a decl test:
var x = []int{1, 2, 3} → binds x to :ty-slice :ty-name "int"
Named-type literals (`Point{1,2}`, `pkg.T{...}`) need type-decl-driven
field resolution; deferred. Interface satisfaction and AST-path error
context also remain — neither gates Phase 4.
**Phase 3 acceptance bar (60+) crossed: types 65/65, total 370/370.**
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"language": "go",
|
"language": "go",
|
||||||
"total_pass": 360,
|
"total_pass": 370,
|
||||||
"total": 360,
|
"total": 370,
|
||||||
"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":55,"total":55,"status":"ok"},
|
{"name":"types","pass":65,"total":65,"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: 360 / 360 tests passing**
|
**Total: 370 / 370 tests passing**
|
||||||
|
|
||||||
| | Suite | Pass | Total |
|
| | Suite | Pass | Total |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ✅ | lex | 129 | 129 |
|
| ✅ | lex | 129 | 129 |
|
||||||
| ✅ | parse | 176 | 176 |
|
| ✅ | parse | 176 | 176 |
|
||||||
| ✅ | types | 55 | 55 |
|
| ✅ | types | 65 | 65 |
|
||||||
| ⬜ | eval | 0 | 0 |
|
| ⬜ | eval | 0 | 0 |
|
||||||
| ⬜ | runtime | 0 | 0 |
|
| ⬜ | runtime | 0 | 0 |
|
||||||
| ⬜ | stdlib | 0 | 0 |
|
| ⬜ | stdlib | 0 | 0 |
|
||||||
|
|||||||
@@ -415,6 +415,67 @@
|
|||||||
(go-parse "double(42)"))
|
(go-parse "double(42)"))
|
||||||
(list :ty-name "int"))
|
(list :ty-name "int"))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"composite: []int{1,2,3} — synth slice type"
|
||||||
|
(gtsy go-ctx-empty "[]int{1, 2, 3}")
|
||||||
|
(list :ty-slice (list :ty-name "int")))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"composite: []string{\"a\",\"b\"}"
|
||||||
|
(gtsy go-ctx-empty "[]string{\"a\", \"b\"}")
|
||||||
|
(list :ty-slice (list :ty-name "string")))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"composite: []int{1, \"bad\"} — element type-error"
|
||||||
|
(gtsy go-ctx-empty "[]int{1, \"bad\"}")
|
||||||
|
(list
|
||||||
|
:type-error :mismatch
|
||||||
|
(list :ty-name "int")
|
||||||
|
(list :ty-untyped-string)))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"composite: empty []int{}"
|
||||||
|
(gtsy go-ctx-empty "[]int{}")
|
||||||
|
(list :ty-slice (list :ty-name "int")))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"composite: [3]int{1,2,3} array"
|
||||||
|
(gtsy go-ctx-empty "[3]int{1, 2, 3}")
|
||||||
|
(list :ty-array (list :literal "3") (list :ty-name "int")))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"composite: map[string]int — synth map type"
|
||||||
|
(gtsy go-ctx-empty "map[string]int{\"a\": 1, \"b\": 2}")
|
||||||
|
(list :ty-map (list :ty-name "string") (list :ty-name "int")))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"composite: map value type-error"
|
||||||
|
(gtsy go-ctx-empty "map[string]int{\"a\": \"bad\"}")
|
||||||
|
(list
|
||||||
|
:type-error :mismatch
|
||||||
|
(list :ty-name "int")
|
||||||
|
(list :ty-untyped-string)))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"composite: map key type-error"
|
||||||
|
(gtsy go-ctx-empty "map[string]int{42: 1}")
|
||||||
|
(list
|
||||||
|
:type-error :mismatch
|
||||||
|
(list :ty-name "string")
|
||||||
|
(list :ty-untyped-int)))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"composite: nested [][]int{[]int{1,2}, []int{3,4}}"
|
||||||
|
(gtsy go-ctx-empty "[][]int{[]int{1, 2}, []int{3, 4}}")
|
||||||
|
(list :ty-slice (list :ty-slice (list :ty-name "int"))))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"composite: var x = []int{1,2,3} — inferred slice"
|
||||||
|
(go-ctx-lookup
|
||||||
|
(go-check-decl go-ctx-empty (go-parse "var x = []int{1, 2, 3}"))
|
||||||
|
"x")
|
||||||
|
(list :ty-slice (list :ty-name "int")))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
go-types-test-summary
|
go-types-test-summary
|
||||||
(str "types " go-types-test-pass "/" go-types-test-count))
|
(str "types " go-types-test-pass "/" go-types-test-count))
|
||||||
|
|||||||
@@ -262,6 +262,9 @@
|
|||||||
(go-is-binop-call? head args)
|
(go-is-binop-call? head args)
|
||||||
(go-synth-binop ctx (nth head 1) (first args) (nth args 1))
|
(go-synth-binop ctx (nth head 1) (first args) (nth args 1))
|
||||||
:else (go-synth-call ctx head args)))
|
:else (go-synth-call ctx head args)))
|
||||||
|
;; (:composite TYPE-OR-EXPR ELEMS) — composite literal
|
||||||
|
(and (list? expr) (= (first expr) :composite))
|
||||||
|
(go-synth-composite ctx (nth expr 1) (nth expr 2))
|
||||||
:else (list :type-error :unsupported-synth expr))))
|
:else (list :type-error :unsupported-synth expr))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
@@ -288,6 +291,65 @@
|
|||||||
(go-type-error? r) r
|
(go-type-error? r) r
|
||||||
:else (go-check-args-against ctx (rest args) (rest params)))))))
|
:else (go-check-args-against ctx (rest args) (rest params)))))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-check-composite-elems
|
||||||
|
;; KEY-TY is nil for slice/array; non-nil for map.
|
||||||
|
;; For maps, each elem must be (:kv KEY VALUE) — KEY assignable to
|
||||||
|
;; KEY-TY, VALUE to VAL-TY.
|
||||||
|
;; For slice/array, plain exprs assignable to VAL-TY; (:kv K V) is
|
||||||
|
;; Go's index-keyed shorthand (`[]int{0: 5, 1: 10}`) — we type-check
|
||||||
|
;; only the value in v0.
|
||||||
|
(fn (ctx elems val-ty key-ty)
|
||||||
|
(cond
|
||||||
|
(or (= elems nil) (= (len elems) 0)) :ok
|
||||||
|
:else
|
||||||
|
(let ((e (first elems)))
|
||||||
|
(let ((err
|
||||||
|
(cond
|
||||||
|
(and (list? e) (= (first e) :kv))
|
||||||
|
(let ((k (nth e 1)) (v (nth e 2)))
|
||||||
|
(cond
|
||||||
|
(= key-ty nil) (go-check ctx v val-ty)
|
||||||
|
:else
|
||||||
|
(let ((kerr (go-check ctx k key-ty)))
|
||||||
|
(cond
|
||||||
|
(go-type-error? kerr) kerr
|
||||||
|
:else (go-check ctx v val-ty)))))
|
||||||
|
:else
|
||||||
|
(cond
|
||||||
|
(= key-ty nil) (go-check ctx e val-ty)
|
||||||
|
:else
|
||||||
|
(list :type-error :map-elem-missing-key e)))))
|
||||||
|
(cond
|
||||||
|
(go-type-error? err) err
|
||||||
|
:else
|
||||||
|
(go-check-composite-elems ctx (rest elems) val-ty key-ty)))))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-synth-composite
|
||||||
|
;; Composite literal: (:composite TYPE-OR-EXPR ELEMS).
|
||||||
|
;; []T{...} — each elem assignable to T; result :ty-slice T
|
||||||
|
;; [N]T{...} — same; result :ty-array N T
|
||||||
|
;; map[K]V{...} — each :kv key:K, value:V; result :ty-map K V
|
||||||
|
;; Named-type literals (Point{...}, pkg.T{...}) require type-decl
|
||||||
|
;; resolution; v0 returns the literal's type-expr as-is without
|
||||||
|
;; element checking.
|
||||||
|
(fn (ctx ty elems)
|
||||||
|
(cond
|
||||||
|
(and (list? ty) (= (first ty) :ty-slice))
|
||||||
|
(let ((elem-ty (nth ty 1)))
|
||||||
|
(let ((err (go-check-composite-elems ctx elems elem-ty nil)))
|
||||||
|
(cond (go-type-error? err) err :else ty)))
|
||||||
|
(and (list? ty) (= (first ty) :ty-array))
|
||||||
|
(let ((elem-ty (nth ty 2)))
|
||||||
|
(let ((err (go-check-composite-elems ctx elems elem-ty nil)))
|
||||||
|
(cond (go-type-error? err) err :else ty)))
|
||||||
|
(and (list? ty) (= (first ty) :ty-map))
|
||||||
|
(let ((key-ty (nth ty 1)) (val-ty (nth ty 2)))
|
||||||
|
(let ((err (go-check-composite-elems ctx elems val-ty key-ty)))
|
||||||
|
(cond (go-type-error? err) err :else ty)))
|
||||||
|
:else ty)))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
go-synth-call
|
go-synth-call
|
||||||
;; Synth a function call. Returns the result type, or :type-error.
|
;; Synth a function call. Returns the result type, or :type-error.
|
||||||
|
|||||||
@@ -244,12 +244,19 @@ Progress-log line → push `origin/loops/go`.
|
|||||||
then return type by result count (0 → `:ty-void`, 1 → that type,
|
then return type by result count (0 → `:ty-void`, 1 → that type,
|
||||||
N → `:ty-tuple`). Recursive calls now type-check because the func
|
N → `:ty-tuple`). Recursive calls now type-check because the func
|
||||||
is bound in the body's ctx. Untyped-constant args flow through.
|
is bound in the body's ctx. Untyped-constant args flow through.
|
||||||
- [ ] Composite type element checking (slice / map / chan).
|
- [x] Composite literal element checking — slice `[]T{...}`, array
|
||||||
|
`[N]T{...}`, map `map[K]V{...}` (key + value checked).
|
||||||
|
`:kv` element with no key on slice/array is permitted (Go's
|
||||||
|
index-keyed shorthand). Nested composite literals work
|
||||||
|
(`[][]int{[]int{1,2}, []int{3,4}}`). Named-type composite
|
||||||
|
literals (`Point{...}`) need type-decl resolution; deferred.
|
||||||
- [ ] Interface satisfaction (structural match against method sets).
|
- [ ] Interface satisfaction (structural match against method sets).
|
||||||
- [ ] Short variable declaration `:=` (synth RHS into LHS bindings).
|
- [ ] Short variable declaration `:=` (synth RHS into LHS bindings).
|
||||||
- Defer: generics (Phase 7), full conversion rules, type assertions,
|
- Defer: generics (Phase 7), full conversion rules, type assertions,
|
||||||
type switches.
|
type switches.
|
||||||
- **Acceptance:** types/ suite at 60+ tests. Current: 55/55. Chisel note
|
- **Acceptance:** types/ suite at 60+ tests. **Bar crossed: 65/65.**
|
||||||
|
Remaining sub-items (interface satisfaction, error reporting carrying
|
||||||
|
AST paths) refine but don't gate Phase 4. Chisel note
|
||||||
`shapes-static-types-bidirectional` — sister-plan design diary is the
|
`shapes-static-types-bidirectional` — sister-plan design diary is the
|
||||||
cross-language record.
|
cross-language record.
|
||||||
|
|
||||||
@@ -550,6 +557,19 @@ 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 cont.: composite-literal element checking.
|
||||||
|
`go-synth-composite` dispatches on the literal's type expression:
|
||||||
|
`:ty-slice` and `:ty-array` check each element assignable to the
|
||||||
|
element type; `:ty-map` checks each `:kv` pair (key against K, value
|
||||||
|
against V) and rejects non-`:kv` map elements. The literal's
|
||||||
|
synthesised type is the type-expression itself, so nested composites
|
||||||
|
fall out by recursion: `[][]int{[]int{1,2}, []int{3,4}}` checks each
|
||||||
|
inner `[]int{...}` as a value of type `[]int`. Named-type literals
|
||||||
|
(`Point{1,2}`, `pkg.T{...}`) need type-decl-driven field resolution;
|
||||||
|
deferred. **Phase 3 acceptance bar (60+ tests) crossed: 65/65, total
|
||||||
|
370/370.** `[nothing]` — composite-literal semantics are mostly Go-
|
||||||
|
specific. Remaining Phase 3 items (interface satisfaction; AST-path
|
||||||
|
error context) sharpen the surface but don't gate Phase 4 (evaluator).
|
||||||
- 2026-05-27 — Phase 3 cont.: call type-checking. `go-synth-call`
|
- 2026-05-27 — Phase 3 cont.: call type-checking. `go-synth-call`
|
||||||
synthesises the callee's type, asserts it's a `:ty-func`, arity-
|
synthesises the callee's type, asserts it's a `:ty-func`, arity-
|
||||||
checks args, then `go-check-args-against` runs each arg through
|
checks args, then `go-check-args-against` runs each arg through
|
||||||
|
|||||||
Reference in New Issue
Block a user