Fix inconsistent env type with nested procs in iterators (#21242) (#25699)

Nested transformBody/liftLambdas passes used a fresh DetectionPass, so
getEnvTypeForOwner could allocate a duplicate PType for the same owner
while :envP already referenced the inner pass type. When addClosureParam
saw cp.typ != t, it errored.

If both types are env objects for the same routine owner, reuse cp.typ
and sync ownerToType.

Adds regression test tests/iter/t21242_nested_closure_in_iter.nim.
This commit is contained in:
dxxb
2026-04-04 19:47:01 +02:00
committed by GitHub
parent 854c1f15ba
commit 0028ea563c
2 changed files with 36 additions and 1 deletions

View File

@@ -408,6 +408,12 @@ Consider:
proc isTypeOf(n: PNode): bool =
n.kind == nkSym and n.sym.magic in {mTypeOf, mType}
proc isEnvTypeForRoutine(envTyp: PType; routine: PSym): bool =
## True if `envTyp` is (maybe wrapped) env object type owned by `routine`, as
## created by `getEnvTypeForOwner` / `createEnvObj`.
let obj = envTyp.skipTypes({tyOwned, tyRef, tyPtr})
result = obj.kind == tyObject and obj.owner.id == routine.id
proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
var cp = getEnvParam(fn)
let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner
@@ -418,7 +424,13 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
cp.typ = t
addHiddenParam(fn, cp)
elif cp.typ != t and fn.kind != skIterator:
localError(c.graph.config, fn.info, "internal error: inconsistent environment type")
# Nested `liftLambdas` uses a fresh `DetectionPass`, so `getEnvTypeForOwner`
# can allocate another PType for the same logical env; the hidden param from
# the inner pass is authoritative (bug #21242).
if isEnvTypeForRoutine(cp.typ, owner) and isEnvTypeForRoutine(t, owner):
c.ownerToType[owner.id] = cp.typ
else:
localError(c.graph.config, fn.info, "internal error: inconsistent environment type")
#echo "adding closure to ", fn.name.s
proc iterEnvHasUpField(g: ModuleGraph, iter: PSym): bool =

View File

@@ -0,0 +1,23 @@
# Regression test for bug #21242
discard """
action: compile
"""
iterator iterSome(): int =
proc inner1() =
let something = 6
proc inner2() =
let othersomething = something
inner2()
for n in 0 .. 10:
inner1()
yield n
proc test() =
proc test1() =
for v in iterSome():
discard
test1()
test()