go: types.sx — literal synth + binop + assignability; canonical pitfall handled + 16 tests [shapes-static-types-bidirectional]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 29s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 29s
Phase 3 cont. Adds:
* go-classify-literal-string — heuristic detection of literal kind
from the value-string (parser strips lexer's kind tag; flagged for
follow-up to extend AST shape).
* go-synth-literal — :ty-untyped-int / -float / -imag / -string.
* go-synth-binop — arithmetic, bitwise, comparison, logical ops with
untyped-constant unification:
untyped-int + untyped-float → untyped-float
untyped + typed → typed
comparison ops → bool
logical ops → bool
* go-untyped? + go-type-assignable? — pluggable assignability that
swaps in where structural equality used to gate go-check. Untyped
int assignable to any numeric type; untyped float assignable to
float/complex; untyped string to string.
**Canonical Go pitfall handled correctly**: `var x float64 = 42 / 7`
parses to a binop, synth produces :ty-untyped-int (since BOTH operands
are untyped, the int division stays in the int domain), and check
against float64 returns :ok via assignability. Wrong implementations
that float-coerce eagerly would give 6.0; the right behaviour is
"compute 6 as int, then convert to float64 = 6.0".
Verified by test "binop: 42 / 7 assignable to float64 (canonical
pitfall)" and the type-only test "binop: 42 / 7 — untyped int".
Sister-plan static-types-bidirectional diary updated with the
**pluggable-assignable-predicate** kit-API proposal:
(check-with assignable? CTX EXPR EXPECTED)
Each consumer plugs in its own variance discipline (Go untyped-flow,
TS structural subtyping, Rust lifetime-aware identity) without
rewriting synth or the judgment skeleton.
types 28/28, total 333/333.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -106,6 +106,91 @@
|
||||
(list :type-error :unbound "ghost"))
|
||||
|
||||
;; ── report ──────────────────────────────────────────────────────
|
||||
(go-types-test
|
||||
"synth: int literal — untyped int"
|
||||
(gtsy go-ctx-empty "42")
|
||||
(list :ty-untyped-int))
|
||||
|
||||
(go-types-test
|
||||
"synth: float literal — untyped float"
|
||||
(gtsy go-ctx-empty "3.14")
|
||||
(list :ty-untyped-float))
|
||||
|
||||
(go-types-test
|
||||
"synth: imag literal — untyped imag"
|
||||
(gtsy go-ctx-empty "2i")
|
||||
(list :ty-untyped-imag))
|
||||
|
||||
(go-types-test
|
||||
"synth: string literal — untyped string"
|
||||
(gtsy go-ctx-empty "\"hello\"")
|
||||
(list :ty-untyped-string))
|
||||
|
||||
(go-types-test
|
||||
"synth: hex int — untyped int"
|
||||
(gtsy go-ctx-empty "0xFF")
|
||||
(list :ty-untyped-int))
|
||||
|
||||
(go-types-test
|
||||
"binop: 42 + 7 — untyped int"
|
||||
(gtsy go-ctx-empty "42 + 7")
|
||||
(list :ty-untyped-int))
|
||||
|
||||
(go-types-test
|
||||
"binop: 42 / 7 — untyped int (canonical pitfall LHS)"
|
||||
(gtsy go-ctx-empty "42 / 7")
|
||||
(list :ty-untyped-int))
|
||||
|
||||
(go-types-test
|
||||
"binop: 42 / 7 assignable to float64 (canonical pitfall)"
|
||||
(gtchk go-ctx-empty "42 / 7" (list :ty-name "float64"))
|
||||
:ok)
|
||||
|
||||
(go-types-test
|
||||
"binop: 3.14 * 2.0 — untyped float"
|
||||
(gtsy go-ctx-empty "3.14 * 2.0")
|
||||
(list :ty-untyped-float))
|
||||
|
||||
(go-types-test
|
||||
"binop: 1 + 2.5 — untyped int + untyped float → untyped float"
|
||||
(gtsy go-ctx-empty "1 + 2.5")
|
||||
(list :ty-untyped-float))
|
||||
|
||||
(go-types-test
|
||||
"binop: comparison produces bool"
|
||||
(gtsy go-ctx-empty "1 < 2")
|
||||
(list :ty-name "bool"))
|
||||
|
||||
(go-types-test
|
||||
"binop: typed-var + untyped-int — propagates var's type"
|
||||
(go-synth
|
||||
(go-ctx-extend go-ctx-empty "x" (list :ty-name "int64"))
|
||||
(go-parse "x + 1"))
|
||||
(list :ty-name "int64"))
|
||||
|
||||
(go-types-test
|
||||
"assign: untyped-int → int"
|
||||
(gtchk go-ctx-empty "42" (list :ty-name "int"))
|
||||
:ok)
|
||||
|
||||
(go-types-test
|
||||
"assign: untyped-int → float32"
|
||||
(gtchk go-ctx-empty "42" (list :ty-name "float32"))
|
||||
:ok)
|
||||
|
||||
(go-types-test
|
||||
"assign: untyped-int → string fails"
|
||||
(gtchk go-ctx-empty "42" (list :ty-name "string"))
|
||||
(list
|
||||
:type-error :mismatch
|
||||
(list :ty-name "string")
|
||||
(list :ty-untyped-int)))
|
||||
|
||||
(go-types-test
|
||||
"assign: untyped-string → string"
|
||||
(gtchk go-ctx-empty "\"hi\"" (list :ty-name "string"))
|
||||
:ok)
|
||||
|
||||
(define
|
||||
go-types-test-summary
|
||||
(str "types " go-types-test-pass "/" go-types-test-count))
|
||||
|
||||
Reference in New Issue
Block a user