From 7b539c9e582e441cdb7e078cdbe247d06a74ad0e Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 16 Jun 2012 18:29:22 +0200 Subject: [PATCH] simple example works again --- compiler/lambdalifting.nim | 41 +++++++++++++++++++++++++++----------- tests/run/tclosure2.nim | 5 +++-- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 7a21428a82..96cf6aef0b 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -165,6 +165,9 @@ proc indirectAccess(a: PNode, b: PSym, info: TLineInfo): PNode = deref.typ = x.typ.sons[0] let field = getSymFromList(deref.typ.n, b.name) + if field == nil: + echo b.name.s + assert false addSon(deref, x) result = newNodeI(nkDotExpr, info) addSon(result, deref) @@ -223,13 +226,16 @@ proc captureVar(o: POuterContext, i: PInnerContext, local: PSym, incl(cp.flags, sfFromGeneric) i.tup = newType(tyTuple, i.fn) i.tup.n = newNodeI(nkRecList, i.fn.info) - cp.typ = i.tup + cp.typ = newType(tyRef, i.fn) + addSon(cp.typ, i.tup) i.closureParam = cp + addHiddenParam(i.fn, i.closureParam) addField(i.tup, local) var it = i.up var access = newSymNode(i.closureParam) var levelsUp = 0 while it.fn.id != local.owner.id: + assert false access = indirectAccess(access, o.shared.upField, info) it = it.up assert it != nil @@ -284,6 +290,11 @@ proc transformInnerProc(o: POuterContext, i: PInnerContext, n: PNode): PNode = let x = transformInnerProc(o, i, n.sons[j]) if x != nil: n.sons[j] = x +proc closureCreationPoint(n: PNode): PNode = + result = newNodeI(nkStmtList, n.info) + result.add(emptyNode) + result.add(n) + proc searchForInnerProcs(o: POuterContext, n: PNode) = case n.kind of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: @@ -305,9 +316,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) = for i in countup(0, body - 1): searchForInnerProcs(o, n.sons[i]) # special handling for the loop body: let oldBlock = o.currentBlock - var ex = newNodeI(nkStmtList, n.info) - ex.add(emptyNode) - ex.add(n.sons[body]) + let ex = closureCreationPoint(n.sons[body]) o.currentBlock = ex searchForInnerProcs(o, n.sons[body]) n.sons[body] = ex @@ -320,10 +329,12 @@ proc searchForInnerProcs(o: POuterContext, n: PNode) = if it.kind == nkCommentStmt: nil elif it.kind == nkIdentDefs: if it.sons[0].kind != nkSym: InternalError(it.info, "transformOuter") + #echo "set: ", it.sons[0].sym.name.s, " ", o.currentBlock == nil IdNodeTablePut(o.localsToEnclosingScope, it.sons[0].sym, o.currentBlock) elif it.kind == nkVarTuple: var L = sonsLen(it) for j in countup(0, L-3): + #echo "set: ", it.sons[j].sym.name.s, " ", o.currentBlock == nil IdNodeTablePut(o.localsToEnclosingScope, it.sons[j].sym, o.currentBlock) else: @@ -350,11 +361,14 @@ proc addVar*(father, v: PNode) = addSon(father, vpart) proc generateClosureCreation(o: POuterContext, scope: PNode): PNode = - # add assignment if its a parameter that has been captured: - var env = newSym(skParam, getIdent(envName), o.fn) + # add assignment if it's a parameter that has been captured: + var env = newSym(skVar, getIdent(envName), o.fn) + incl(env.flags, sfShadowed) env.info = scope.info - env.typ = newType(tyTuple, o.fn) - env.typ.n = newNodeI(nkRecList, scope.info) + env.typ = newType(tyRef, o.fn) + var tup = newType(tyTuple, o.fn) + tup.n = newNodeI(nkRecList, scope.info) + env.typ.addSon(tup) result = newNodeI(nkStmtList, env.info) var v = newNodeI(nkVarSection, env.info) @@ -367,7 +381,7 @@ proc generateClosureCreation(o: POuterContext, scope: PNode): PNode = for v, scope2 in pairs(o.localsToEnclosingScope): if scope2 == scope: let local = PSym(v) - addField(env.typ, local) + addField(tup, local) let fieldAccess = indirectAccess(env, local, env.info) if sfByCopy in local.flags or local.kind == skParam: # add ``env.param = param`` @@ -404,7 +418,7 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode = # change 'local' to 'closure.local', unless it's a 'byCopy' variable: if sfByCopy notin local.flags: result = IdNodeTableGet(o.localsToAccess, local) - assert result != nil + assert result != nil, "cannot find: " & local.name.s # else it is captured by copy and this means that 'outer' should continue # to access the local as a local. of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, @@ -425,9 +439,12 @@ proc liftLambdas(fn: PSym, shared: PLLShared, body: PNode): PNode = result = body else: var o = newOuterContext(fn, shared) + let ex = closureCreationPoint(body) + o.currentBlock = ex searchForInnerProcs(o, body) - result = transformOuterProc(o, body) - if result == nil: result = body + let a = transformOuterProc(o, body) + result = ex + #echo renderTree(result) # XXX should 's' be replaced by a tuple ('s', env)? diff --git a/tests/run/tclosure2.nim b/tests/run/tclosure2.nim index c71cc9f1cc..b44c92db78 100644 --- a/tests/run/tclosure2.nim +++ b/tests/run/tclosure2.nim @@ -23,14 +23,15 @@ when true: proc bx = if i > 10: return i += 1 - for j in 0 .. 0: echo i + #for j in 0 .. 0: echo i bx() bx() + echo i ax() -when true: +when false: proc accumulator(start: int): (proc(): int {.closure.}) = var x = start-1 #let dummy = proc =