Make same-name top-level types in different sources DISTINCT nominal types
instead of collapsing last-wins in the type table (issue 0105).
Registration:
- internNamedTypeDecl assigns a per-decl nominal_id and populates
type_decl_tids. The first author of a name keeps nominal_id 0 (byte-identical
to pre-E2); a genuine cross-module shadow (>=2 distinct normalized-path
authors per the import facts) gets a fresh id -> a distinct TypeId.
- mergeFlat/addOwnDecl stop first-wins-dropping per-source decls (named types +
non-fn const_decls) so every same-name author reaches registration; functions
and var_decls (incl. #foreign extern globals) keep first-wins.
Resolution (selectNominalLeaf):
- own-author wins; else flatTypeAuthorCount over the transitive flat closure:
>=2 distinct -> .ambiguous (loud diagnostic + poison); exactly one -> resolved;
a flat author not yet findByName-registered -> .undeclared stub (not a leak).
- struct-literal type names route through the same source-aware leaf.
- lazyLowerFunction pins the function's own source before resolving its return
type, so a shadowed signature type resolves in its module, not the caller's.
Codegen:
- mangleTypeName appends __n<id> for nonzero nominal_id so same-name shadows get
distinct monomorph symbols (struct_to_string__Box vs __Box__n1).
Library hygiene:
- rename trace.sx's compiler-contracted Frame -> TraceFrame (+ the two compiler
findByName sites) so it never collides with a UI/geometry Frame; the layout is
structural (getFrameStructType / SxFrame), name-independent.
Examples: 0752-0756 pin the five 0105 cases (distinct fields / same fields /
own-wins / ambiguous / alias per-source); 0170 pins the folded anon-struct-field
regression.
Generic substitution and monomorphization-key construction now live in one
module, src/ir/generics.zig, behind a *Lowering facade (GenericResolver),
mirroring CallResolver / ExprTyper. Moved verbatim:
- mangleTypeName + mangleParamList (the mono-key fragment builder),
- mangleGenericName (generic mono key), appendComptimeValueMangle (comptime-value
fragment),
- buildTypeBindings (call-site type-param inference), inferGenericReturnType
(generic return resolution).
inferGenericReturnType now uses a scoped TypeBindingScope (enter/exit with defer)
instead of a manual type_bindings save/restore — the PLAN-ARCH A4.1 "scoped
substitution env" shape; a generics.test.zig assertion confirms the prior
bindings are restored (the issue-0048/0050 leak class, for this field).
Lowering keeps a thin pub mangleTypeName wrapper delegating to
genericResolver().mangleTypeName, because ~30 cross-cutting callers (impl-map
keys, conversion keys, shape keys) reach it well beyond generics. mangleParamList
(sole caller was mangleTypeName) moved fully. The other 4 originals are deleted
(no fallback); their 6 call sites now go through self.genericResolver()
(calls.zig via self.l.genericResolver()).
matchTypeParam / extractTypeParam / isTypeParamDecl widened to pub (the moved
substitution logic calls them); genericResolver() accessor added. The 2
mangleTypeName / inferGenericReturnType unit tests moved from lower.test.zig to
generics.test.zig (driving GenericResolver directly) and wired into the barrel.
monomorphizeFunction / monomorphizePackFn intentionally stay in lower.zig (they
save/restore three fields across nested mono and call emission helpers) — a
heavier scoped-env adoption deferred to an optional sub-step 3.
zig build, zig build test, and tests/run_examples.sh (357/0) all green — no .ir
snapshot churn, confirming the move preserved mono-key/substitution output.