diff options
Diffstat (limited to 'compiler/destroyer.nim')
-rw-r--r-- | compiler/destroyer.nim | 63 |
1 files changed, 48 insertions, 15 deletions
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index afa2e5e50..0fdeceba0 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -93,9 +93,7 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, - strutils, options, dfa, lowerings - -template hasDestructor(t: PType): bool = tfHasAsgn in t.flags + strutils, options, dfa, lowerings, rodread const InterestingSyms = {skVar, skResult, skLet} @@ -166,18 +164,50 @@ proc isHarmlessVar*(s: PSym; c: Con): bool = template interestingSym(s: PSym): bool = s.owner == c.owner and s.kind in InterestingSyms and hasDestructor(s.typ) -proc genSink(t: PType; dest: PNode): PNode = - let op = if t.sink != nil: t.sink else: t.assignment - assert op != nil +proc patchHead(n: PNode) = + if n.kind in nkCallKinds and n[0].kind == nkSym and n.len > 1: + let s = n[0].sym + if s.name.s[0] == '=' and s.name.s in ["=sink", "=", "=destroy"]: + if sfFromGeneric in s.flags: + excl(s.flags, sfFromGeneric) + patchHead(s.getBody) + if n[1].typ.isNil: + # XXX toptree crashes without this workaround. Figure out why. + return + let t = n[1].typ.skipTypes({tyVar, tyGenericInst, tyAlias, tyInferred}) + template patch(op, field) = + if s.name.s == op and field != nil and field != s: + n.sons[0].sym = field + patch "=sink", t.sink + patch "=", t.assignment + patch "=destroy", t.destructor + for x in n: + patchHead(x) + +proc patchHead(s: PSym) = + if sfFromGeneric in s.flags: + patchHead(s.ast[bodyPos]) + +template genOp(opr, opname) = + let op = opr + if op == nil: + globalError(dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t)) + elif op.ast[genericParamsPos].kind != nkEmpty: + globalError(dest.info, "internal error: '" & opname & "' operator is generic") + patchHead op result = newTree(nkCall, newSymNode(op), newTree(nkHiddenAddr, dest)) +proc genSink(t: PType; dest: PNode): PNode = + let t = t.skipTypes({tyGenericInst, tyAlias}) + genOp(if t.sink != nil: t.sink else: t.assignment, "=sink") + proc genCopy(t: PType; dest: PNode): PNode = - assert t.assignment != nil - result = newTree(nkCall, newSymNode(t.assignment), newTree(nkHiddenAddr, dest)) + let t = t.skipTypes({tyGenericInst, tyAlias}) + genOp(t.assignment, "=") proc genDestroy(t: PType; dest: PNode): PNode = - assert t.destructor != nil - result = newTree(nkCall, newSymNode(t.destructor), newTree(nkHiddenAddr, dest)) + let t = t.skipTypes({tyGenericInst, tyAlias}) + genOp(t.destructor, "=destroy") proc addTopVar(c: var Con; v: PNode) = c.topLevelVars.add newTree(nkIdentDefs, v, emptyNode, emptyNode) @@ -189,7 +219,7 @@ template recurse(n, dest) = dest.add p(n[i], c) proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = - if ri.kind in nkCallKinds: + if ri.kind in nkCallKinds+{nkObjConstr}: result = genSink(ri.typ, dest) # watch out and no not transform 'ri' twice if it's a call: let ri2 = copyNode(ri) @@ -253,7 +283,7 @@ proc p(n: PNode; c: var Con): PNode = result = copyNode(n) recurse(n, result) of nkAsgn, nkFastAsgn: - if n[0].kind == nkSym and interestingSym(n[0].sym): + if hasDestructor(n[0].typ): result = moveOrCopy(n[0], n[1], c) else: result = copyNode(n) @@ -266,6 +296,8 @@ proc p(n: PNode; c: var Con): PNode = recurse(n, result) proc injectDestructorCalls*(owner: PSym; n: PNode): PNode = + when defined(nimDebugDestroys): + echo "injecting into ", n var c: Con c.owner = owner c.tmp = newSym(skTemp, getIdent":d", owner, n.info) @@ -291,6 +323,7 @@ proc injectDestructorCalls*(owner: PSym; n: PNode): PNode = result.add body when defined(nimDebugDestroys): - echo "------------------------------------" - echo owner.name.s, " transformed to: " - echo result + if owner.name.s == "main" or true: + echo "------------------------------------" + echo owner.name.s, " transformed to: " + echo result |