haskell: Phase 13 — where-clauses in instance bodies (desugar fix, +4 tests)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -131,112 +131,78 @@
|
|||||||
(let
|
(let
|
||||||
((tag (first node)))
|
((tag (first node)))
|
||||||
(cond
|
(cond
|
||||||
;; Transformations
|
|
||||||
((= tag "where")
|
((= tag "where")
|
||||||
(list
|
(list
|
||||||
:let
|
:let (map hk-desugar (nth node 2))
|
||||||
(map hk-desugar (nth node 2))
|
|
||||||
(hk-desugar (nth node 1))))
|
(hk-desugar (nth node 1))))
|
||||||
((= tag "guarded") (hk-guards-to-if (nth node 1)))
|
((= tag "guarded") (hk-guards-to-if (nth node 1)))
|
||||||
((= tag "list-comp")
|
((= tag "list-comp")
|
||||||
(hk-lc-desugar
|
(hk-lc-desugar (hk-desugar (nth node 1)) (nth node 2)))
|
||||||
(hk-desugar (nth node 1))
|
|
||||||
(nth node 2)))
|
|
||||||
|
|
||||||
;; Expression nodes
|
|
||||||
((= tag "app")
|
((= tag "app")
|
||||||
(list
|
(list
|
||||||
:app
|
:app (hk-desugar (nth node 1))
|
||||||
(hk-desugar (nth node 1))
|
|
||||||
(hk-desugar (nth node 2))))
|
(hk-desugar (nth node 2))))
|
||||||
((= tag "op")
|
((= tag "op")
|
||||||
(list
|
(list
|
||||||
:op
|
:op (nth node 1)
|
||||||
(nth node 1)
|
|
||||||
(hk-desugar (nth node 2))
|
(hk-desugar (nth node 2))
|
||||||
(hk-desugar (nth node 3))))
|
(hk-desugar (nth node 3))))
|
||||||
((= tag "neg") (list :neg (hk-desugar (nth node 1))))
|
((= tag "neg") (list :neg (hk-desugar (nth node 1))))
|
||||||
((= tag "if")
|
((= tag "if")
|
||||||
(list
|
(list
|
||||||
:if
|
:if (hk-desugar (nth node 1))
|
||||||
(hk-desugar (nth node 1))
|
|
||||||
(hk-desugar (nth node 2))
|
(hk-desugar (nth node 2))
|
||||||
(hk-desugar (nth node 3))))
|
(hk-desugar (nth node 3))))
|
||||||
((= tag "tuple")
|
((= tag "tuple") (list :tuple (map hk-desugar (nth node 1))))
|
||||||
(list :tuple (map hk-desugar (nth node 1))))
|
((= tag "list") (list :list (map hk-desugar (nth node 1))))
|
||||||
((= tag "list")
|
|
||||||
(list :list (map hk-desugar (nth node 1))))
|
|
||||||
((= tag "range")
|
((= tag "range")
|
||||||
(list
|
(list
|
||||||
:range
|
:range (hk-desugar (nth node 1))
|
||||||
(hk-desugar (nth node 1))
|
|
||||||
(hk-desugar (nth node 2))))
|
(hk-desugar (nth node 2))))
|
||||||
((= tag "range-step")
|
((= tag "range-step")
|
||||||
(list
|
(list
|
||||||
:range-step
|
:range-step (hk-desugar (nth node 1))
|
||||||
(hk-desugar (nth node 1))
|
|
||||||
(hk-desugar (nth node 2))
|
(hk-desugar (nth node 2))
|
||||||
(hk-desugar (nth node 3))))
|
(hk-desugar (nth node 3))))
|
||||||
((= tag "lambda")
|
((= tag "lambda")
|
||||||
(list
|
(list :lambda (nth node 1) (hk-desugar (nth node 2))))
|
||||||
:lambda
|
|
||||||
(nth node 1)
|
|
||||||
(hk-desugar (nth node 2))))
|
|
||||||
((= tag "let")
|
((= tag "let")
|
||||||
(list
|
(list
|
||||||
:let
|
:let (map hk-desugar (nth node 1))
|
||||||
(map hk-desugar (nth node 1))
|
|
||||||
(hk-desugar (nth node 2))))
|
(hk-desugar (nth node 2))))
|
||||||
((= tag "case")
|
((= tag "case")
|
||||||
(list
|
(list
|
||||||
:case
|
:case (hk-desugar (nth node 1))
|
||||||
(hk-desugar (nth node 1))
|
|
||||||
(map hk-desugar (nth node 2))))
|
(map hk-desugar (nth node 2))))
|
||||||
((= tag "alt")
|
((= tag "alt")
|
||||||
(list :alt (nth node 1) (hk-desugar (nth node 2))))
|
(list :alt (nth node 1) (hk-desugar (nth node 2))))
|
||||||
((= tag "do") (hk-desugar-do (nth node 1)))
|
((= tag "do") (hk-desugar-do (nth node 1)))
|
||||||
((= tag "sect-left")
|
((= tag "sect-left")
|
||||||
(list
|
(list :sect-left (nth node 1) (hk-desugar (nth node 2))))
|
||||||
:sect-left
|
|
||||||
(nth node 1)
|
|
||||||
(hk-desugar (nth node 2))))
|
|
||||||
((= tag "sect-right")
|
((= tag "sect-right")
|
||||||
(list
|
(list :sect-right (nth node 1) (hk-desugar (nth node 2))))
|
||||||
:sect-right
|
|
||||||
(nth node 1)
|
|
||||||
(hk-desugar (nth node 2))))
|
|
||||||
|
|
||||||
;; Top-level
|
|
||||||
((= tag "program")
|
((= tag "program")
|
||||||
(list :program (map hk-desugar (nth node 1))))
|
(list :program (map hk-desugar (nth node 1))))
|
||||||
((= tag "module")
|
((= tag "module")
|
||||||
(list
|
(list
|
||||||
:module
|
:module (nth node 1)
|
||||||
(nth node 1)
|
|
||||||
(nth node 2)
|
(nth node 2)
|
||||||
(nth node 3)
|
(nth node 3)
|
||||||
(map hk-desugar (nth node 4))))
|
(map hk-desugar (nth node 4))))
|
||||||
|
|
||||||
;; Decls carrying a body
|
|
||||||
((= tag "fun-clause")
|
((= tag "fun-clause")
|
||||||
(list
|
(list
|
||||||
:fun-clause
|
:fun-clause (nth node 1)
|
||||||
(nth node 1)
|
|
||||||
(nth node 2)
|
(nth node 2)
|
||||||
(hk-desugar (nth node 3))))
|
(hk-desugar (nth node 3))))
|
||||||
|
((= tag "instance-decl")
|
||||||
|
(list
|
||||||
|
:instance-decl (nth node 1)
|
||||||
|
(nth node 2)
|
||||||
|
(map hk-desugar (nth node 3))))
|
||||||
((= tag "pat-bind")
|
((= tag "pat-bind")
|
||||||
(list
|
(list :pat-bind (nth node 1) (hk-desugar (nth node 2))))
|
||||||
:pat-bind
|
|
||||||
(nth node 1)
|
|
||||||
(hk-desugar (nth node 2))))
|
|
||||||
((= tag "bind")
|
((= tag "bind")
|
||||||
(list
|
(list :bind (nth node 1) (hk-desugar (nth node 2))))
|
||||||
:bind
|
|
||||||
(nth node 1)
|
|
||||||
(hk-desugar (nth node 2))))
|
|
||||||
|
|
||||||
;; Everything else: leaf literals, vars, cons, patterns,
|
|
||||||
;; types, imports, type-sigs, data / newtype / fixity, …
|
|
||||||
(:else node)))))))
|
(:else node)))))))
|
||||||
|
|
||||||
;; Convenience — tokenize + layout + parse + desugar.
|
;; Convenience — tokenize + layout + parse + desugar.
|
||||||
|
|||||||
31
lib/haskell/tests/instance-where.sx
Normal file
31
lib/haskell/tests/instance-where.sx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
;; instance-where.sx — Phase 13: where-clauses inside instance bodies.
|
||||||
|
|
||||||
|
(hk-test
|
||||||
|
"instance method body with where-helper (Bool)"
|
||||||
|
(hk-deep-force
|
||||||
|
(hk-run
|
||||||
|
"class Greet a where\n greet :: a -> String\ninstance Greet Bool where\n greet x = mkMsg x\n where mkMsg True = \"yes\"\n mkMsg False = \"no\"\nmain = greet True"))
|
||||||
|
"yes")
|
||||||
|
|
||||||
|
(hk-test
|
||||||
|
"instance method body with where-helper (False branch)"
|
||||||
|
(hk-deep-force
|
||||||
|
(hk-run
|
||||||
|
"class Greet a where\n greet :: a -> String\ninstance Greet Bool where\n greet x = mkMsg x\n where mkMsg True = \"yes\"\n mkMsg False = \"no\"\nmain = greet False"))
|
||||||
|
"no")
|
||||||
|
|
||||||
|
(hk-test
|
||||||
|
"instance method body with where-binding referenced multiple times"
|
||||||
|
(hk-deep-force
|
||||||
|
(hk-run
|
||||||
|
"class Twice a where\n twice :: a -> Int\ninstance Twice Int where\n twice x = h + h\n where h = x + 1\nmain = twice 5"))
|
||||||
|
12)
|
||||||
|
|
||||||
|
(hk-test
|
||||||
|
"instance method body with multi-binding where"
|
||||||
|
(hk-deep-force
|
||||||
|
(hk-run
|
||||||
|
"class Calc a where\n calc :: a -> Int\ninstance Calc Int where\n calc x = a + b\n where a = x * 2\n b = x + 1\nmain = calc 3"))
|
||||||
|
10)
|
||||||
|
|
||||||
|
{:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}
|
||||||
@@ -220,7 +220,7 @@ No OCaml changes are needed. The view type is fully representable as an SX dict.
|
|||||||
|
|
||||||
### Phase 13 — `where` in typeclass instances + default methods
|
### Phase 13 — `where` in typeclass instances + default methods
|
||||||
|
|
||||||
- [ ] Verify `where`-clauses in `instance` bodies desugar correctly. The
|
- [x] Verify `where`-clauses in `instance` bodies desugar correctly. The
|
||||||
`hk-bind-decls!` instance arm must call the same where-lifting logic as
|
`hk-bind-decls!` instance arm must call the same where-lifting logic as
|
||||||
top-level function clauses. Write a targeted test to confirm.
|
top-level function clauses. Write a targeted test to confirm.
|
||||||
- [ ] Class declarations may include default method implementations. Parser:
|
- [ ] Class declarations may include default method implementations. Parser:
|
||||||
@@ -307,6 +307,18 @@ No OCaml changes are needed. The view type is fully representable as an SX dict.
|
|||||||
|
|
||||||
_Newest first._
|
_Newest first._
|
||||||
|
|
||||||
|
**2026-05-07** — Phase 13 `where`-clauses in `instance` bodies:
|
||||||
|
- Bug discovered: `hk-desugar` didn't recurse into `instance-decl` method
|
||||||
|
bodies, so a `where`-form in an instance method survived to eval and hit
|
||||||
|
`eval: unknown node tag 'where'`. Fix: added an `instance-decl` case to
|
||||||
|
the desugarer that maps `hk-desugar` over the method-decls list. The
|
||||||
|
existing `fun-clause` branch then desugars each method body, including
|
||||||
|
the where → let lifting.
|
||||||
|
- 4 tests in new `tests/instance-where.sx`: where-helper with literal
|
||||||
|
pattern matching, references reused multiple times, and multi-binding
|
||||||
|
where. Verified no regression in class.sx (14/14), deriving.sx (15/15),
|
||||||
|
desugar.sx (15/15).
|
||||||
|
|
||||||
**2026-05-07** — Phase 12 conformance: uniquewords.hs (4/4) + setops.hs (8/8) → Phase 12 complete:
|
**2026-05-07** — Phase 12 conformance: uniquewords.hs (4/4) + setops.hs (8/8) → Phase 12 complete:
|
||||||
- `program-uniquewords.sx`: `foldl Set.insert` over a word list, then check
|
- `program-uniquewords.sx`: `foldl Set.insert` over a word list, then check
|
||||||
`Set.size`/`member`. 4/4.
|
`Set.size`/`member`. 4/4.
|
||||||
|
|||||||
Reference in New Issue
Block a user