diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index cd51aaddd..daaa145e1 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -94,6 +94,7 @@ type options: TOptions module: BModule g: PGlobals + generatedParamCopies: IntSet beforeRetNeeded: bool unique: int # for temp identifier generation blocks: seq[TBlock] @@ -924,7 +925,7 @@ const proc needsNoCopy(p: PProc; y: PNode): bool = return y.kind in nodeKindsNeedNoCopy or - (mapType(y.typ) != etyBaseIndex and + ((mapType(y.typ) != etyBaseIndex or y.sym.kind == skParam) and (skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyLent, tyVar, tyCString, tyProc} + IntegralTypes)) @@ -1232,12 +1233,29 @@ proc genProcForSymIfNeeded(p: PProc, s: PSym) = if owner != nil: add(owner.locals, newp) else: attachProc(p, newp, s) +proc genCopyForParamIfNeeded(p: PProc, n: PNode) = + let s = n.sym + if p.prc == s.owner or needsNoCopy(p, n): + return + var owner = p.up + while true: + if owner == nil: + internalError(p.config, n.info, "couldn't find the owner proc of the closed over param: " & s.name.s) + if owner.prc == s.owner: + if not owner.generatedParamCopies.containsOrIncl(s.id): + let copy = "$1 = nimCopy(null, $1, $2);$n" % [s.loc.r, genTypeInfo(p, s.typ)] + add(owner.locals, owner.indentLine(copy)) + return + owner = owner.up + proc genSym(p: PProc, n: PNode, r: var TCompRes) = var s = n.sym case s.kind of skVar, skLet, skParam, skTemp, skResult, skForVar: if s.loc.r == nil: internalError(p.config, n.info, "symbol has no generated name: " & s.name.s) + if s.kind == skParam: + genCopyForParamIfNeeded(p, n) let k = mapType(p, s.typ) if k == etyBaseIndex: r.typ = etyBaseIndex diff --git a/tests/js/tclosures.nim b/tests/js/tclosures.nim index 659c60092..70037f4bf 100644 --- a/tests/js/tclosures.nim +++ b/tests/js/tclosures.nim @@ -49,3 +49,47 @@ for i in 1 .. 10: let results = runCallbacks() doAssert(expected == $results) + +block issue7048: + block: + proc foo(x: seq[int]): auto = + proc bar: int = x[1] + bar + + var stuff = @[1, 2] + let f = foo(stuff) + stuff[1] = 321 + doAssert f() == 2 + + block: + proc foo(x: tuple[things: string]; y: array[3, int]): auto = + proc very: auto = + proc deeply: auto = + proc nested: (char, int) = (x.things[0], y[1]) + nested + deeply + very() + + var + stuff = (things: "NIM") + stuff2 = [32, 64, 96] + let f = foo(stuff, stuff2) + stuff.things = "VIM" + stuff2[1] *= 10 + doAssert f()() == ('N', 64) + doAssert (stuff.things[0], stuff2[1]) == ('V', 640) + + block: + proc foo(x: ptr string): auto = + proc bar(): int = len(x[]) + bar + + var + s1 = "xyz" + s2 = "stuff" + p = addr s1 + + let f = foo(p) + p = addr s2 + doAssert len(p[]) == 5 + doAssert f() == 3 \ No newline at end of file