Files
Nim/tests/iter/tnestedclosures.nim
Yuriy Glukhov 5fa96ef270 Fixes #3824, fixes #19154, and hopefully #24094. Re-applies #23787. (#24316)
The first commit reverts the revert of #23787.
The second fixes lambdalifting in convolutedly nested
closures/closureiters. This is considered to be the reason of #24094,
though I can't tell for sure, as I was not able to reproduce #24094 for
complicated but irrelevant reasons. Therefore I ask @jmgomez, @metagn or
anyone who could reproduce it to try it again with this PR.

I would suggest this PR to not be squashed if possible, as the history
is already messy enough.

Some theory behind the lambdalifting fix:
- A closureiter that captures anything outside its body will always have
`:up` in its env. This property is now used as a trigger to lift any
proc that captures such a closureiter.
- Instantiating a closureiter involves filling out its `:up`, which was
previously done incorrectly. The fixed algorithm is to use "current" env
if it is the owner of the iter declaration, or traverse through `:up`s
of env param until the common ancestor is found.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2024-10-18 10:36:41 +02:00

140 lines
2.0 KiB
Nim

discard """
targets: "c"
output: '''
Test 1:
12
Test 2:
23
23
Test 3:
34
34
Test 4:
45
45
50
50
Test 5:
45
123
47
50
Test 6:
<hi>
Test 7:
0
1
2
'''
"""
block: #24094
echo "Test 1:"
proc foo() =
let x = 12
iterator bar2(): int {.closure.} =
yield x
proc bar() =
let z = bar2
for y in z(): # just doing bar2() gives param not in env: x
echo y
bar()
foo()
block: #24094
echo "Test 2:"
iterator foo(): int {.closure.} =
let x = 23
iterator bar2(): int {.closure.} =
yield x
proc bar() =
let z = bar2
for y in z():
echo y
bar()
yield x
for x in foo(): echo x
block: #24094
echo "Test 3:"
iterator foo(): int {.closure.} =
let x = 34
proc bar() =
echo x
iterator bar2(): int {.closure.} =
bar()
yield x
for y in bar2():
yield y
for x in foo(): echo x
block:
echo "Test 4:"
proc foo() =
var x = 45
iterator bar2(): int {.closure.} =
yield x
yield x + 3
let b1 = bar2
let b2 = bar2
echo b1()
echo b2()
x = 47
echo b1()
echo b2()
foo()
block:
echo "Test 5:"
proc foo() =
var x = 45
iterator bar2(): int {.closure.} =
yield x
yield x + 3
proc bar() =
var y = 123
iterator bar3(): int {.closure.} =
yield x
yield y
let b3 = bar3
for z in b3():
echo z
x = 47
let b2 = bar2
for z in b2():
echo z
bar()
foo()
block: #19154
echo "Test 6:"
proc test(s: string): proc(): iterator(): string =
iterator it(): string = yield s
proc f(): iterator(): string = it
return f
let it = test("hi")()
for s in it():
echo "<", s, ">"
block: #3824
echo "Test 7:"
proc main =
iterator factory(): int {.closure.} =
iterator bar(): int {.closure.} =
yield 0
yield 1
yield 2
for x in bar(): yield x
for x in factory():
echo x
main()