summary refs log tree commit diff stats
path: root/compiler/destroyer.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/destroyer.nim')
-rw-r--r--compiler/destroyer.nim63
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