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

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

View File

@@ -12,7 +12,7 @@
import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs,
idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos,
transf
transf, liftdestructors
discard """
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))
else:
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;
d: DetectionPass; c: var LiftingPass): PNode =

View File

@@ -18,19 +18,19 @@ import modulegraphs, lineinfos, idents, ast, astalgo, renderer, semdata,
type
TLiftCtx = object
graph: ModuleGraph
g: ModuleGraph
info: TLineInfo # for construction
kind: TTypeAttachedOp
fn: PSym
asgnForType: PType
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 produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
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 =
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) =
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]))
proc dotField(x: PNode, f: PSym): PNode =
@@ -87,7 +87,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
of nkRecList:
for t in items(n): fillBodyObj(c, t, body, x, y)
else:
illFormedAstLocal(n, c.graph.config)
illFormedAstLocal(n, c.g.config)
proc genAddr(g: ModuleGraph; x: PNode): PNode =
if x.kind == nkHiddenDeref:
@@ -124,20 +124,28 @@ proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(op, y))
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)
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;
field: var PSym): bool =
if optNimV2 in c.graph.config.globalOptions:
if optNimV2 in c.g.config.globalOptions:
let op = field
if field != nil and sfOverriden in field.flags:
if sfError in op.flags:
incl c.fn.flags, sfError
#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)
body.add newAsgnCall(c.graph, op, x, y)
body.add newAsgnCall(c.g, op, x, y)
result = true
elif tfHasAsgn in t.flags:
var op: PSym
@@ -151,38 +159,37 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
else:
op = field
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:
incl c.fn.flags, sfError
#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)
# We also now do generic instantiations in the destructor lifting pass:
if op.ast[genericParamsPos].kind != nkEmpty:
assert t.typeInst != nil
op = c.c.instTypeBoundOp(c.c, op, t.typeInst, c.info, attachedAsgn, 1)
op = instantiateGeneric(c, op, t, t.typeInst)
field = op
#echo "trying to use ", op.ast
#echo "for ", op.name.s, " "
#debug(t)
#return false
assert op.ast[genericParamsPos].kind == nkEmpty
body.add newAsgnCall(c.graph, op, x, y)
body.add newAsgnCall(c.g, op, x, y)
result = true
proc addDestructorCall(c: var TLiftCtx; t: PType; body, x: PNode) =
var op = t.destructor
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 == t.destructor
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)
body.add destructorCall(c.graph, op, x)
body.add destructorCall(c.g, op, x)
elif useNoGc(c, t):
internalError(c.graph.config, c.info,
internalError(c.g.config, c.info,
"type-bound operator could not be resolved")
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.ast[genericParamsPos].kind != nkEmpty:
assert t.typeInst != nil
# 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
#markUsed(c.graph.config, c.info, op, c.graph.usageSym)
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
body.add destructorCall(c.graph, op, x)
body.add destructorCall(c.g, op, x)
result = true
#result = addDestructorCall(c, t, body, x)
of attachedAsgn:
@@ -209,7 +215,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
of attachedDeepCopy:
let op = t.attachedOps[attachedDeepCopy]
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)
body.add newDeepCopyCall(op, x, y)
result = true
@@ -226,13 +232,13 @@ proc addVar(father, v, value: PNode) =
addSon(father, vpart)
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(c.graph.cache, lowerings.genPrefix), c.fn, c.info)
temp.typ = getSysType(c.graph, body.info, tyInt)
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.fn, c.info)
temp.typ = getSysType(c.g, body.info, tyInt)
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, c.info)
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
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 =
result = newNodeI(nkWhileStmt, c.info, 2)
let cmp = genBuiltin(c.graph, mLtI, "<", i)
cmp.add genLen(c.graph, dest)
cmp.typ = getSysType(c.graph, c.info, tyBool)
let cmp = genBuiltin(c.g, mLtI, "<", i)
cmp.add genLen(c.g, dest)
cmp.typ = getSysType(c.g, c.info, tyBool)
result.sons[0] = cmp
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))
proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
let incCall = genBuiltin(c.graph, mInc, "inc", i)
incCall.add lowerings.newIntLit(c.graph, c.info, 1)
let incCall = genBuiltin(c.g, mInc, "inc", i)
incCall.add lowerings.newIntLit(c.g, c.info, 1)
body.add incCall
proc newSeqCall(g: ModuleGraph; x, y: PNode): PNode =
@@ -270,14 +276,14 @@ proc setLenStrCall(g: ModuleGraph; x, y: PNode): PNode =
result.add lenCall
proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode =
let lenCall = genBuiltin(c.graph, mLengthSeq, "len", y)
lenCall.typ = getSysType(c.graph, x.info, tyInt)
var op = getSysMagic(c.graph, x.info, "setLen", mSetLengthSeq)
op = c.c.instTypeBoundOp(c.c, op, t, c.info, attachedAsgn, 1)
let lenCall = genBuiltin(c.g, mLengthSeq, "len", y)
lenCall.typ = getSysType(c.g, x.info, tyInt)
var op = getSysMagic(c.g, x.info, "setLen", mSetLengthSeq)
op = instantiateGeneric(c, op, t, t)
result = newTree(nkCall, newSymNode(op, x.info), x, lenCall)
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 elemType = t.lastSon
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)
forallElements(c, t, body, x, y)
of attachedSink:
let moveCall = genBuiltin(c.graph, mMove, "move", x)
let moveCall = genBuiltin(c.g, mMove, "move", x)
moveCall.add y
doAssert t.destructor != nil
moveCall.add destructorCall(c.graph, t.destructor, x)
moveCall.add destructorCall(c.g, t.destructor, x)
body.add moveCall
of attachedDestructor:
# destroy all elements:
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) =
createTypeBoundOps(c.c, t, body.info)
createTypeBoundOps(c.g, c.c, t, body.info)
case c.kind
of attachedAsgn, attachedDeepCopy:
doAssert t.assignment != nil
body.add newAsgnCall(c.graph, t.assignment, x, y)
body.add newAsgnCall(c.g, t.assignment, x, y)
of attachedSink:
# 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
doAssert t.destructor != nil
moveCall.add destructorCall(c.graph, t.destructor, x)
moveCall.add destructorCall(c.g, t.destructor, x)
body.add moveCall
# alternatively we could do this:
when false:
doAssert t.asink != nil
body.add newAsgnCall(c.graph, t.asink, x, y)
body.add newAsgnCall(c.g, t.asink, x, y)
of attachedDestructor:
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) =
case c.kind
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:
let moveCall = genBuiltin(c.graph, mMove, "move", x)
let moveCall = genBuiltin(c.g, mMove, "move", x)
moveCall.add y
doAssert t.destructor != nil
moveCall.add destructorCall(c.graph, t.destructor, x)
moveCall.add destructorCall(c.g, t.destructor, x)
body.add moveCall
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) =
case c.kind
of attachedSink:
# we 'nil' y out afterwards so we *need* to take over its reference
# 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)
of attachedAsgn:
body.add genIf(c, y, callCodegenProc(c.graph, "nimIncWeakRef", c.info, y))
body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x))
body.add genIf(c, y, callCodegenProc(c.g, "nimIncWeakRef", c.info, y))
body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
body.add newAsgnStmt(x, y)
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")
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
#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):
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:
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
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:
let call = newNodeI(nkCall, c.info, 2)
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
body.add newAsgnStmt(x, call)
elif optNimV2 in c.graph.config.globalOptions:
let xx = genBuiltin(c.graph, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.graph, c.info, tyPointer)
elif optNimV2 in c.g.config.globalOptions:
let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.g, c.info, tyPointer)
case c.kind
of attachedSink:
# we 'nil' y out afterwards so we *need* to take over its reference
# 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)
of attachedAsgn:
let yy = genBuiltin(c.graph, mAccessEnv, "accessEnv", y)
yy.typ = getSysType(c.graph, c.info, tyPointer)
body.add genIf(c, yy, callCodegenProc(c.graph, "nimIncWeakRef", c.info, yy))
body.add genIf(c, xx, callCodegenProc(c.graph, "nimDecWeakRef", c.info, xx))
let yy = genBuiltin(c.g, mAccessEnv, "accessEnv", y)
yy.typ = getSysType(c.g, c.info, tyPointer)
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncWeakRef", c.info, yy))
body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
body.add newAsgnStmt(x, y)
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")
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c.graph, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.graph, c.info, tyPointer)
let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.g, c.info, tyPointer)
var actions = newNodeI(nkStmtList, c.info)
let elemType = t.lastSon
#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
of attachedSink, attachedAsgn:
body.add genIf(c, xx, actions)
@@ -427,7 +433,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
tyPtr, tyOpt, tyUncheckedArray:
defaultOp(c, t, body, x, y)
of tyRef:
if optNimV2 in c.graph.config.globalOptions:
if optNimV2 in c.g.config.globalOptions:
weakrefOp(c, t, body, x, y)
else:
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)
of tyOwned:
let base = t.skipTypes(abstractInstOwned)
if optNimV2 in c.graph.config.globalOptions:
if optNimV2 in c.g.config.globalOptions:
case base.kind
of tyRef:
ownedRefOp(c, base, body, x, y)
@@ -457,13 +463,13 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of tySequence:
if useNoGc(c, t):
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
# 'selectedGC' here to determine if we have the new runtime.
discard considerUserDefinedOp(c, t, body, x, y)
elif tfHasAsgn in t.flags:
if c.kind != attachedDestructor:
body.add newSeqCall(c.graph, x, y)
body.add newSeqCall(c.g, x, y)
forallElements(c, t, body, x, y)
else:
defaultOp(c, t, body, x, y)
@@ -483,12 +489,12 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of tyTuple:
fillBodyTup(c, t, body, x, y)
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,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
tyGenericParam, tyGenericBody, tyNil, tyUntyped, tyTyped,
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
of tyVar, tyLent:
if c.kind != attachedDestructor:
@@ -497,25 +503,24 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
tyGenericInst, tyStatic, tyAlias, tySink:
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
let baseType = typ[0]
if baseType.attachedOps[kind] == nil:
discard produceSym(c, baseType, kind, info)
discard produceSym(g, c, baseType, kind, info)
typ.attachedOps[kind] = baseType.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 =
if typ.kind == tyDistinct:
return produceSymDistinctType(c, typ, kind, info)
return produceSymDistinctType(g, c, typ, kind, info)
var a: TLiftCtx
a.info = info
a.graph = c.graph
a.g = g
a.kind = kind
a.c = c
let g = c.graph
let body = newNodeI(nkStmtList, info)
let procname = getIdent(g.cache, AttachedOpToStr[kind])
@@ -537,7 +542,7 @@ proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
typ.attachedOps[kind] = result
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
else:
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) =
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[0].kind == nkSym and n[0].sym.magic == mDestroy:
let t = n[1].typ.skipTypes(abstractVar)
if t.destructor == nil:
discard produceSym(c, t, attachedDestructor, info)
discard produceSym(g, c, t, attachedDestructor, info)
if t.destructor != nil:
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:
internalError(c.graph.config, info, "patching mDestroy with mDestroy?")
internalError(g.config, info, "patching mDestroy with mDestroy?")
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) =
if field.ast != nil and field.ast[genericParamsPos].kind != nkEmpty:
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:
patchBody(c, field.ast, info)
patchBody(g, c, field.ast, info)
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 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
## to ensure we lift assignment, destructors and moves properly.
## The later 'injectdestructors' pass depends on it.
@@ -595,11 +606,11 @@ proc createTypeBoundOps(c: PContext; orig: PType; info: TLineInfo) =
incl orig.flags, tfCheckedForDestructor
let h = sighashes.hashType(orig, {CoType, CoConsiderOwned, CoDistinct})
var canon = c.graph.canonTypes.getOrDefault(h)
var canon = g.canonTypes.getOrDefault(h)
var overwrite = false
if canon == nil:
let typ = orig.skipTypes({tyGenericInst, tyAlias})
c.graph.canonTypes[h] = typ
g.canonTypes[h] = typ
canon = typ
elif canon != orig:
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:
for k in attachedDestructor..attachedSink:
if canon.attachedOps[k] == nil:
discard produceSym(c, canon, k, info)
discard produceSym(g, c, canon, k, info)
else:
inst(canon.attachedOps[k], canon)

View File

@@ -709,7 +709,7 @@ proc track(tracked: PEffects, n: PNode) =
return
if n.typ != nil:
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:
a = a[1]
# 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)
when false: cstringCheck(tracked, n)
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:
for child in n:
let last = lastSon(child)
if last.kind != nkEmpty: track(tracked, last)
if tracked.owner.kind != skMacro:
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:
createTypeBoundOps(tracked.c, child[i].typ, child.info)
createTypeBoundOps(tracked.graph, tracked.c, child[i].typ, child.info)
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:
for i in 0 .. child.len-3:
initVar(tracked, child.sons[i], volatileCheck=false)
@@ -827,15 +827,15 @@ proc track(tracked: PEffects, n: PNode) =
if tracked.owner.kind != skMacro:
if it.kind == nkVarTuple:
for x in it:
createTypeBoundOps(tracked.c, x.typ, x.info)
createTypeBoundOps(tracked.graph, tracked.c, x.typ, x.info)
else:
createTypeBoundOps(tracked.c, it.typ, it.info)
createTypeBoundOps(tracked.graph, tracked.c, it.typ, it.info)
let iterCall = n[n.len-2]
let loopBody = n[n.len-1]
if tracked.owner.kind != skMacro and iterCall.safelen > 1:
# XXX this is a bit hacky:
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, loopBody)
setLen(tracked.init, oldState)