From 39e63e9fcc21e829cd10de219a5e21d2674b696a Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 23 Jun 2026 12:03:29 +0200 Subject: [PATCH] IC: progress --- compiler/lowerings.nim | 10 ++++++++++ compiler/transf.nim | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index c0a51fd619..d72b403a37 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -361,6 +361,16 @@ proc getFieldFromObj*(t: PType; v: PSym): PSym = assert t.kind == tyObject result = lookupInRecord(t.n, v.itemId) if result != nil: break + # A LOADED (Sealed) env object carries fields baked by the producer process; + # re-lifting a NIF-loaded routine in a consumer (e.g. a macro VM-evaluating an + # imported `p2pProtocolBackendImpl`) re-captures the same local under a + # divergent process-local id, so the derived-itemId match misses. Fall back to + # the name+position identity `addField` uses — SYMMETRIC with `addField`'s + # Sealed by-name reuse — so the access resolves the field `addField` produced + # instead of failing with `not part of closure object type`. + if t.state == Sealed: + result = lookupCapturedField(t.n, v) + if result != nil: break t = t.baseClass if t == nil: break t = t.skipTypes(skipPtrs) diff --git a/compiler/transf.nim b/compiler/transf.nim index 6ee5aa7b92..f0cf9dd33b 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -1401,6 +1401,18 @@ proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flags: Transf g.vmTransfIdgen = idGeneratorForBackend(g.systemModule) liftIdgen = g.vmTransfIdgen var c = openTransf(g, prc.getModule, "", liftIdgen, flags) + # `liftCapturedVars` rewrites captured locals to `:env.field` IN PLACE on the + # body it is handed; the env-creation prologue lands only in the returned + # wrapper. When the VM drives this transform (running a macro/CT proc), that + # in-place mutation corrupts the routine's PRE-transform `ast[bodyPos]` — + # under IC exactly the node `getBody` serializes to the module's `.s.nif`. So + # snapshot the pristine body before the VM lift and restore `ast[bodyPos]` + # afterwards: the VM still consumes the fully-lifted `result`, but `getBody` + # keeps faithfully returning the pre-transform body for serialization. The + # cg/backend path (`inVMTransform == 0`) is untouched. + let vmPristineBody = + if g.inVMTransform > 0: copyTree(getBody(g, prc)) + else: nil result = liftLambdas(g, prc, getBody(g, prc), c.tooEarly, c.idgen, flags) result = processTransf(c, result, prc) liftDefer(c, result) @@ -1410,6 +1422,8 @@ proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flags: Transf result = g.transformClosureIterator(c.idgen, prc, result) incl(result.flags, nfTransf) + if vmPristineBody != nil: + prc.ast[bodyPos] = vmPristineBody if useCache in flags or prc.typ.callConv == ccInline: # genProc for inline procs will be called multiple times from different modules,