mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 08:54:53 +00:00
fixes #24863, refs #23787 and #24316
Working off the minimized example, my understanding of the issue is: `n`
captures `r` as `:envP.r1` where `:envP` is the environment of `b`, then
`proc () = n()` does the lambda lifting of `n` again (which isn't done
if the `proc ()` is marked `{.closure.}`, hence the workaround) which
then captures the `:envP` as another field inside the `:envP`, so it
generates `:envP.:envP_2.r1` but the `.:envP_2` field is `nil`, so it
causes a segfault.
The problem is that the capture of `r` in `n` is done inside
`detectCapturedVars` for the surrounding closure iterator: inner procs
are not special cased and traversed as regular nodes, so it thinks it's
inside the iterator and generates a field access of `:envP` freely. The
lambda lifting version of `detectCapturedVars` ignores inner procs and
works off of symbol uses (anonymous iterator and lambda declarations
pretend their symbol is used).
As a naive solution, closure iterators now also ignore inner proc
declarations same as `lambdalifting.detectCapturedVars`, but unlike it
they also don't do anything for the inner proc symbols. Lambdalifting
seems to properly handle the lifted variables but in the worst case we
can also make sure `closureiters.detectCapturedVars` traverses inner
procs by marking every local of the closure iter used in them as needing
lifting (but not doing the lifting). This does not seem necessary for
now so it's not done (was done and reverted in [this
commit](9bb39a9259)),
but regressions are still possible
179 lines
2.6 KiB
Nim
179 lines
2.6 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
|
|
Test 8:
|
|
123
|
|
456
|
|
'''
|
|
"""
|
|
|
|
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()
|
|
|
|
block: # issue #12487
|
|
iterator FaiReader(): string {.closure.} =
|
|
yield "something"
|
|
|
|
template toClosure(i): auto =
|
|
iterator j: string {.closure.} =
|
|
for x in FaiReader():
|
|
yield x
|
|
j
|
|
|
|
proc main =
|
|
var reader = toClosure(FaiReader())
|
|
var s: seq[string] = @[]
|
|
for x in reader():
|
|
s.add(x)
|
|
doAssert s == @["something"]
|
|
|
|
main()
|
|
|
|
block: # minimized issue #24863
|
|
echo "Test 8:"
|
|
proc c() =
|
|
iterator b(): int {.closure.} =
|
|
let r = 456
|
|
yield 123
|
|
proc n() =
|
|
echo r
|
|
let a = proc () = n()
|
|
a()
|
|
|
|
let j = b
|
|
echo j()
|
|
discard j()
|
|
|
|
c()
|