fixes closure generation when only paramters are captured

This commit is contained in:
Andreas Rumpf 2015-12-29 02:44:37 +01:00
commit 5c9332c57d

View file

@ -387,6 +387,7 @@ type
processed: IntSet processed: IntSet
envCreation: PNode envCreation: PNode
envVar: PNode envVar: PNode
owner: PSym # the owner of the 'envVar'
proc initLiftingPass(fn: PSym): LiftingPass = proc initLiftingPass(fn: PSym): LiftingPass =
result.processed = initIntSet() result.processed = initIntSet()
@ -448,16 +449,20 @@ proc newEnvVar(owner: PSym; typ: PType): PNode =
else: else:
result = newSymNode(v) result = newSymNode(v)
proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass; proc setupEnvVar(owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode = c: var LiftingPass) =
if c.envVar.isNil: if c.owner != owner or c.envVar.isNil:
assert c.envCreation.isNil
let envVarType = d.ownerToType.getOrDefault(owner.id) let envVarType = d.ownerToType.getOrDefault(owner.id)
if envVarType.isNil: if envVarType.isNil:
localError n.info, "internal error: could not determine closure type" localError owner.info, "internal error: could not determine closure type"
c.envVar = newEnvVar(owner, envVarType) c.envVar = newEnvVar(owner, envVarType)
c.envCreation = rawClosureCreation(c.envVar, owner, d, c.envCreation = rawClosureCreation(c.envVar, owner, d,
envVarType.sons[0]) envVarType.sons[0])
c.owner = owner
proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode =
setupEnvVar(owner, d, c)
let access = c.envVar let access = c.envVar
let obj = access.typ.sons[0] let obj = access.typ.sons[0]
let field = getFieldFromObj(obj, n.sym) let field = getFieldFromObj(obj, n.sym)
@ -545,10 +550,16 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode =
result.add(stateAsgnStmt) result.add(stateAsgnStmt)
result.flags.incl nfLL result.flags.incl nfLL
proc symToClosure(n: PNode; owner: PSym; c: LiftingPass): PNode = proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode =
let s = n.sym let s = n.sym
# direct dependency, so use the outer's env variable: # direct dependency, so use the outer's env variable:
if s.skipGenericOwner == owner: if s.skipGenericOwner == owner:
if c.owner != owner:
setupEnvVar(owner, d, c)
if c.owner != owner or c.envVar.isNil:
localError(n.info, "internal error: no environment var found")
return n
result = makeClosure(s, c.envVar, n.info) result = makeClosure(s, c.envVar, n.info)
elif s == owner: elif s == owner:
# recursive calls go through (lambda, hiddenParam): # recursive calls go through (lambda, hiddenParam):
@ -566,7 +577,7 @@ proc symToClosure(n: PNode; owner: PSym; c: LiftingPass): PNode =
let upField = lookupInRecord(obj.n, getIdent(upName)) let upField = lookupInRecord(obj.n, getIdent(upName))
if upField == nil: if upField == nil:
localError(n.info, "internal error: no environment found") localError(n.info, "internal error: no environment found")
break return n
access = rawIndirectAccess(access, upField, n.info) access = rawIndirectAccess(access, upField, n.info)
proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
@ -584,8 +595,10 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
if not c.processed.containsOrIncl(s.id): if not c.processed.containsOrIncl(s.id):
let oldEnvVar = c.envVar let oldEnvVar = c.envVar
let oldEnvCreation = c.envCreation let oldEnvCreation = c.envCreation
let oldOwner = c.owner
c.envVar = nil c.envVar = nil
c.envCreation = nil c.envCreation = nil
c.owner = s
let body = wrapIterBody(liftCapturedVars(s.getBody, s, d, c), s) let body = wrapIterBody(liftCapturedVars(s.getBody, s, d, c), s)
if c.envCreation.isNil: if c.envCreation.isNil:
s.ast.sons[bodyPos] = body s.ast.sons[bodyPos] = body
@ -594,7 +607,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
c.envCreation = nil c.envCreation = nil
c.envVar = oldEnvVar c.envVar = oldEnvVar
c.envCreation = oldEnvCreation c.envCreation = oldEnvCreation
result = symToClosure(n, owner, c) c.owner = oldOwner
result = symToClosure(n, owner, d, c)
elif s.id in d.capturedVars: elif s.id in d.capturedVars:
if s.owner != owner: if s.owner != owner:
result = accessViaEnvParam(n, owner) result = accessViaEnvParam(n, owner)
@ -672,6 +686,7 @@ proc liftLambdas*(fn: PSym, body: PNode): PNode =
else: else:
result = body result = body
#if fn.name.s == "outer": #if fn.name.s == "outer":
# echo "had something to do ", d.somethingToDo
# echo renderTree(result, {renderIds}) # echo renderTree(result, {renderIds})
proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode = proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =