mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 01:14:41 +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 (cherry picked from commitc06bb6cc03)