mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-17 10:34:53 +00:00
102 lines
2.7 KiB
Nim
102 lines
2.7 KiB
Nim
discard """
|
|
description: '''IC vs `nim c`: closure environments, their hooks and their owners'''
|
|
"""
|
|
|
|
#? metamorphic
|
|
|
|
# A closure's environment type — and the `=destroy`/`=copy` the compiler lifts
|
|
# for it — is minted by the BACKEND, during the `lower` stage, and exists in no
|
|
# module's semmed NIF. The per-module backend has to decide which translation
|
|
# unit emits such a routine, and the owner walk it uses lands on the module of
|
|
# the ORIGINAL generic: for a generic closure iterator defined in one module and
|
|
# instantiated in another, that is a module which never sees the instance, so the
|
|
# env's `=destroy` was emitted by nobody (`undefined reference to
|
|
# eqdestroy__c485__…`). Every referencing TU emits it now.
|
|
#
|
|
# The steps then move the captured state around, because the env's LAYOUT is what
|
|
# decides whether those hooks are trivial: a body-only edit that adds a capture
|
|
# changes the env type of a routine whose importers do not re-sem.
|
|
|
|
#!FILE clleaf.nim
|
|
type Ev* = proc (s: string): string {.closure.}
|
|
|
|
proc leafMaker*(tag: string): Ev =
|
|
var n = 0
|
|
proc outer(s: string): string =
|
|
proc inner(t: string): string =
|
|
inc n
|
|
tag & ":" & t & ":" & $n
|
|
inner(s)
|
|
result = outer
|
|
|
|
iterator leafIter*[T](xs: seq[T]): T {.closure.} =
|
|
for x in xs: yield x
|
|
|
|
#!FILE clmid.nim
|
|
import clleaf
|
|
|
|
proc midMaker*(tag: string): Ev =
|
|
let base = leafMaker(tag & "/mid")
|
|
var calls = 0
|
|
result = proc (s: string): string =
|
|
inc calls
|
|
base(s) & "#" & $calls
|
|
|
|
proc midIter*(): seq[string] =
|
|
# instantiates `leafIter[string]` HERE, not where it is defined
|
|
result = @[]
|
|
for x in leafIter(@["p", "q"]): result.add x
|
|
|
|
#!FILE main.nim
|
|
import clleaf, clmid
|
|
|
|
let t = midMaker("top")
|
|
echo t("Alpha")
|
|
echo t("Beta")
|
|
echo midIter()
|
|
|
|
# an instance only the main module has
|
|
var fs: seq[float] = @[]
|
|
for x in leafIter(@[1.5, 2.5]): fs.add x
|
|
echo fs
|
|
#!STEP
|
|
|
|
# body-only edit that GROWS the environment: a second captured local
|
|
#!FILE clleaf.nim
|
|
type Ev* = proc (s: string): string {.closure.}
|
|
|
|
proc leafMaker*(tag: string): Ev =
|
|
var n = 0
|
|
var seen: seq[string] = @[]
|
|
proc outer(s: string): string =
|
|
proc inner(t: string): string =
|
|
inc n
|
|
seen.add t
|
|
tag & ":" & t & ":" & $n & ":" & $seen.len
|
|
inner(s)
|
|
result = outer
|
|
|
|
iterator leafIter*[T](xs: seq[T]): T {.closure.} =
|
|
var i = 0
|
|
for x in xs:
|
|
inc i
|
|
yield x
|
|
#!STEP
|
|
|
|
# and shrink it again
|
|
#!FILE clleaf.nim
|
|
type Ev* = proc (s: string): string {.closure.}
|
|
|
|
proc leafMaker*(tag: string): Ev =
|
|
var n = 0
|
|
proc outer(s: string): string =
|
|
proc inner(t: string): string =
|
|
inc n
|
|
tag & ":" & t & ":" & $n
|
|
inner(s)
|
|
result = outer
|
|
|
|
iterator leafIter*[T](xs: seq[T]): T {.closure.} =
|
|
for x in xs: yield x
|
|
#!STEP
|