fixes closure generation when only paramters are captured
This commit is contained in:
parent
870b03707b
commit
5c9332c57d
1 changed files with 23 additions and 8 deletions
|
|
@ -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 =
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue