Files
Nim/tests/iter/tlowerpragmablock.nim
Ryan McConnell f8e470eb57 fix: {.cast(uncheckedAssign).} ineffective across yield in closure iterators (#25916)
closureiters.nim splits a stmt list at yield points, moving post-yield
code into a new state body. When that stmt list was inside a pragma
block like `{.cast(uncheckedAssign).}`, the new state's body was created
as a bare nkStmtList without the wrapper.

Fix: track the enclosing pragma block in the transform context, and wrap
newly-created state bodies in a copy of it when the split occurs inside
one. Added an explicit `nkPragmaBlock` case to
`transformClosureIteratorBody` that saves/restores `ctx.enclosingPragma`
around its body.
2026-06-16 19:15:16 +02:00

53 lines
1.2 KiB
Nim

discard """
action: "run"
"""
# Test: {.cast(uncheckedAssign).} must suppress FieldDiscriminantCheck
# when a yield inside the pragma block causes the closure-iterator
# transform to split the body. The discriminant assignment lands in
# the post-yield state and must inherit the wrapper.
type
MyKind = enum mkOne, mkTwo
MyVariant = object
case kind: MyKind
of mkOne:
x: int
of mkTwo:
y: float
iterator iterUncheckedYield(dest: var MyVariant): int {.closure.} =
{.cast(uncheckedAssign).}:
yield 1
dest.kind = mkTwo
block:
var v = MyVariant(kind: mkOne, x: 42)
var count = 0
for x in iterUncheckedYield(v):
if count == 0:
doAssert x == 1
inc count
# don't break — continue to advance past the yield,
# which runs the discriminant assignment
else:
break
doAssert v.kind == mkTwo
iterator iterNestedPragma(dest: var MyVariant): int {.closure.} =
{.cast(uncheckedAssign).}:
{.cast(gcsafe).}:
yield 1
dest.kind = mkTwo
block:
var v = MyVariant(kind: mkOne, x: 42)
var count = 0
for x in iterNestedPragma(v):
if count == 0:
doAssert x == 1
inc count
else:
break
doAssert v.kind == mkTwo