From 34b3893316cf7e2bd1392bd97d420e50a05b793b Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 10 Jun 2026 12:32:57 +0200 Subject: [PATCH] IC: keep NIF-only package-name marker out of symbol stubs The `pkg marker appended to skPackage NIF names leaked into the user-visible name of Partial stubs: vmgen's toKey built callback keys like 'getCurrentException.system.stdlib`pkg', so the VM compiled the real body of getCurrentException instead of dispatching to the vmops callback and failed with 'cannot evaluate at compile time: currException' (tparsefile, ttryparseexpr). The marked name was also a latent hash-divergence source: sighashes' hashNonProc/hashOwner hash package names straight off possibly-Partial stubs. Stubs are now created with the clean name; the marker doubles as a kind signal, so the stub starts as skPackage and globalName re-appends the marker when rebuilding the NIF index key. NIF file content is unchanged. Macro sweep 90/95 (up from 88, restores the baseline; the 5 remaining fails are the known deep ones), tests/ic 5/5. Co-Authored-By: Claude Fable 5 --- compiler/ast2nif.nim | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/compiler/ast2nif.nim b/compiler/ast2nif.nim index 4af394cc57..e17fe05a39 100644 --- a/compiler/ast2nif.nim +++ b/compiler/ast2nif.nim @@ -202,6 +202,9 @@ proc toNifSymName(w: var Writer; sym: PSym): string = proc globalName(sym: PSym; config: ConfigRef): string = result = sym.name.s + if sym.kindImpl == skPackage: + # stubs store the clean name; the NIF index is keyed by the marked one + result.add PkgMarker result.add '.' result.addInt sym.disamb result.add '.' @@ -238,6 +241,18 @@ proc parseSymName*(s: string): ParsedSymName = dec i return ParsedSymName(name: s, module: "") +proc stubKindAndName(cache: IdentCache; rawName: string): (TSymKind, PIdent) = + ## The user-visible name of a symbol stub must NOT keep NIF-only name + ## decorations: the `PkgMarker` of package symbols would otherwise leak into + ## every reader of `name.s` that runs before the stub is fully loaded + ## (e.g. vmgen's callback keys built from owner chains). The marker also + ## tells us the symbol kind up front, which `globalName` uses to rebuild + ## the marked NIF name for the index lookup. + if rawName.endsWith(PkgMarker): + (skPackage, cache.getIdent(rawName[0 ..< rawName.len - PkgMarker.len])) + else: + (skStub, cache.getIdent(rawName)) + template buildTree(dest: var TokenBuf; tag: TagId; body: untyped) = dest.addParLe tag body @@ -1138,7 +1153,8 @@ proc loadSymStub(c: var DecodeContext; t: SymId; thisModule: string; let id = ItemId(module: module.int32, item: val[]) let offs = c.getOffset(module, symAsStr) - result = PSym(itemId: id, kindImpl: skStub, name: c.cache.getIdent(sn.name), disamb: sn.count.int32, state: Partial) + let (stubKind, stubName) = stubKindAndName(c.cache, sn.name) + result = PSym(itemId: id, kindImpl: stubKind, name: stubName, disamb: sn.count.int32, state: Partial) c.syms[symAsStr] = (result, offs) proc loadSymStub(c: var DecodeContext; n: var Cursor; thisModule: string; @@ -1281,8 +1297,8 @@ proc loadSymFromCursor(c: var DecodeContext; s: PSym; n: var Cursor; thisModule: inc n if s.kindImpl == skPackage and s.name.s.endsWith(PkgMarker): - # Stubs keep the marked NIF ident (see PkgMarker) so that `globalName` - # reconstructs the index key; the in-memory sym gets the real name back. + # Fallback: stubs are normally created with the clean name already + # (see stubKindAndName); strip the NIF-only marker if one slipped through. s.name = c.cache.getIdent(s.name.s[0 ..< s.name.s.len - PkgMarker.len]) case s.kindImpl @@ -1518,7 +1534,8 @@ proc loadSymFromIndexEntry(c: var DecodeContext; module: FileIndex; inc val[] let id = ItemId(module: symModule.int32, item: val[]) - result = PSym(itemId: id, kindImpl: skStub, name: c.cache.getIdent(sn.name), disamb: sn.count.int32, state: Partial) + let (stubKind, stubName) = stubKindAndName(c.cache, sn.name) + result = PSym(itemId: id, kindImpl: stubKind, name: stubName, disamb: sn.count.int32, state: Partial) c.syms[symAsStr] = (result, entry) proc extractBasename(nifName: string): string =