go: types.sx — call type-checking + 8 tests; recursive funcs now type [nothing]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 36s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 36s
Phase 3 cont. The expression-synth :app dispatch is now bifurcated:
* go-is-binop-call? — head is :var with an operator name AND 2 args
AND the operator is in one of the binop tables. Short-circuits to
go-synth-binop as before.
* Everything else routes to go-synth-call.
go-synth-call:
1. Synth the callee. Must produce a (list :ty-func PARAMS RESULTS).
Otherwise → (:type-error :not-callable TYPE).
2. Arity-check args vs params. Mismatch → (:type-error :arity-mismatch).
3. go-check-args-against: each arg assignable to corresponding param
(untyped-constant flow works — `f(42)` accepts the untyped int
into an int param).
4. Result by count:
0 results → (list :ty-void)
1 result → that result directly
N results → (list :ty-tuple TYPES) for multi-return
The recursive case lights up: go-check-func-decl binds the function
in its own body's ctx before checking. So:
func fib(n int) int { return fib(n) + fib(n) }
now type-checks because `fib` resolves inside the body, synth-call
sees its `:ty-func` and verifies the recursive call. Multi-return
functions destructure into `:ty-tuple` which short-decl will need to
consume next iteration.
types 55/55, total 360/360.
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": 352,
|
"total_pass": 360,
|
||||||
"total": 352,
|
"total": 360,
|
||||||
"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":47,"total":47,"status":"ok"},
|
{"name":"types","pass":55,"total":55,"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: 352 / 352 tests passing**
|
**Total: 360 / 360 tests passing**
|
||||||
|
|
||||||
| | Suite | Pass | Total |
|
| | Suite | Pass | Total |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| ✅ | lex | 129 | 129 |
|
| ✅ | lex | 129 | 129 |
|
||||||
| ✅ | parse | 176 | 176 |
|
| ✅ | parse | 176 | 176 |
|
||||||
| ✅ | types | 47 | 47 |
|
| ✅ | types | 55 | 55 |
|
||||||
| ⬜ | eval | 0 | 0 |
|
| ⬜ | eval | 0 | 0 |
|
||||||
| ⬜ | runtime | 0 | 0 |
|
| ⬜ | runtime | 0 | 0 |
|
||||||
| ⬜ | stdlib | 0 | 0 |
|
| ⬜ | stdlib | 0 | 0 |
|
||||||
|
|||||||
@@ -326,6 +326,95 @@
|
|||||||
"g")
|
"g")
|
||||||
(list :ty-func (list) (list (list :ty-name "int"))))
|
(list :ty-func (list) (list (list :ty-name "int"))))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"call: synth result of typed func"
|
||||||
|
(go-synth
|
||||||
|
(go-ctx-extend
|
||||||
|
go-ctx-empty
|
||||||
|
"double"
|
||||||
|
(list
|
||||||
|
:ty-func (list (list :ty-name "int"))
|
||||||
|
(list (list :ty-name "int"))))
|
||||||
|
(go-parse "double(5)"))
|
||||||
|
(list :ty-name "int"))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"call: arg-count mismatch"
|
||||||
|
(go-synth
|
||||||
|
(go-ctx-extend
|
||||||
|
go-ctx-empty
|
||||||
|
"double"
|
||||||
|
(list
|
||||||
|
:ty-func (list (list :ty-name "int"))
|
||||||
|
(list (list :ty-name "int"))))
|
||||||
|
(go-parse "double(1, 2)"))
|
||||||
|
(list :type-error :arity-mismatch 1 2))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"call: arg-type mismatch"
|
||||||
|
(go-synth
|
||||||
|
(go-ctx-extend
|
||||||
|
go-ctx-empty
|
||||||
|
"f"
|
||||||
|
(list
|
||||||
|
:ty-func (list (list :ty-name "int"))
|
||||||
|
(list (list :ty-name "int"))))
|
||||||
|
(go-parse "f(\"hi\")"))
|
||||||
|
(list
|
||||||
|
:type-error :mismatch
|
||||||
|
(list :ty-name "int")
|
||||||
|
(list :ty-untyped-string)))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"call: not callable (calling an int)"
|
||||||
|
(go-synth
|
||||||
|
(go-ctx-extend go-ctx-empty "x" (list :ty-name "int"))
|
||||||
|
(go-parse "x(1)"))
|
||||||
|
(list :type-error :not-callable (list :ty-name "int")))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"call: no-result func (void) call"
|
||||||
|
(go-synth
|
||||||
|
(go-ctx-extend
|
||||||
|
go-ctx-empty
|
||||||
|
"log"
|
||||||
|
(list :ty-func (list (list :ty-name "string")) (list)))
|
||||||
|
(go-parse "log(\"hi\")"))
|
||||||
|
(list :ty-void))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"call: multi-return → :ty-tuple"
|
||||||
|
(go-synth
|
||||||
|
(go-ctx-extend
|
||||||
|
go-ctx-empty
|
||||||
|
"divmod"
|
||||||
|
(list
|
||||||
|
:ty-func (list (list :ty-name "int") (list :ty-name "int"))
|
||||||
|
(list (list :ty-name "int") (list :ty-name "int"))))
|
||||||
|
(go-parse "divmod(10, 3)"))
|
||||||
|
(list :ty-tuple (list (list :ty-name "int") (list :ty-name "int"))))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"call: recursive func works (fib)"
|
||||||
|
(go-ctx-lookup
|
||||||
|
(go-check-decl
|
||||||
|
go-ctx-empty
|
||||||
|
(go-parse "func fib(n int) int { return fib(n) + fib(n) }"))
|
||||||
|
"fib")
|
||||||
|
(list :ty-func (list (list :ty-name "int")) (list (list :ty-name "int"))))
|
||||||
|
|
||||||
|
(go-types-test
|
||||||
|
"call: untyped-int arg accepted into int param"
|
||||||
|
(go-synth
|
||||||
|
(go-ctx-extend
|
||||||
|
go-ctx-empty
|
||||||
|
"double"
|
||||||
|
(list
|
||||||
|
:ty-func (list (list :ty-name "int"))
|
||||||
|
(list (list :ty-name "int"))))
|
||||||
|
(go-parse "double(42)"))
|
||||||
|
(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))
|
||||||
|
|||||||
@@ -253,15 +253,67 @@
|
|||||||
(cond
|
(cond
|
||||||
(= t nil) (list :type-error :unbound name)
|
(= t nil) (list :type-error :unbound name)
|
||||||
:else t)))))
|
:else t)))))
|
||||||
;; (:app (:var OP) [LHS RHS]) — binary operator
|
;; (:app HEAD ARGS) — function application:
|
||||||
(and (list? expr) (= (first expr) :app)
|
;; binop if HEAD is :var with an operator name + 2 args
|
||||||
(list? (nth expr 1)) (= (first (nth expr 1)) :var)
|
;; else: general function call
|
||||||
(= (len (nth expr 2)) 2))
|
(and (list? expr) (= (first expr) :app))
|
||||||
(let ((op (nth (nth expr 1) 1))
|
(let ((head (nth expr 1)) (args (nth expr 2)))
|
||||||
(args (nth expr 2)))
|
(cond
|
||||||
(go-synth-binop ctx op (first args) (nth args 1)))
|
(go-is-binop-call? head args)
|
||||||
|
(go-synth-binop ctx (nth head 1) (first args) (nth args 1))
|
||||||
|
:else (go-synth-call ctx head args)))
|
||||||
:else (list :type-error :unsupported-synth expr))))
|
:else (list :type-error :unsupported-synth expr))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-is-binop-call?
|
||||||
|
(fn (head args)
|
||||||
|
(and (list? head) (= (first head) :var)
|
||||||
|
(= (len args) 2)
|
||||||
|
(let ((op (nth head 1)))
|
||||||
|
(or (some (fn (o) (= o op)) go-arith-binops)
|
||||||
|
(some (fn (o) (= o op)) go-bitwise-binops)
|
||||||
|
(some (fn (o) (= o op)) go-compare-binops)
|
||||||
|
(some (fn (o) (= o op)) go-logical-binops))))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-check-args-against
|
||||||
|
;; Each arg in ARGS assignable to the corresponding PARAMS type.
|
||||||
|
;; Caller already verified arities match.
|
||||||
|
(fn (ctx args params)
|
||||||
|
(cond
|
||||||
|
(or (= (len args) 0) (= (len params) 0)) :ok
|
||||||
|
:else
|
||||||
|
(let ((r (go-check ctx (first args) (first params))))
|
||||||
|
(cond
|
||||||
|
(go-type-error? r) r
|
||||||
|
:else (go-check-args-against ctx (rest args) (rest params)))))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
go-synth-call
|
||||||
|
;; Synth a function call. Returns the result type, or :type-error.
|
||||||
|
;; 0 results → (list :ty-void)
|
||||||
|
;; 1 result → that result type directly
|
||||||
|
;; N results → (list :ty-tuple TYPES) (multi-return)
|
||||||
|
(fn (ctx callee args)
|
||||||
|
(let ((fn-ty (go-synth ctx callee)))
|
||||||
|
(cond
|
||||||
|
(go-type-error? fn-ty) fn-ty
|
||||||
|
(not (and (list? fn-ty) (= (first fn-ty) :ty-func)))
|
||||||
|
(list :type-error :not-callable fn-ty)
|
||||||
|
:else
|
||||||
|
(let ((params (nth fn-ty 1)) (results (nth fn-ty 2)))
|
||||||
|
(cond
|
||||||
|
(not (= (len args) (len params)))
|
||||||
|
(list :type-error :arity-mismatch
|
||||||
|
(len params) (len args))
|
||||||
|
:else
|
||||||
|
(let ((err (go-check-args-against ctx args params)))
|
||||||
|
(cond
|
||||||
|
(go-type-error? err) err
|
||||||
|
(= (len results) 0) (list :ty-void)
|
||||||
|
(= (len results) 1) (first results)
|
||||||
|
:else (list :ty-tuple results)))))))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
go-synth-binop
|
go-synth-binop
|
||||||
(fn (ctx op lhs rhs)
|
(fn (ctx op lhs rhs)
|
||||||
|
|||||||
@@ -239,14 +239,17 @@ Progress-log line → push `origin/loops/go`.
|
|||||||
signature, assignments verify RHS assignable to LHS). The function
|
signature, assignments verify RHS assignable to LHS). The function
|
||||||
itself is bound in the body's ctx so recursion will work once
|
itself is bound in the body's ctx so recursion will work once
|
||||||
call-checking lands. Signature-only (no body) just binds.
|
call-checking lands. Signature-only (no body) just binds.
|
||||||
- [ ] Call type-checking (synth callee, check args against param types,
|
- [x] Call type-checking. `go-synth-call`: synth callee → expect
|
||||||
synth result).
|
`:ty-func`, arity-check, check each arg assignable to param,
|
||||||
|
then return type by result count (0 → `:ty-void`, 1 → that type,
|
||||||
|
N → `:ty-tuple`). Recursive calls now type-check because the func
|
||||||
|
is bound in the body's ctx. Untyped-constant args flow through.
|
||||||
- [ ] Composite type element checking (slice / map / chan).
|
- [ ] Composite type element checking (slice / map / chan).
|
||||||
- [ ] 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: 47/47. Chisel note
|
- **Acceptance:** types/ suite at 60+ tests. Current: 55/55. 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.
|
||||||
|
|
||||||
@@ -547,6 +550,20 @@ 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.: call type-checking. `go-synth-call`
|
||||||
|
synthesises the callee's type, asserts it's a `:ty-func`, arity-
|
||||||
|
checks args, then `go-check-args-against` runs each arg through
|
||||||
|
`go-check` against the corresponding param type (untyped-constant
|
||||||
|
flow works). Result: `:ty-void` for 0-result funcs, the result type
|
||||||
|
for 1-result, `(list :ty-tuple TYPES)` for multi-return. The
|
||||||
|
`:app` dispatch in `go-synth` now routes via `go-is-binop-call?`
|
||||||
|
(operator name + 2 args + op in the binop tables) — binops short-
|
||||||
|
circuit; everything else goes through the call path. **Recursive
|
||||||
|
functions now type-check** because the func is bound in its own
|
||||||
|
body's ctx by `go-check-func-decl`. +8 tests, types 55/55, total
|
||||||
|
360/360. `[nothing]` — Go-side composition on top of established
|
||||||
|
primitives; no new kit-relevant shapes (call semantics are uniform
|
||||||
|
across statically-typed guests).
|
||||||
- 2026-05-27 — Phase 3 cont.: function-declaration checking +
|
- 2026-05-27 — Phase 3 cont.: function-declaration checking +
|
||||||
statement-level dispatch. `go-check-func-decl` binds the function in
|
statement-level dispatch. `go-check-func-decl` binds the function in
|
||||||
the outer ctx (so the body can see itself), extends the body's ctx
|
the outer ctx (so the body can see itself), extends the body's ctx
|
||||||
|
|||||||
Reference in New Issue
Block a user