fix(types): check nested closure/function bodies and cast targets (issue 0064)

Closes the two residual silent holes in the unknown-type diagnostic:

- Nested closure / function bodies. The body walk stopped at closure and
  nested-fn boundaries, so a typo'd type in a closure's local annotation
  silently became a 0-field struct. `walkBodyTypes` now descends control
  flow and expressions to re-enter each closure / nested fn via `checkScope`,
  which accumulates that scope's generic + value-`Type` params onto the
  parent's — so an inner closure still sees the outer function's `$T` (no
  false positive) while a genuine unknown is flagged at any nesting depth.
  `harvestScopeDecls` collects type-decl names across the whole body
  (including nested scopes) up front so locals are never false-flagged.

- Cast targets. `cast(T)` where `T` is a value-`Type` param (no `$`) cast to
  a fabricated empty struct silently; it now gets the tailored `$T` hint. An
  unknown *literal* cast target already errors via value resolution, so it's
  left to that path — no double diagnostic.

Suite: 350 passed, 0 failed. Regressions: examples/1114 (nested-closure
annotation), 1115 (cast value param).
This commit is contained in:
agra
2026-06-02 10:57:17 +03:00
parent 63b512a182
commit bd01d2224d
10 changed files with 273 additions and 66 deletions

View File

@@ -26,10 +26,19 @@
> ran with the value dropped. Nested function / closure bodies are their own scope
> and are not descended (safe under-coverage); explicit `cast(T)` already has its
> own `unresolved` diagnostic and is left to it.
> Regression tests: `examples/1111-diagnostics-nondollar-type-param-rejected.sx`
> (tailored hint), `examples/1112-diagnostics-unknown-type-name-rejected.sx`
> (typo'd field type), and `examples/1113-diagnostics-unknown-type-local-var-rejected.sx`
> (body-level local annotation) — all exit 1. Suite: 348 passed, 0 failed.
> The walk descends into **nested closure / function bodies** too (`walkBodyTypes`
> + `checkScope`): each scope accumulates its generic params onto the parent's, so
> a closure body still sees the enclosing function's `$T`, and a type annotation in
> any nesting depth is checked. `harvestScopeDecls` collects type-decl names across
> the whole body (including nested scopes) so locals aren't false-flagged. Cast
> targets are handled too: `cast(T)` where `T` is a value-`Type` param (the
> otherwise-silent cast case) gets the tailored hint, while an unknown *literal*
> cast target is left to the existing value-resolution `unresolved` diagnostic (no
> double-report). The only remaining under-coverage is benign (annotations buried in
> AST positions the walker doesn't descend stay unchecked — never a false positive).
> Regression tests: `examples/1111` (tailored hint, signature), `1112` (typo'd field
> type), `1113` (body-level local annotation), `1114` (nested-closure annotation),
> `1115` (`cast` value param) — all exit 1. Suite: 350 passed, 0 failed.
## Symptom