Merge loops/haskell into architecture: Phase 17 — import decls, type annotations, typecheck 15/15

This commit is contained in:
2026-05-12 14:45:44 +00:00
5 changed files with 247 additions and 34 deletions

View File

@@ -316,11 +316,11 @@ No OCaml changes are needed. The view type is fully representable as an SX dict.
Real Haskell programs use these on every page; closing the gaps unblocks
larger conformance programs and removes one-line workarounds in test sources.
- [ ] Type annotations in expressions: `(x :: Int)`, `f (1 :: Int)`,
- [x] Type annotations in expressions: `(x :: Int)`, `f (1 :: Int)`,
`return (42 :: Int)`. Parser currently rejects `::` in `aexp` position;
desugar should drop the annotation (we have no inference at this layer
yet, so it's a parse-only pass-through).
- [ ] `import` declarations anywhere at the start of a module — currently
- [x] `import` declarations anywhere at the start of a module — currently
only the very-top-of-file form is recognised. Real test programs that
mix prelude code with `import qualified Data.IORef` need this.
- [ ] Multi-line top-level `where` blocks (`where { ... }` with explicit
@@ -359,10 +359,100 @@ that to single-digit minutes.
- [ ] Verify the scoreboard output is byte-identical to the old per-process
driver, then keep the per-process path as `--isolated` for debugging.
### Phase 20 — Close Algorithm W gaps
`lib/haskell/infer.sx` already implements core HM (TVar/TCon/TArr/TApp/TTuple/
TScheme, substitution, occurs-check unification, instantiate/generalize, let-
polymorphism). 75 inference unit tests + 15 typecheck integration tests pass.
The remaining gaps that block typing real programs:
- [ ] `case` expressions in `hk-w`. Needs to infer scrutinee type, then for
each `(:alt pat body)` infer the pattern's binding env (extending
`hk-w-pat`) and unify body types across alts.
- [ ] `do` notation: extend `hk-type-env0` with `return :: a -> IO a`,
`(>>=) :: IO a -> (a -> IO b) -> IO b`, `(>>) :: IO a -> IO b -> IO b`,
and primitive IO actions (`putStrLn :: String -> IO ()`,
`getLine :: IO String`, etc.). May need a `TApp (TCon "IO") a` shape.
- [ ] Record-accessor desugaring leaves `__rec_field` placeholder visible to
inference. Either skip generated accessor clauses during `hk-infer-prog`
or rewrite the desugar to produce a typed shape.
- [ ] Type annotations in expressions `(x :: Int)` (parser also needed; see
Phase 17). Infer should unify the inferred type with the annotation.
- [ ] Tests in `lib/haskell/tests/infer-extras.sx` (≥ 10) covering the
above shapes.
### Phase 21 — Type classes (Eq, Ord, Num, Show)
The evaluator already implements typeclass dispatch via dict-passing
(`__default__ClassName_method` + per-instance dicts). The type system
ignores `class` and `instance` decls. Closing this means HM with
constraints (qualified types `[ClassName var] => type`).
- [ ] Extend the type representation: `(TQual CONSTRAINTS TYPE)` where
`CONSTRAINTS = [(class-name . type-arg), …]`.
- [ ] Generalize → `forall vars. preds => type`; instantiate → fresh-rename
vars in both preds and type.
- [ ] During inference, when a primitive operator that needs a class is
used (e.g. `+`), emit a constraint `(Num t)`; collect constraints in
the substitution-threading.
- [ ] At let-generalization, simplify constraints (defaulting for `Num`
literals → `Int`; entailment via known instances).
- [ ] `class` declarations register members with their qualified type;
`instance` declarations register a witness.
- [ ] At top-level, if any unsolvable constraint remains → type error
("No instance for X").
- [ ] Tests in `lib/haskell/tests/typeclasses.sx` (≥ 12 covering Eq, Ord,
Num overloading, show on instances, instance ambiguity rejection).
### Phase 22 — Typecheck-then-run as the default
- [ ] Replace `hk-run` with a typecheck-first variant in the conformance
driver, or run conformance twice (once typed, once untyped) and report
both pass-rates in `scoreboard.md`.
- [ ] Investigate which existing 36 programs are untypeable due to gaps
closed in Phase 20-21 vs genuinely dynamically-typed; aim for ≥ 30/36
programs typechecking before committing to the swap.
- [ ] If swap is committed, retire `hk-run` callsites in tests in favour
of `hk-run-typed`; keep the untyped path available for parser/eval
development against in-progress features.
## Progress log
_Newest first._
**2026-05-10** — Phase 17 second box: `import` declarations anywhere among
top-level decls. `hk-collect-module-body` previously ran a fixed
import-loop at the start, then a separate decl-loop; merged into a single
`hk-body-step` dispatcher that routes `import` to the imports list and
everything else to `hk-parse-decl`. Each call site (initial step + post-
semicolon loop) now uses the dispatcher. Imports collected mid-stream
still feed into `hk-bind-decls!` correctly because the eval side reads
them via the imports list, not by AST position. tests/parse-extras.sx
12 → 17 covering very-top, mid-stream, post-main, two-imports-different-
positions, and unqualified mid-file. Regression: eval 66/0, exceptions
14/0, typecheck 15/0, records 14/0, ioref 13/0, map 26/0, set 17/0.
**2026-05-08** — Phase 17 first box: expression type annotations `(x :: Int)`,
`f (1 :: Int)`, `(\x -> x+1) :: Int -> Int`. Parser's `hk-parse-parens`
gains a `::` arm after the first inner expression: consume `::`, parse a
type via the existing `hk-parse-type`, expect `)`, emit `(:type-ann EXPR
TYPE)`. Desugar drops the annotation — `:type-ann E _ → (hk-desugar E)` —
since the existing eval path has no type-directed dispatch; Phase 20 will
let inference consume the annotation. tests/parse-extras.sx 12/12; eval,
exceptions, typecheck, records, ioref still clean.
**2026-05-08** — Plan extends with Phases 20-22 (HM type system). Discovered
during planning that `lib/haskell/infer.sx` already lands core Algorithm W
(75 inference unit tests pass; let-polymorphism, sig checking, error
reporting via `hk-expr->brief`). Fixed five regressing tests in
`lib/haskell/tests/typecheck.sx` that compared an unforced thunk against
the expected value — added `hk-deep-force` around `hk-run-typed` to match
the existing untyped-path convention. typecheck.sx now 15/15.
Phase 20 captures the remaining Algorithm W gaps (case, do, record
accessors, expression annotations); Phase 21 captures type classes with
qualified types; Phase 22 captures the integration step (typecheck-then-run
across conformance).
**2026-05-08** — Phase 16 Exception handling complete (6 ops + module wiring +
14 unit tests + 2 conformance programs). `hk-bind-exceptions!` in `eval.sx`
registers `throwIO`, `throw`, `evaluate`, `catch`, `try`, `handle`, and