fix(types): extend unknown-type check into function bodies (issue 0064)

The signature/field check missed body-level type positions: a local
annotation naming a non-existent type flowed through the empty-struct stub
untouched, so `v: Coordnate = 5` silently compiled and ran (the value
dropped) — an invalid program accepted with no diagnostic.

`checkUnknownTypeNames` now also walks each main-file function body
(`checkBodyTypes`): local var/const type annotations — including inside
if / loop / match / push / defer / onfail blocks and decl-value blocks — are
validated with the enclosing function's generic params in scope, and
body-local `T :: struct/enum/union` declarations are collected first
(`collectBodyDeclNames`) so legitimate locals aren't false-flagged. Nested
function/closure bodies are their own scope and are not descended (safe
under-coverage); explicit `cast(T)` already surfaces its own `unresolved`
diagnostic and is left to it.

Regression: examples/1113 (local annotation of a non-existent type, exit 1).
This commit is contained in:
agra
2026-06-02 10:41:29 +03:00
parent c490ffcfe9
commit 63b512a182
6 changed files with 106 additions and 3 deletions

View File

@@ -17,9 +17,19 @@
> types are recognized via the type table (`findByName`), so cross-module
> references aren't false-flagged; inline compound spellings (`[:0]u8`), arbitrary-
> width ints (`u1`/`u2`), and `$`-introduced generics (`-> $R`) are all exempted.
> The pass also walks function **bodies** (`checkBodyTypes` + `collectBodyDeclNames`):
> local `var` / `const` type annotations — including inside `if` / loop / `match` /
> `push` / `defer` / `onfail` blocks and decl-value blocks — are checked with the
> enclosing function's generic params in scope, and body-local `T :: struct/enum/
> union` declarations are collected so they aren't false-flagged. This closes the
> silent body-level hole where `v: Coordnate = 5` (a non-existent type) compiled and
> 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, exit 1) and `examples/1112-diagnostics-unknown-type-name-rejected.sx`
> (typo'd field type, exit 1). Suite: 347 passed, 0 failed.
> (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.
## Symptom