[refactoring] liftdestructors.nim is callable from lambdalifting; refs #11217

This commit is contained in:
Araq 2019-06-12 10:44:37 +02:00
commit b056d32a79
3 changed files with 120 additions and 104 deletions

View file

@ -12,7 +12,7 @@
import import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, intsets, strutils, options, ast, astalgo, trees, treetab, msgs,
idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos, idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos,
transf transf, liftdestructors
discard """ discard """
The basic approach is that captured vars need to be put on the heap and The basic approach is that captured vars need to be put on the heap and
@ -583,6 +583,11 @@ proc rawClosureCreation(owner: PSym;
# oldenv, env.info)) # oldenv, env.info))
else: else:
localError(d.graph.config, env.info, "internal error: cannot create up reference") 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:
when false:
if optNimV2 in d.graph.config.globalOptions:
createTypeBoundOps(d.graph, nil, env.typ, owner.info)
proc closureCreationForIter(iter: PNode; proc closureCreationForIter(iter: PNode;
d: DetectionPass; c: var LiftingPass): PNode = d: DetectionPass; c: var LiftingPass): PNode =

View file

@ -18,19 +18,19 @@ import modulegraphs, lineinfos, idents, ast, astalgo, renderer, semdata,
type type
TLiftCtx = object TLiftCtx = object
graph: ModuleGraph g: ModuleGraph
info: TLineInfo # for construction info: TLineInfo # for construction
kind: TTypeAttachedOp kind: TTypeAttachedOp
fn: PSym fn: PSym
asgnForType: PType asgnForType: PType
recurse: bool recurse: bool
c: PContext c: PContext # c can be nil, then we are called from lambdalifting!
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp; proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo): PSym info: TLineInfo): PSym
proc createTypeBoundOps*(c: PContext; orig: PType; info: TLineInfo) proc createTypeBoundOps*(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo)
proc at(a, i: PNode, elemType: PType): PNode = proc at(a, i: PNode, elemType: PType): PNode =
result = newNodeI(nkBracketExpr, a.info, 2) result = newNodeI(nkBracketExpr, a.info, 2)
@ -40,7 +40,7 @@ proc at(a, i: PNode, elemType: PType): PNode =
proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
for i in 0 ..< t.len: for i in 0 ..< t.len:
let lit = lowerings.newIntLit(c.graph, x.info, i) let lit = lowerings.newIntLit(c.g, x.info, i)
fillBody(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i])) fillBody(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i]))
proc dotField(x: PNode, f: PSym): PNode = proc dotField(x: PNode, f: PSym): PNode =
@ -87,7 +87,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
of nkRecList: of nkRecList:
for t in items(n): fillBodyObj(c, t, body, x, y) for t in items(n): fillBodyObj(c, t, body, x, y)
else: else:
illFormedAstLocal(n, c.graph.config) illFormedAstLocal(n, c.g.config)
proc genAddr(g: ModuleGraph; x: PNode): PNode = proc genAddr(g: ModuleGraph; x: PNode): PNode =
if x.kind == nkHiddenDeref: if x.kind == nkHiddenDeref:
@ -124,20 +124,28 @@ proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(op, y)) result = newAsgnStmt(x, newOpCall(op, y))
proc useNoGc(c: TLiftCtx; t: PType): bool {.inline.} = proc useNoGc(c: TLiftCtx; t: PType): bool {.inline.} =
result = optNimV2 in c.graph.config.globalOptions and result = optNimV2 in c.g.config.globalOptions and
({tfHasGCedMem, tfHasOwned} * t.flags != {} or t.isGCedMem) ({tfHasGCedMem, tfHasOwned} * t.flags != {} or t.isGCedMem)
proc instantiateGeneric(c: var TLiftCtx; op: PSym; t, typeInst: PType): PSym =
if c.c != nil and typeInst != nil:
result = c.c.instTypeBoundOp(c.c, op, typeInst, c.info, attachedAsgn, 1)
else:
localError(c.g.config, c.info,
"cannot generate destructor for generic type: " & typeToString(t))
result = nil
proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
field: var PSym): bool = field: var PSym): bool =
if optNimV2 in c.graph.config.globalOptions: if optNimV2 in c.g.config.globalOptions:
let op = field let op = field
if field != nil and sfOverriden in field.flags: if field != nil and sfOverriden in field.flags:
if sfError in op.flags: if sfError in op.flags:
incl c.fn.flags, sfError incl c.fn.flags, sfError
#else: #else:
# markUsed(c.graph.config, c.info, op, c.graph.usageSym) # markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op) onUse(c.info, op)
body.add newAsgnCall(c.graph, op, x, y) body.add newAsgnCall(c.g, op, x, y)
result = true result = true
elif tfHasAsgn in t.flags: elif tfHasAsgn in t.flags:
var op: PSym var op: PSym
@ -151,38 +159,37 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
else: else:
op = field op = field
if op == nil: if op == nil:
op = produceSym(c.c, t, c.kind, c.info) op = produceSym(c.g, c.c, t, c.kind, c.info)
if sfError in op.flags: if sfError in op.flags:
incl c.fn.flags, sfError incl c.fn.flags, sfError
#else: #else:
# markUsed(c.graph.config, c.info, op, c.graph.usageSym) # markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op) onUse(c.info, op)
# We also now do generic instantiations in the destructor lifting pass: # We also now do generic instantiations in the destructor lifting pass:
if op.ast[genericParamsPos].kind != nkEmpty: if op.ast[genericParamsPos].kind != nkEmpty:
assert t.typeInst != nil op = instantiateGeneric(c, op, t, t.typeInst)
op = c.c.instTypeBoundOp(c.c, op, t.typeInst, c.info, attachedAsgn, 1)
field = op field = op
#echo "trying to use ", op.ast #echo "trying to use ", op.ast
#echo "for ", op.name.s, " " #echo "for ", op.name.s, " "
#debug(t) #debug(t)
#return false #return false
assert op.ast[genericParamsPos].kind == nkEmpty assert op.ast[genericParamsPos].kind == nkEmpty
body.add newAsgnCall(c.graph, op, x, y) body.add newAsgnCall(c.g, op, x, y)
result = true result = true
proc addDestructorCall(c: var TLiftCtx; t: PType; body, x: PNode) = proc addDestructorCall(c: var TLiftCtx; t: PType; body, x: PNode) =
var op = t.destructor var op = t.destructor
if op == nil and useNoGc(c, t): if op == nil and useNoGc(c, t):
op = produceSym(c.c, t, attachedDestructor, c.info) op = produceSym(c.g, c.c, t, attachedDestructor, c.info)
doAssert op != nil doAssert op != nil
doAssert op == t.destructor doAssert op == t.destructor
if op != nil: if op != nil:
#markUsed(c.graph.config, c.info, op, c.graph.usageSym) #markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op) onUse(c.info, op)
body.add destructorCall(c.graph, op, x) body.add destructorCall(c.g, op, x)
elif useNoGc(c, t): elif useNoGc(c, t):
internalError(c.graph.config, c.info, internalError(c.g.config, c.info,
"type-bound operator could not be resolved") "type-bound operator could not be resolved")
proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
@ -192,14 +199,13 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
if op != nil and sfOverriden in op.flags: if op != nil and sfOverriden in op.flags:
if op.ast[genericParamsPos].kind != nkEmpty: if op.ast[genericParamsPos].kind != nkEmpty:
assert t.typeInst != nil
# patch generic destructor: # patch generic destructor:
op = c.c.instTypeBoundOp(c.c, op, t.typeInst, c.info, attachedAsgn, 1) op = instantiateGeneric(c, op, t, t.typeInst)
t.attachedOps[attachedDestructor] = op t.attachedOps[attachedDestructor] = op
#markUsed(c.graph.config, c.info, op, c.graph.usageSym) #markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op) onUse(c.info, op)
body.add destructorCall(c.graph, op, x) body.add destructorCall(c.g, op, x)
result = true result = true
#result = addDestructorCall(c, t, body, x) #result = addDestructorCall(c, t, body, x)
of attachedAsgn: of attachedAsgn:
@ -209,7 +215,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
of attachedDeepCopy: of attachedDeepCopy:
let op = t.attachedOps[attachedDeepCopy] let op = t.attachedOps[attachedDeepCopy]
if op != nil: if op != nil:
#markUsed(c.graph.config, c.info, op, c.graph.usageSym) #markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op) onUse(c.info, op)
body.add newDeepCopyCall(op, x, y) body.add newDeepCopyCall(op, x, y)
result = true result = true
@ -226,13 +232,13 @@ proc addVar(father, v, value: PNode) =
addSon(father, vpart) addSon(father, vpart)
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(c.graph.cache, lowerings.genPrefix), c.fn, c.info) var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.fn, c.info)
temp.typ = getSysType(c.graph, body.info, tyInt) temp.typ = getSysType(c.g, body.info, tyInt)
incl(temp.flags, sfFromGeneric) incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, c.info) var v = newNodeI(nkVarSection, c.info)
result = newSymNode(temp) result = newSymNode(temp)
v.addVar(result, lowerings.newIntLit(c.graph, body.info, first)) v.addVar(result, lowerings.newIntLit(c.g, body.info, first))
body.add v body.add v
proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode = proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode =
@ -242,9 +248,9 @@ proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode =
proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode = proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
result = newNodeI(nkWhileStmt, c.info, 2) result = newNodeI(nkWhileStmt, c.info, 2)
let cmp = genBuiltin(c.graph, mLtI, "<", i) let cmp = genBuiltin(c.g, mLtI, "<", i)
cmp.add genLen(c.graph, dest) cmp.add genLen(c.g, dest)
cmp.typ = getSysType(c.graph, c.info, tyBool) cmp.typ = getSysType(c.g, c.info, tyBool)
result.sons[0] = cmp result.sons[0] = cmp
result.sons[1] = newNodeI(nkStmtList, c.info) result.sons[1] = newNodeI(nkStmtList, c.info)
@ -252,8 +258,8 @@ proc genIf(c: var TLiftCtx; cond, action: PNode): PNode =
result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action)) result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action))
proc addIncStmt(c: var TLiftCtx; body, i: PNode) = proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
let incCall = genBuiltin(c.graph, mInc, "inc", i) let incCall = genBuiltin(c.g, mInc, "inc", i)
incCall.add lowerings.newIntLit(c.graph, c.info, 1) incCall.add lowerings.newIntLit(c.g, c.info, 1)
body.add incCall body.add incCall
proc newSeqCall(g: ModuleGraph; x, y: PNode): PNode = proc newSeqCall(g: ModuleGraph; x, y: PNode): PNode =
@ -270,14 +276,14 @@ proc setLenStrCall(g: ModuleGraph; x, y: PNode): PNode =
result.add lenCall result.add lenCall
proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode = proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode =
let lenCall = genBuiltin(c.graph, mLengthSeq, "len", y) let lenCall = genBuiltin(c.g, mLengthSeq, "len", y)
lenCall.typ = getSysType(c.graph, x.info, tyInt) lenCall.typ = getSysType(c.g, x.info, tyInt)
var op = getSysMagic(c.graph, x.info, "setLen", mSetLengthSeq) var op = getSysMagic(c.g, x.info, "setLen", mSetLengthSeq)
op = c.c.instTypeBoundOp(c.c, op, t, c.info, attachedAsgn, 1) op = instantiateGeneric(c, op, t, t)
result = newTree(nkCall, newSymNode(op, x.info), x, lenCall) result = newTree(nkCall, newSymNode(op, x.info), x, lenCall)
proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let i = declareCounter(c, body, firstOrd(c.graph.config, t)) let i = declareCounter(c, body, firstOrd(c.g.config, t))
let whileLoop = genWhileLoop(c, i, x) let whileLoop = genWhileLoop(c, i, x)
let elemType = t.lastSon let elemType = t.lastSon
fillBody(c, elemType, whileLoop.sons[1], x.at(i, elemType), fillBody(c, elemType, whileLoop.sons[1], x.at(i, elemType),
@ -296,63 +302,63 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add setLenSeqCall(c, t, x, y) body.add setLenSeqCall(c, t, x, y)
forallElements(c, t, body, x, y) forallElements(c, t, body, x, y)
of attachedSink: of attachedSink:
let moveCall = genBuiltin(c.graph, mMove, "move", x) let moveCall = genBuiltin(c.g, mMove, "move", x)
moveCall.add y moveCall.add y
doAssert t.destructor != nil doAssert t.destructor != nil
moveCall.add destructorCall(c.graph, t.destructor, x) moveCall.add destructorCall(c.g, t.destructor, x)
body.add moveCall body.add moveCall
of attachedDestructor: of attachedDestructor:
# destroy all elements: # destroy all elements:
forallElements(c, t, body, x, y) forallElements(c, t, body, x, y)
body.add genBuiltin(c.graph, mDestroy, "destroy", x) body.add genBuiltin(c.g, mDestroy, "destroy", x)
proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
createTypeBoundOps(c.c, t, body.info) createTypeBoundOps(c.g, c.c, t, body.info)
case c.kind case c.kind
of attachedAsgn, attachedDeepCopy: of attachedAsgn, attachedDeepCopy:
doAssert t.assignment != nil doAssert t.assignment != nil
body.add newAsgnCall(c.graph, t.assignment, x, y) body.add newAsgnCall(c.g, t.assignment, x, y)
of attachedSink: of attachedSink:
# we always inline the move for better performance: # we always inline the move for better performance:
let moveCall = genBuiltin(c.graph, mMove, "move", x) let moveCall = genBuiltin(c.g, mMove, "move", x)
moveCall.add y moveCall.add y
doAssert t.destructor != nil doAssert t.destructor != nil
moveCall.add destructorCall(c.graph, t.destructor, x) moveCall.add destructorCall(c.g, t.destructor, x)
body.add moveCall body.add moveCall
# alternatively we could do this: # alternatively we could do this:
when false: when false:
doAssert t.asink != nil doAssert t.asink != nil
body.add newAsgnCall(c.graph, t.asink, x, y) body.add newAsgnCall(c.g, t.asink, x, y)
of attachedDestructor: of attachedDestructor:
doAssert t.destructor != nil doAssert t.destructor != nil
body.add destructorCall(c.graph, t.destructor, x) body.add destructorCall(c.g, t.destructor, x)
proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind case c.kind
of attachedAsgn, attachedDeepCopy: of attachedAsgn, attachedDeepCopy:
body.add callCodegenProc(c.graph, "nimAsgnStrV2", c.info, genAddr(c.graph, x), y) body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c.g, x), y)
of attachedSink: of attachedSink:
let moveCall = genBuiltin(c.graph, mMove, "move", x) let moveCall = genBuiltin(c.g, mMove, "move", x)
moveCall.add y moveCall.add y
doAssert t.destructor != nil doAssert t.destructor != nil
moveCall.add destructorCall(c.graph, t.destructor, x) moveCall.add destructorCall(c.g, t.destructor, x)
body.add moveCall body.add moveCall
of attachedDestructor: of attachedDestructor:
body.add genBuiltin(c.graph, mDestroy, "destroy", x) body.add genBuiltin(c.g, mDestroy, "destroy", x)
proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind case c.kind
of attachedSink: of attachedSink:
# we 'nil' y out afterwards so we *need* to take over its reference # we 'nil' y out afterwards so we *need* to take over its reference
# count value: # count value:
body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x)) body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
body.add newAsgnStmt(x, y) body.add newAsgnStmt(x, y)
of attachedAsgn: of attachedAsgn:
body.add genIf(c, y, callCodegenProc(c.graph, "nimIncWeakRef", c.info, y)) body.add genIf(c, y, callCodegenProc(c.g, "nimIncWeakRef", c.info, y))
body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x)) body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
body.add newAsgnStmt(x, y) body.add newAsgnStmt(x, y)
of attachedDestructor: of attachedDestructor:
body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x)) body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
of attachedDeepCopy: assert(false, "cannot happen") of attachedDeepCopy: assert(false, "cannot happen")
proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
@ -360,14 +366,14 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let elemType = t.lastSon let elemType = t.lastSon
#fillBody(c, elemType, actions, genDeref(x), genDeref(y)) #fillBody(c, elemType, actions, genDeref(x), genDeref(y))
#var disposeCall = genBuiltin(c.graph, mDispose, "dispose", x) #var disposeCall = genBuiltin(c.g, mDispose, "dispose", x)
if isFinal(elemType): if isFinal(elemType):
addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr)) addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr))
actions.add callCodegenProc(c.graph, "nimRawDispose", c.info, x) actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x)
else: else:
addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr)) addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr))
actions.add callCodegenProc(c.graph, "nimDestroyAndDispose", c.info, x) actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x)
case c.kind case c.kind
of attachedSink, attachedAsgn: of attachedSink, attachedAsgn:
@ -383,35 +389,35 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# have to go through some indirection; we delegate this to the codegen: # have to go through some indirection; we delegate this to the codegen:
let call = newNodeI(nkCall, c.info, 2) let call = newNodeI(nkCall, c.info, 2)
call.typ = t call.typ = t
call.sons[0] = newSymNode(createMagic(c.graph, "deepCopy", mDeepCopy)) call.sons[0] = newSymNode(createMagic(c.g, "deepCopy", mDeepCopy))
call.sons[1] = y call.sons[1] = y
body.add newAsgnStmt(x, call) body.add newAsgnStmt(x, call)
elif optNimV2 in c.graph.config.globalOptions: elif optNimV2 in c.g.config.globalOptions:
let xx = genBuiltin(c.graph, mAccessEnv, "accessEnv", x) let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.graph, c.info, tyPointer) xx.typ = getSysType(c.g, c.info, tyPointer)
case c.kind case c.kind
of attachedSink: of attachedSink:
# we 'nil' y out afterwards so we *need* to take over its reference # we 'nil' y out afterwards so we *need* to take over its reference
# count value: # count value:
body.add genIf(c, xx, callCodegenProc(c.graph, "nimDecWeakRef", c.info, xx)) body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
body.add newAsgnStmt(x, y) body.add newAsgnStmt(x, y)
of attachedAsgn: of attachedAsgn:
let yy = genBuiltin(c.graph, mAccessEnv, "accessEnv", y) let yy = genBuiltin(c.g, mAccessEnv, "accessEnv", y)
yy.typ = getSysType(c.graph, c.info, tyPointer) yy.typ = getSysType(c.g, c.info, tyPointer)
body.add genIf(c, yy, callCodegenProc(c.graph, "nimIncWeakRef", c.info, yy)) body.add genIf(c, yy, callCodegenProc(c.g, "nimIncWeakRef", c.info, yy))
body.add genIf(c, xx, callCodegenProc(c.graph, "nimDecWeakRef", c.info, xx)) body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
body.add newAsgnStmt(x, y) body.add newAsgnStmt(x, y)
of attachedDestructor: of attachedDestructor:
body.add genIf(c, xx, callCodegenProc(c.graph, "nimDecWeakRef", c.info, xx)) body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
of attachedDeepCopy: assert(false, "cannot happen") of attachedDeepCopy: assert(false, "cannot happen")
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c.graph, mAccessEnv, "accessEnv", x) let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.graph, c.info, tyPointer) xx.typ = getSysType(c.g, c.info, tyPointer)
var actions = newNodeI(nkStmtList, c.info) var actions = newNodeI(nkStmtList, c.info)
let elemType = t.lastSon let elemType = t.lastSon
#discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(xx)) #discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(xx))
actions.add callCodegenProc(c.graph, "nimDestroyAndDispose", c.info, xx) actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, xx)
case c.kind case c.kind
of attachedSink, attachedAsgn: of attachedSink, attachedAsgn:
body.add genIf(c, xx, actions) body.add genIf(c, xx, actions)
@ -427,7 +433,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
tyPtr, tyOpt, tyUncheckedArray: tyPtr, tyOpt, tyUncheckedArray:
defaultOp(c, t, body, x, y) defaultOp(c, t, body, x, y)
of tyRef: of tyRef:
if optNimV2 in c.graph.config.globalOptions: if optNimV2 in c.g.config.globalOptions:
weakrefOp(c, t, body, x, y) weakrefOp(c, t, body, x, y)
else: else:
defaultOp(c, t, body, x, y) defaultOp(c, t, body, x, y)
@ -438,7 +444,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
defaultOp(c, t, body, x, y) defaultOp(c, t, body, x, y)
of tyOwned: of tyOwned:
let base = t.skipTypes(abstractInstOwned) let base = t.skipTypes(abstractInstOwned)
if optNimV2 in c.graph.config.globalOptions: if optNimV2 in c.g.config.globalOptions:
case base.kind case base.kind
of tyRef: of tyRef:
ownedRefOp(c, base, body, x, y) ownedRefOp(c, base, body, x, y)
@ -457,13 +463,13 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of tySequence: of tySequence:
if useNoGc(c, t): if useNoGc(c, t):
useSeqOrStrOp(c, t, body, x, y) useSeqOrStrOp(c, t, body, x, y)
elif c.graph.config.selectedGC == gcDestructors: elif c.g.config.selectedGC == gcDestructors:
# note that tfHasAsgn is propagated so we need the check on # note that tfHasAsgn is propagated so we need the check on
# 'selectedGC' here to determine if we have the new runtime. # 'selectedGC' here to determine if we have the new runtime.
discard considerUserDefinedOp(c, t, body, x, y) discard considerUserDefinedOp(c, t, body, x, y)
elif tfHasAsgn in t.flags: elif tfHasAsgn in t.flags:
if c.kind != attachedDestructor: if c.kind != attachedDestructor:
body.add newSeqCall(c.graph, x, y) body.add newSeqCall(c.g, x, y)
forallElements(c, t, body, x, y) forallElements(c, t, body, x, y)
else: else:
defaultOp(c, t, body, x, y) defaultOp(c, t, body, x, y)
@ -483,12 +489,12 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of tyTuple: of tyTuple:
fillBodyTup(c, t, body, x, y) fillBodyTup(c, t, body, x, y)
of tyVarargs, tyOpenArray: of tyVarargs, tyOpenArray:
localError(c.graph.config, c.info, "cannot copy openArray") localError(c.g.config, c.info, "cannot copy openArray")
of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
tyGenericParam, tyGenericBody, tyNil, tyUntyped, tyTyped, tyGenericParam, tyGenericBody, tyNil, tyUntyped, tyTyped,
tyTypeDesc, tyGenericInvocation, tyForward: tyTypeDesc, tyGenericInvocation, tyForward:
#internalError(c.graph.config, c.info, "assignment requested for type: " & typeToString(t)) #internalError(c.g.config, c.info, "assignment requested for type: " & typeToString(t))
discard discard
of tyVar, tyLent: of tyVar, tyLent:
if c.kind != attachedDestructor: if c.kind != attachedDestructor:
@ -497,25 +503,24 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
tyGenericInst, tyStatic, tyAlias, tySink: tyGenericInst, tyStatic, tyAlias, tySink:
fillBody(c, lastSon(t), body, x, y) fillBody(c, lastSon(t), body, x, y)
proc produceSymDistinctType(c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym = proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym =
assert typ.kind == tyDistinct assert typ.kind == tyDistinct
let baseType = typ[0] let baseType = typ[0]
if baseType.attachedOps[kind] == nil: if baseType.attachedOps[kind] == nil:
discard produceSym(c, baseType, kind, info) discard produceSym(g, c, baseType, kind, info)
typ.attachedOps[kind] = baseType.attachedOps[kind] typ.attachedOps[kind] = baseType.attachedOps[kind]
result = typ.attachedOps[kind] result = typ.attachedOps[kind]
proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp; proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo): PSym = info: TLineInfo): PSym =
if typ.kind == tyDistinct: if typ.kind == tyDistinct:
return produceSymDistinctType(c, typ, kind, info) return produceSymDistinctType(g, c, typ, kind, info)
var a: TLiftCtx var a: TLiftCtx
a.info = info a.info = info
a.graph = c.graph a.g = g
a.kind = kind a.kind = kind
a.c = c a.c = c
let g = c.graph
let body = newNodeI(nkStmtList, info) let body = newNodeI(nkStmtList, info)
let procname = getIdent(g.cache, AttachedOpToStr[kind]) let procname = getIdent(g.cache, AttachedOpToStr[kind])
@ -537,7 +542,7 @@ proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
typ.attachedOps[kind] = result typ.attachedOps[kind] = result
var tk: TTypeKind var tk: TTypeKind
if optNimV2 in c.graph.config.globalOptions: if optNimV2 in g.config.globalOptions:
tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind
else: else:
tk = tyNone # no special casing for strings and seqs tk = tyNone # no special casing for strings and seqs
@ -561,33 +566,39 @@ proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
template liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) = template liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
discard "now a nop" discard "now a nop"
proc patchBody(c: PContext; n: PNode; info: TLineInfo) = proc patchBody(g: ModuleGraph; c: PContext; n: PNode; info: TLineInfo) =
if n.kind in nkCallKinds: if n.kind in nkCallKinds:
if n[0].kind == nkSym and n[0].sym.magic == mDestroy: if n[0].kind == nkSym and n[0].sym.magic == mDestroy:
let t = n[1].typ.skipTypes(abstractVar) let t = n[1].typ.skipTypes(abstractVar)
if t.destructor == nil: if t.destructor == nil:
discard produceSym(c, t, attachedDestructor, info) discard produceSym(g, c, t, attachedDestructor, info)
if t.destructor != nil: if t.destructor != nil:
if t.destructor.ast[genericParamsPos].kind != nkEmpty: if t.destructor.ast[genericParamsPos].kind != nkEmpty:
internalError(c.graph.config, info, "resolved destructor is generic") internalError(g.config, info, "resolved destructor is generic")
if t.destructor.magic == mDestroy: if t.destructor.magic == mDestroy:
internalError(c.graph.config, info, "patching mDestroy with mDestroy?") internalError(g.config, info, "patching mDestroy with mDestroy?")
n.sons[0] = newSymNode(t.destructor) n.sons[0] = newSymNode(t.destructor)
for x in n: patchBody(c, x, info) for x in n: patchBody(g, c, x, info)
template inst(field, t) = template inst(field, t) =
if field.ast != nil and field.ast[genericParamsPos].kind != nkEmpty: if field.ast != nil and field.ast[genericParamsPos].kind != nkEmpty:
if t.typeInst != nil: if t.typeInst != nil:
field = c.instTypeBoundOp(c, field, t.typeInst, info, attachedAsgn, 1) var a: TLiftCtx
a.info = info
a.g = g
a.kind = k
a.c = c
field = instantiateGeneric(a, field, t, t.typeInst)
if field.ast != nil: if field.ast != nil:
patchBody(c, field.ast, info) patchBody(g, c, field.ast, info)
else: else:
localError(c.graph.config, info, "unresolved generic parameter") localError(g.config, info, "unresolved generic parameter")
proc isTrival(s: PSym): bool {.inline.} = s == nil or s.ast[bodyPos].len == 0 proc isTrival(s: PSym): bool {.inline.} = s == nil or s.ast[bodyPos].len == 0
proc createTypeBoundOps(c: PContext; orig: PType; info: TLineInfo) = proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo) =
## In the semantic pass this is called in strategic places ## In the semantic pass this is called in strategic places
## to ensure we lift assignment, destructors and moves properly. ## to ensure we lift assignment, destructors and moves properly.
## The later 'injectdestructors' pass depends on it. ## The later 'injectdestructors' pass depends on it.
@ -595,11 +606,11 @@ proc createTypeBoundOps(c: PContext; orig: PType; info: TLineInfo) =
incl orig.flags, tfCheckedForDestructor incl orig.flags, tfCheckedForDestructor
let h = sighashes.hashType(orig, {CoType, CoConsiderOwned, CoDistinct}) let h = sighashes.hashType(orig, {CoType, CoConsiderOwned, CoDistinct})
var canon = c.graph.canonTypes.getOrDefault(h) var canon = g.canonTypes.getOrDefault(h)
var overwrite = false var overwrite = false
if canon == nil: if canon == nil:
let typ = orig.skipTypes({tyGenericInst, tyAlias}) let typ = orig.skipTypes({tyGenericInst, tyAlias})
c.graph.canonTypes[h] = typ g.canonTypes[h] = typ
canon = typ canon = typ
elif canon != orig: elif canon != orig:
overwrite = true overwrite = true
@ -614,7 +625,7 @@ proc createTypeBoundOps(c: PContext; orig: PType; info: TLineInfo) =
# we generate the destructor first so that other operators can depend on it: # we generate the destructor first so that other operators can depend on it:
for k in attachedDestructor..attachedSink: for k in attachedDestructor..attachedSink:
if canon.attachedOps[k] == nil: if canon.attachedOps[k] == nil:
discard produceSym(c, canon, k, info) discard produceSym(g, c, canon, k, info)
else: else:
inst(canon.attachedOps[k], canon) inst(canon.attachedOps[k], canon)

View file

@ -709,7 +709,7 @@ proc track(tracked: PEffects, n: PNode) =
return return
if n.typ != nil: if n.typ != nil:
if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray: if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray:
createTypeBoundOps(tracked.c, n.typ, n.info) createTypeBoundOps(tracked.graph, tracked.c, n.typ, n.info)
if a.kind == nkCast and a[1].typ.kind == tyProc: if a.kind == nkCast and a[1].typ.kind == tyProc:
a = a[1] a = a[1]
# XXX: in rare situations, templates and macros will reach here after # XXX: in rare situations, templates and macros will reach here after
@ -770,18 +770,18 @@ proc track(tracked: PEffects, n: PNode) =
notNilCheck(tracked, n.sons[1], n.sons[0].typ) notNilCheck(tracked, n.sons[1], n.sons[0].typ)
when false: cstringCheck(tracked, n) when false: cstringCheck(tracked, n)
if tracked.owner.kind != skMacro: if tracked.owner.kind != skMacro:
createTypeBoundOps(tracked.c, n[0].typ, n.info) createTypeBoundOps(tracked.graph, tracked.c, n[0].typ, n.info)
of nkVarSection, nkLetSection: of nkVarSection, nkLetSection:
for child in n: for child in n:
let last = lastSon(child) let last = lastSon(child)
if last.kind != nkEmpty: track(tracked, last) if last.kind != nkEmpty: track(tracked, last)
if tracked.owner.kind != skMacro: if tracked.owner.kind != skMacro:
if child.kind == nkVarTuple: if child.kind == nkVarTuple:
createTypeBoundOps(tracked.c, child[^1].typ, child.info) createTypeBoundOps(tracked.graph, tracked.c, child[^1].typ, child.info)
for i in 0..child.len-3: for i in 0..child.len-3:
createTypeBoundOps(tracked.c, child[i].typ, child.info) createTypeBoundOps(tracked.graph, tracked.c, child[i].typ, child.info)
else: else:
createTypeBoundOps(tracked.c, child[0].typ, child.info) createTypeBoundOps(tracked.graph, tracked.c, child[0].typ, child.info)
if child.kind == nkIdentDefs and last.kind != nkEmpty: if child.kind == nkIdentDefs and last.kind != nkEmpty:
for i in 0 .. child.len-3: for i in 0 .. child.len-3:
initVar(tracked, child.sons[i], volatileCheck=false) initVar(tracked, child.sons[i], volatileCheck=false)
@ -827,15 +827,15 @@ proc track(tracked: PEffects, n: PNode) =
if tracked.owner.kind != skMacro: if tracked.owner.kind != skMacro:
if it.kind == nkVarTuple: if it.kind == nkVarTuple:
for x in it: for x in it:
createTypeBoundOps(tracked.c, x.typ, x.info) createTypeBoundOps(tracked.graph, tracked.c, x.typ, x.info)
else: else:
createTypeBoundOps(tracked.c, it.typ, it.info) createTypeBoundOps(tracked.graph, tracked.c, it.typ, it.info)
let iterCall = n[n.len-2] let iterCall = n[n.len-2]
let loopBody = n[n.len-1] let loopBody = n[n.len-1]
if tracked.owner.kind != skMacro and iterCall.safelen > 1: if tracked.owner.kind != skMacro and iterCall.safelen > 1:
# XXX this is a bit hacky: # XXX this is a bit hacky:
if iterCall[1].typ != nil and iterCall[1].typ.skipTypes(abstractVar).kind notin {tyVarargs, tyOpenArray}: if iterCall[1].typ != nil and iterCall[1].typ.skipTypes(abstractVar).kind notin {tyVarargs, tyOpenArray}:
createTypeBoundOps(tracked.c, iterCall[1].typ, iterCall[1].info) createTypeBoundOps(tracked.graph, tracked.c, iterCall[1].typ, iterCall[1].info)
track(tracked, iterCall) track(tracked, iterCall)
track(tracked, loopBody) track(tracked, loopBody)
setLen(tracked.init, oldState) setLen(tracked.init, oldState)