# 0069 — forward identifier type alias is falsely rejected by unknown-type pass

> **RESOLVED.** Root cause: `Lowering.scanDecls`' `.identifier` alias branch only
> registered `A :: B` into `ProgramIndex.type_alias_map` when `B` was already
> known (in `type_alias_map` or the `TypeTable`). A forward target declared later
> (`MyChain :: MyInt; MyInt :: i32;`) was never present during the single forward
> scan, so the alias name went unregistered and the A2.4 unknown-type pass — which
> treats `type_alias_map` keys as declared types — flagged its uses.
> Fix: added a fixpoint post-pass `resolveForwardIdentifierAliases` at the end of
> `scanDecls` that re-resolves identifier-RHS aliases until no progress, after every
> top-level name has been seen. A value const is never an `.identifier` node and an
> alias whose target is a value const still misses both lookups, so issue 0068's
> value-const rejection is preserved. Regression:
> `examples/0132-types-forward-type-alias.sx`.

## Symptom

A forward-referenced identifier type alias is rejected as an unknown type, even
though the same alias chain works when ordered after its target.

Observed: `MyChain` is diagnosed as an unknown type.

Expected: `MyChain :: MyInt; MyInt :: i32;` should resolve `MyChain` to `i32`
when used in a type annotation, matching the existing ordered-chain behavior
(`MyInt :: i32; MyChain :: MyInt;`).

## Reproduction

```sx
MyChain :: MyInt;
MyInt :: i32;

main :: () -> i32 {
    v: MyChain = 7;
    return v;
}
```

Run:

```sh
./zig-out/bin/sx run .sx-tmp/probe-0068-forward-alias.sx
```

Observed output:

```text
error: unknown type 'MyChain'
  --> .sx-tmp/probe-0068-forward-alias.sx:7:8
   |
 7 |     v: MyChain = 7;
   |        ^^^^^^^
```

The repro is standalone; the inline source above is sufficient to recreate the
scratch file under `.sx-tmp/`.

## Investigation prompt

Fix issue 0069: a forward-referenced identifier type alias must not be falsely
rejected by the A2.4 unknown-type diagnostic pass.

Context:
- This surfaced while re-reviewing `8770145`, the issue-0068 fix. That fix
  correctly stopped arbitrary value consts (`NotAType :: 123`) from satisfying
  the unknown-type check.
- Ordered identifier aliases still work: `MyInt :: i32; MyChain :: MyInt;`.
- `.call` type aliases still work: `Vec3 :: Vec(3, f32);` and
  `Foo :: Complex(u32);`.
- The failing shape is specifically a forward identifier alias:
  `MyChain :: MyInt; MyInt :: i32;`.

Suspected area:
- `src/ir/lower.zig`, `Lowering.scanDecls`, especially the `.identifier` alias
  branch for `const_decl` values. It only inserts `cd.name` into
  `ProgramIndex.type_alias_map` if the RHS is already in `type_alias_map` or
  already registered in the `TypeTable`. A forward target is not present yet, so
  the alias name is never recorded.
- `src/ir/semantic_diagnostics.zig`,
  `UnknownTypeChecker.collectDeclaredTypeNames` / `reportIfUnknownType`. After
  issue 0068, `.identifier` aliases are intentionally excluded from
  `constValueIntroducesType` and are supposed to be covered by canonical facts
  (`ProgramIndex.type_alias_map` / `TypeTable`). Because the forward alias never
  reaches those facts, the checker flags the alias as unknown.

Likely fix:
- Do not reintroduce the issue-0068 bug by adding all `.identifier` const names
  to the declared-type set.
- Instead, make identifier aliases converge through canonical alias facts even
  when the RHS is declared later. A small two-pass alias registration/resolution
  in `scanDecls`, or an explicit pending-alias graph that resolves after all
  top-level declarations are scanned, would keep `ProgramIndex.type_alias_map`
  authoritative without accepting value constants.
- Preserve value const rejection: `NotAType :: 123; v: NotAType` must continue
  to emit `unknown type 'NotAType'`.
- Preserve ordered/chained aliases and type-returning call aliases:
  `examples/0116-types-type-alias-size-align.sx`,
  `examples/0201-generics-generic-struct.sx`, and
  `examples/1117-diagnostics-value-const-as-type-rejected.sx`.

Verification:
- Add a focused regression for the repro above, likely in the `01xx` types block
  because the desired behavior is successful alias resolution.
- Run the new regression and the existing alias/diagnostic guards:

```sh
zig build
zig build test
bash tests/run_examples.sh
```

Expected result: the forward alias program compiles/runs (returning `7`), the
issue-0068 value-const case still fails with a diagnostic, and the full suite
passes.
