diff options
Diffstat (limited to 'compiler/lambdalifting.nim')
-rw-r--r-- | compiler/lambdalifting.nim | 138 |
1 files changed, 71 insertions, 67 deletions
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index c23ca52cb..b552d9455 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -126,32 +126,32 @@ proc newCall(a: PSym, b: PNode): PNode = result.add newSymNode(a) result.add b -proc createClosureIterStateType*(g: ModuleGraph; iter: PSym): PType = +proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PType = var n = newNodeI(nkRange, iter.info) n.add newIntNode(nkIntLit, -1) n.add newIntNode(nkIntLit, 0) - result = newType(tyRange, iter) + result = newType(tyRange, nextId(idgen), iter) result.n = n var intType = nilOrSysInt(g) - if intType.isNil: intType = newType(tyInt, iter) + if intType.isNil: intType = newType(tyInt, nextId(idgen), iter) rawAddSon(result, intType) -proc createStateField(g: ModuleGraph; iter: PSym): PSym = - result = newSym(skField, getIdent(g.cache, ":state"), iter, iter.info) - result.typ = createClosureIterStateType(g, iter) +proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym = + result = newSym(skField, getIdent(g.cache, ":state"), nextId(idgen), iter, iter.info) + result.typ = createClosureIterStateType(g, iter, idgen) -proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType = +proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType = # YYY meh, just add the state field for every closure for now, it's too # hard to figure out if it comes from a closure iterator: - result = createObj(g, owner, info, final=false) - rawAddField(result, createStateField(g, owner)) + result = createObj(g, idgen, owner, info, final=false) + rawAddField(result, createStateField(g, owner, idgen)) -proc getClosureIterResult*(g: ModuleGraph; iter: PSym): PSym = +proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym = if resultPos < iter.ast.len: result = iter.ast[resultPos].sym else: # XXX a bit hacky: - result = newSym(skResult, getIdent(g.cache, ":result"), iter, iter.info, {}) + result = newSym(skResult, getIdent(g.cache, ":result"), nextId(idgen), iter, iter.info, {}) result.typ = iter.typ[0] incl(result.flags, sfUsed) iter.ast.add newSymNode(result) @@ -209,7 +209,7 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode = result[0] = le result[1] = ri -proc makeClosure*(g: ModuleGraph; prc: PSym; env: PNode; info: TLineInfo): PNode = +proc makeClosure*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; env: PNode; info: TLineInfo): PNode = result = newNodeIT(nkClosure, info, prc.typ) result.add(newSymNode(prc)) if env == nil: @@ -219,7 +219,7 @@ proc makeClosure*(g: ModuleGraph; prc: PSym; env: PNode; info: TLineInfo): PNode localError(g.config, info, "internal error: taking closure of closure") result.add(env) #if isClosureIterator(result.typ): - createTypeBoundOps(g, nil, result.typ, info) + createTypeBoundOps(g, nil, result.typ, info, idgen) if tfHasAsgn in result.typ.flags or optSeqDestructors in g.config.globalOptions: prc.flags.incl sfInjectDestructors @@ -237,13 +237,13 @@ proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} = let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro result = conf.backend == backendJs and not isCompileTime -proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; owner: PSym) = - createTypeBoundOps(g, nil, refType.lastSon, info) - createTypeBoundOps(g, nil, refType, info) +proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; idgen: IdGenerator; owner: PSym) = + createTypeBoundOps(g, nil, refType.lastSon, info, idgen) + createTypeBoundOps(g, nil, refType, info, idgen) if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions: owner.flags.incl sfInjectDestructors -proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode = +proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode = # transforms (iter) to (let env = newClosure[iter](); (iter, env)) if liftingHarmful(g.config, owner): return n let iter = n.sym @@ -255,10 +255,10 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode = var env: PNode if owner.isIterator: let it = getHiddenParam(g, owner) - addUniqueField(it.typ.skipTypes({tyOwned})[0], hp, g.cache) + addUniqueField(it.typ.skipTypes({tyOwned})[0], hp, g.cache, idgen) env = indirectAccess(newSymNode(it), hp, hp.info) else: - let e = newSym(skLet, iter.name, owner, n.info) + let e = newSym(skLet, iter.name, nextId(idgen), owner, n.info) e.typ = hp.typ e.flags = hp.flags env = newSymNode(e) @@ -267,13 +267,13 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode = result.add(v) # add 'new' statement: result.add newCall(getSysSym(g, n.info, "internalNew"), env) - createTypeBoundOpsLL(g, env.typ, n.info, owner) - result.add makeClosure(g, iter, env, n.info) + createTypeBoundOpsLL(g, env.typ, n.info, idgen, owner) + result.add makeClosure(g, idgen, iter, env, n.info) -proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode = +proc freshVarForClosureIter*(g: ModuleGraph; s: PSym; idgen: IdGenerator; owner: PSym): PNode = let envParam = getHiddenParam(g, owner) let obj = envParam.typ.skipTypes({tyOwned, tyRef, tyPtr}) - addField(obj, s, g.cache) + addField(obj, s, g.cache, idgen) var access = newSymNode(envParam) assert obj.kind == tyObject @@ -305,13 +305,15 @@ type ownerToType: Table[int, PType] somethingToDo: bool graph: ModuleGraph + idgen: IdGenerator -proc initDetectionPass(g: ModuleGraph; fn: PSym): DetectionPass = +proc initDetectionPass(g: ModuleGraph; fn: PSym; idgen: IdGenerator): DetectionPass = result.processed = initIntSet() result.capturedVars = initIntSet() result.ownerToType = initTable[int, PType]() result.processed.incl(fn.id) result.graph = g + result.idgen = idgen discard """ proc outer = @@ -327,15 +329,15 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym; info: TLineInfo): PType = result = c.ownerToType.getOrDefault(owner.id) if result.isNil: - result = newType(tyRef, owner) - let obj = createEnvObj(c.graph, owner, info) + result = newType(tyRef, nextId(c.idgen), owner) + let obj = createEnvObj(c.graph, c.idgen, owner, info) rawAddSon(result, obj) c.ownerToType[owner.id] = result -proc asOwnedRef(c: DetectionPass; t: PType): PType = +proc asOwnedRef(c: var DetectionPass; t: PType): PType = if optOwnedRefs in c.graph.config.globalOptions: assert t.kind == tyRef - result = newType(tyOwned, t.owner) + result = newType(tyOwned, nextId(c.idgen), t.owner) result.flags.incl tfHasOwned result.rawAddSon t else: @@ -344,7 +346,7 @@ proc asOwnedRef(c: DetectionPass; t: PType): PType = proc getEnvTypeForOwnerUp(c: var DetectionPass; owner: PSym; info: TLineInfo): PType = var r = c.getEnvTypeForOwner(owner, info) - result = newType(tyPtr, owner) + result = newType(tyPtr, nextId(c.idgen), owner) rawAddSon(result, r.skipTypes({tyOwned, tyRef, tyPtr})) proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) = @@ -372,7 +374,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) = if c.graph.config.selectedGC == gcDestructors and sfCursor notin upField.flags: localError(c.graph.config, dep.info, "internal error: up reference is not a .cursor") else: - let result = newSym(skField, upIdent, obj.owner, obj.owner.info) + let result = newSym(skField, upIdent, nextId(c.idgen), obj.owner, obj.owner.info) result.typ = fieldType when false: if c.graph.config.selectedGC == gcDestructors: @@ -410,7 +412,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) = let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner let t = c.getEnvTypeForOwner(owner, info) if cp == nil: - cp = newSym(skParam, getIdent(c.graph.cache, paramName), fn, fn.info) + cp = newSym(skParam, getIdent(c.graph.cache, paramName), nextId(c.idgen), fn, fn.info) incl(cp.flags, sfFromGeneric) cp.typ = t addHiddenParam(fn, cp) @@ -433,7 +435,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = if innerProc: if s.isIterator: c.somethingToDo = true if not c.processed.containsOrIncl(s.id): - let body = transformBody(c.graph, s, cache = true) + let body = transformBody(c.graph, c.idgen, s, cache = true) detectCapturedVars(body, s, c) let ow = s.skipGenericOwner if ow == owner: @@ -446,9 +448,9 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = #let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef, tyPtr}) if s.name.id == getIdent(c.graph.cache, ":state").id: - obj.n[0].sym.id = -s.id + obj.n[0].sym.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item) else: - addField(obj, s, c.graph.cache) + addField(obj, s, c.graph.cache, c.idgen) # direct or indirect dependency: elif (innerProc and s.typ.callConv == ccClosure) or interestingVar(s): discard """ @@ -470,7 +472,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id): let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr}) #getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr}) - addField(obj, s, c.graph.cache) + addField(obj, s, c.graph.cache, c.idgen) # create required upFields: var w = owner.skipGenericOwner if isInnerProc(w) or owner.isIterator: @@ -535,8 +537,8 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode = localError(g.config, n.info, "internal error: environment misses: " & s.name.s) result = n -proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo): PNode = - var v = newSym(skVar, getIdent(cache, envName), owner, info) +proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo; idgen: IdGenerator): PNode = + var v = newSym(skVar, getIdent(cache, envName), nextId(idgen), owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = typ result = newSymNode(v) @@ -548,7 +550,7 @@ proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo): PNo else: result = newSymNode(v) -proc setupEnvVar(owner: PSym; d: DetectionPass; +proc setupEnvVar(owner: PSym; d: var DetectionPass; c: var LiftingPass; info: TLineInfo): PNode = if owner.isIterator: return getHiddenParam(d.graph, owner).newSymNode @@ -557,10 +559,10 @@ proc setupEnvVar(owner: PSym; d: DetectionPass; let envVarType = d.ownerToType.getOrDefault(owner.id) if envVarType.isNil: localError d.graph.config, owner.info, "internal error: could not determine closure type" - result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info) + result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info, d.idgen) c.envVars[owner.id] = result if optOwnedRefs in d.graph.config.globalOptions: - var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), owner, info) + var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), nextId d.idgen, owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = envVarType c.unownedEnvVars[owner.id] = newSymNode(v) @@ -576,7 +578,7 @@ proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode = result = rawIndirectAccess(result, upField, p.info) proc rawClosureCreation(owner: PSym; - d: DetectionPass; c: var LiftingPass; + d: var DetectionPass; c: var LiftingPass; info: TLineInfo): PNode = result = newNodeI(nkStmtList, owner.info) @@ -602,7 +604,7 @@ proc rawClosureCreation(owner: PSym; let env2 = copyTree(env) env2.typ = unowned.typ result.add newAsgnStmt(unowned, env2, env.info) - createTypeBoundOpsLL(d.graph, unowned.typ, env.info, owner) + createTypeBoundOpsLL(d.graph, unowned.typ, env.info, d.idgen, owner) # add assignment statements for captured parameters: for i in 1..<owner.typ.n.len: @@ -611,7 +613,7 @@ proc rawClosureCreation(owner: PSym; let fieldAccess = indirectAccess(env, local, env.info) # add ``env.param = param`` result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info)) - createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info) + createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info, d.idgen) if tfHasAsgn in fieldAccess.typ.flags or optSeqDestructors in d.graph.config.globalOptions: owner.flags.incl sfInjectDestructors @@ -628,28 +630,28 @@ proc rawClosureCreation(owner: PSym; localError(d.graph.config, env.info, "internal error: cannot create up reference") # we are not in the sem'check phase anymore! so pass 'nil' for the PContext # and hope for the best: - createTypeBoundOpsLL(d.graph, env.typ, owner.info, owner) + createTypeBoundOpsLL(d.graph, env.typ, owner.info, d.idgen, owner) -proc finishClosureCreation(owner: PSym; d: DetectionPass; c: LiftingPass; +proc finishClosureCreation(owner: PSym; d: var DetectionPass; c: LiftingPass; info: TLineInfo; res: PNode) = if optOwnedRefs in d.graph.config.globalOptions: let unowned = c.unownedEnvVars[owner.id] assert unowned != nil let nilLit = newNodeIT(nkNilLit, info, unowned.typ) res.add newAsgnStmt(unowned, nilLit, info) - createTypeBoundOpsLL(d.graph, unowned.typ, info, owner) + createTypeBoundOpsLL(d.graph, unowned.typ, info, d.idgen, owner) proc closureCreationForIter(iter: PNode; - d: DetectionPass; c: var LiftingPass): PNode = + d: var DetectionPass; c: var LiftingPass): PNode = result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ) let owner = iter.sym.skipGenericOwner - var v = newSym(skVar, getIdent(d.graph.cache, envName), owner, iter.info) + var v = newSym(skVar, getIdent(d.graph.cache, envName), nextId(d.idgen), owner, iter.info) incl(v.flags, sfShadowed) v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ) var vnode: PNode if owner.isIterator: let it = getHiddenParam(d.graph, owner) - addUniqueField(it.typ.skipTypes({tyOwned, tyRef, tyPtr}), v, d.graph.cache) + addUniqueField(it.typ.skipTypes({tyOwned, tyRef, tyPtr}), v, d.graph.cache, d.idgen) vnode = indirectAccess(newSymNode(it), v, v.info) else: vnode = v.newSymNode @@ -657,7 +659,7 @@ proc closureCreationForIter(iter: PNode; addVar(vs, vnode) result.add(vs) result.add(newCall(getSysSym(d.graph, iter.info, "internalNew"), vnode)) - createTypeBoundOpsLL(d.graph, vnode.typ, iter.info, owner) + createTypeBoundOpsLL(d.graph, vnode.typ, iter.info, d.idgen, owner) let upField = lookupInRecord(v.typ.skipTypes({tyOwned, tyRef, tyPtr}).n, getIdent(d.graph.cache, upName)) if upField != nil: @@ -667,9 +669,9 @@ proc closureCreationForIter(iter: PNode; u, iter.info)) else: localError(d.graph.config, iter.info, "internal error: cannot create up reference for iter") - result.add makeClosure(d.graph, iter.sym, vnode, iter.info) + result.add makeClosure(d.graph, d.idgen, iter.sym, vnode, iter.info) -proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass; +proc accessViaEnvVar(n: PNode; owner: PSym; d: var DetectionPass; c: var LiftingPass): PNode = var access = setupEnvVar(owner, d, c, n.info) if optOwnedRefs in d.graph.config.globalOptions: @@ -685,21 +687,21 @@ proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass; proc getStateField*(g: ModuleGraph; owner: PSym): PSym = getHiddenParam(g, owner).typ.skipTypes({tyOwned, tyRef, tyPtr}).n[0].sym -proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; +proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass; c: var LiftingPass): PNode -proc symToClosure(n: PNode; owner: PSym; d: DetectionPass; +proc symToClosure(n: PNode; owner: PSym; d: var DetectionPass; c: var LiftingPass): PNode = let s = n.sym if s == owner: # recursive calls go through (lambda, hiddenParam): let available = getHiddenParam(d.graph, owner) - result = makeClosure(d.graph, s, available.newSymNode, n.info) + result = makeClosure(d.graph, d.idgen, s, available.newSymNode, n.info) elif s.isIterator: result = closureCreationForIter(n, d, c) elif s.skipGenericOwner == owner: # direct dependency, so use the outer's env variable: - result = makeClosure(d.graph, s, setupEnvVar(owner, d, c, n.info), n.info) + result = makeClosure(d.graph, d.idgen, s, setupEnvVar(owner, d, c, n.info), n.info) else: let available = getHiddenParam(d.graph, owner) let wanted = getHiddenParam(d.graph, s).typ @@ -707,7 +709,7 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass; var access = newSymNode(available) while true: if access.typ == wanted: - return makeClosure(d.graph, s, access, n.info) + return makeClosure(d.graph, d.idgen, s, access, n.info) let obj = access.typ.skipTypes({tyOwned, tyRef, tyPtr}) let upField = lookupInRecord(obj.n, getIdent(d.graph.cache, upName)) if upField == nil: @@ -715,7 +717,7 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass; return n access = rawIndirectAccess(access, upField, n.info) -proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; +proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass; c: var LiftingPass): PNode = result = n case n.kind @@ -727,7 +729,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; # echo renderTree(s.getBody, {renderIds}) let oldInContainer = c.inContainer c.inContainer = 0 - var body = transformBody(d.graph, s, cache = false) + var body = transformBody(d.graph, d.idgen, s, cache = false) body = liftCapturedVars(body, s, d, c) if c.envVars.getOrDefault(s.id).isNil: s.transformedBody = body @@ -833,8 +835,9 @@ proc semCaptureSym*(s, owner: PSym) = # since the analysis is not entirely correct, we don't set 'tfCapturesEnv' # here -proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNode = - var d = initDetectionPass(g, fn) +proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType; + idgen: IdGenerator): PNode = + var d = initDetectionPass(g, fn, idgen) var c = initLiftingPass(fn) # pretend 'fn' is a closure iterator for the analysis: let oldKind = fn.kind @@ -847,7 +850,8 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNo fn.transitionRoutineSymKind(oldKind) fn.typ.callConv = oldCC -proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode = +proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool; + idgen: IdGenerator): PNode = # XXX backend == backendJs does not suffice! The compiletime stuff needs # the transformation even when compiling to JS ... @@ -862,7 +866,7 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PN result = body tooEarly = true else: - var d = initDetectionPass(g, fn) + var d = initDetectionPass(g, fn, idgen) detectCapturedVars(body, fn, d) if not d.somethingToDo and fn.isIterator: addClosureParam(d, fn, body.info) @@ -886,7 +890,7 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode = # ------------------- iterator transformation -------------------------------- -proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode = +proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym): PNode = # problem ahead: the iterator could be invoked indirectly, but then # we don't know what environment to create here: # @@ -931,7 +935,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode = let iter = op.sym let hp = getHiddenParam(g, iter) - env = newSym(skLet, iter.name, owner, body.info) + env = newSym(skLet, iter.name, nextId(idgen), owner, body.info) env.typ = hp.typ env.flags = hp.flags @@ -940,7 +944,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode = result.add(v) # add 'new' statement: result.add(newCall(getSysSym(g, env.info, "internalNew"), env.newSymNode)) - createTypeBoundOpsLL(g, env.typ, body.info, owner) + createTypeBoundOpsLL(g, env.typ, body.info, idgen, owner) elif op.kind == nkStmtListExpr: let closure = op.lastSon @@ -966,7 +970,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode = vpart.add newNodeI(nkEmpty, body.info) # no explicit type if not env.isNil: - call[0] = makeClosure(g, call[0].sym, env.newSymNode, body.info) + call[0] = makeClosure(g, idgen, call[0].sym, env.newSymNode, body.info) vpart.add call v2.add vpart |