`populateInterfaceTablesFromIndex` stubbed a `PSym` for every global symbol a
module declares and inserted it into `interf` and/or `interfHidden`. On a
68-module target that is 2.37M stubs across the build — and 2.04M of them go
into `interfHidden` alone, which a `cg`/`emit` stage has no way to reach.
`interfHidden` is selected exclusively by `modulegraphs.interfSelect`, and only
when `optImportHidden` is in the module's options. That flag is set in exactly
one place — `importer.importModuleAs`, i.e. during sem. A backend stage builds
its module symbols in `moduleFromNifFile` and never imports anything, so the
flag cannot be set and the table cannot be selected. Skipping the hidden-only
branch there is unobservable, not merely unlikely to be observed.
Exported symbols still go into both tables. That is 0.33M inserts against the
2.0M saved, and it leaves `interfHidden` a coherent view — a module with no
hidden symbols — rather than an empty one, should anything ever consult it.
interface tables 1401ms -> 863ms
loadDepClosure 2771ms -> 2309ms
cold --ic:on build 9.38s -> 8.91s
Skipping the tables WHOLESALE in a backend stage does not work, and the failure
is worth recording since it is the obvious next thought: the exported half is
what `magicsys.getSysSym` resolves through, so the stage dies with "system
module needs: pointer". Skipping them in the FRONTEND is worse still — `nim m`
loses `defined`.
Verified: both configurations build; `tests/ic` 40/40; 67/67 generated `.c`
byte-identical, cursor still identical to `PNode`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FMyRHByv7hhaQJ4Pa1bHbE