# issue-0042 — Const-decl type aliases (`MyInt :: s32;`) silently return `.s64` from `size_of` / `align_of` **FIXED.** `MyInt :: s32; size_of(MyInt)` now returns `4` correctly. The `resolveTypeArg` `.identifier` branch consults `type_alias_map` before falling through. The fix landed alongside the broader alias-resolution work tracked in CHECKPOINT.md (Session 63's `type_bridge` alias-resolution extension); no specific commit isolates this issue. Below preserved as a record of the original problem. ## Symptom A type alias declared via `Foo :: SomeType;` is registered in the lowering's `type_alias_map` but is **never consulted** when the alias name is later used as a type argument to `size_of` / `align_of`. The fallback returns `.s64` (8 bytes) — which coincidentally produces a correct result for any alias whose underlying type is 8 bytes (`*T`, `f64`, function pointers, `s64`, `u64`), silently masking the bug for years. Observed: ``` size_of(s32) = 4 ← direct, correct size_of(MyInt) = 8 ← via alias, WRONG (expected 4) ``` Where `MyInt :: s32;`. ## Reproduction ```sx #import "modules/std.sx"; MyInt :: s32; main :: () -> s32 { print("direct: {}\n", size_of(s32)); // 4 print("alias: {}\n", size_of(MyInt)); // 8 — should be 4 0; } ``` `./zig-out/bin/sx run` against unmodified master prints: ``` direct: 4 alias: 8 ``` ## Why this surfaces now issue-0041 work extends the const-decl alias path to register pointer, optional, array, slice, many-pointer, and function-type aliases (`Ptr :: *u8;`, `Maybe :: ?u8;`, `Arr :: [3]u8;`, `Cb :: (s32) -> s32;`). Every one of those aliases ends up in `type_alias_map`, then `size_of()` falls through the same `.identifier` branch that ignores the map — returning `.s64` (8). For pointer and function-type aliases this is coincidentally right (8 bytes). For optional, array, etc. it produces silently-wrong sizes (`size_of(Maybe) = 8` instead of 2; `size_of(Arr) = 8` instead of 3). The issue-0041 work cannot land without this being fixed — the test snapshots would pin in the wrong values and the new feature would ship subtly broken. ## Investigation prompt > The bug lives in `src/ir/lower.zig`, in `resolveTypeArg` > ([line ~7132](src/ir/lower.zig#L7132)). The `.identifier` > branch looks like: > > ```zig > .identifier => |id| { > if (self.type_bindings) |tb| { > if (tb.get(id.name)) |ty| return ty; > } > const name_id = self.module.types.internString(id.name); > return self.module.types.findByName(name_id) orelse .s64; > }, > ``` > > It checks `type_bindings` (generic-monomorphization) and > `findByName` (registered named types), but never consults > `self.type_alias_map` — which is where the const-decl alias > registration in `lower.zig:425` puts entries. The neighbouring > `.type_expr` branch (line ~7143) DOES check `type_alias_map`: > > ```zig > .type_expr => |te| { > if (self.type_alias_map.get(te.name)) |alias_ty| return alias_ty; > return type_bridge.resolveAstType(node, &self.module.types); > }, > ``` > > Why two branches: an `.identifier` AST node is what parsePrimary > emits for non-keyword names; `.type_expr` is what it emits for > built-in primitive names recognised by `Type.fromName` (`s32`, > `u8`, etc.) and for the `f32`/`f64`/`Type` keywords. User-defined > alias names like `MyInt` and `Ptr` flow through `.identifier`. > > **Likely fix:** mirror the `type_alias_map.get` lookup in the > `.identifier` branch — try alias map first (or before/after > findByName, whichever is the established precedence elsewhere). > > ```zig > .identifier => |id| { > if (self.type_bindings) |tb| { > if (tb.get(id.name)) |ty| return ty; > } > if (self.type_alias_map.get(id.name)) |alias_ty| return alias_ty; > const name_id = self.module.types.internString(id.name); > return self.module.types.findByName(name_id) orelse .s64; > }, > ``` > > **Verification:** > 1. Add the repro above as `examples/issue-0042.sx`. > 2. `bash tests/run_examples.sh --update` to capture expected > output (`alias: 4`, not `alias: 8`). > 3. Make sure existing snapshots that test type aliases (search > `examples/` for `::` patterns followed by `size_of`) don't > change in unexpected ways. > > **Possible adjacency:** the issue may extend to `align_of` > (likely same call path) and to type-alias chains > (`A :: s32; B :: A;` — does B resolve through A's alias entry?). > Worth pinning down with a test once the primary fix lands. ## Plan-level impact Blocks issue-0041 (compound-type-as-expression). Once 0042 is fixed, 0041 work can resume from the testing phase (the parser and lowering edits for 0041 are already in place; only the alias lookup is broken). ## Suggested fix order 1. Land 0042's `.identifier` alias-map lookup. 2. Resume 0041 from the test step — re-run `examples/issue-0041.sx` and verify `size_of(Maybe) = 2`, `size_of(Arr) = 3`, etc. 3. Regenerate snapshots and proceed with the 0041 finishing steps (50-smoke, rename, etc.).