summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2019-04-18 00:53:02 +0200
committerAraq <rumpf_a@web.de>2019-04-18 00:53:02 +0200
commit750f50b6c04e275207ec5d1aace478369e1acf9e (patch)
tree3b429bf844f776513adf1d48dceab1ac21f27d69 /compiler
parentfb3681b42543639e67a5b1d8dd60412e354b7a46 (diff)
downloadNim-750f50b6c04e275207ec5d1aace478369e1acf9e.tar.gz
destructors: internal compiler refactoring
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim24
-rw-r--r--compiler/ccgtypes.nim8
-rw-r--r--compiler/injectdestructors.nim34
-rw-r--r--compiler/liftdestructors.nim69
-rw-r--r--compiler/semdata.nim6
-rw-r--r--compiler/semstmts.nim14
-rw-r--r--compiler/semtypinst.nim25
7 files changed, 77 insertions, 103 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 75e67ac67..c98b2a576 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -877,6 +877,13 @@ type
 
   TTypeSeq* = seq[PType]
   TLockLevel* = distinct int16
+
+  TTypeAttachedOp* = enum ## as usual, order is important here
+    attachedDestructor,
+    attachedAsgn,
+    attachedSink,
+    attachedDeepCopy
+
   TType* {.acyclic.} = object of TIdObj # \
                               # types are identical iff they have the
                               # same id; there may be multiple copies of a type
@@ -897,12 +904,7 @@ type
     owner*: PSym              # the 'owner' of the type
     sym*: PSym                # types have the sym associated with them
                               # it is used for converting types to strings
-    destructor*: PSym         # destructor. warning: nil here may not necessary
-                              # mean that there is no destructor.
-                              # see instantiateDestructor in semdestruct.nim
-    deepCopy*: PSym           # overriden 'deepCopy' operation
-    assignment*: PSym         # overriden '=' operation
-    sink*: PSym               # overriden '=sink' operation
+    attachedOps*: array[TTypeAttachedOp, PSym] # destructors, etc.
     methods*: seq[(int,PSym)] # attached methods
     size*: BiggestInt         # the size of the type in bytes
                               # -1 means that the size is unkwown
@@ -1275,6 +1277,7 @@ const
   UnspecifiedLockLevel* = TLockLevel(-1'i16)
   MaxLockLevel* = 1000'i16
   UnknownLockLevel* = TLockLevel(1001'i16)
+  AttachedOpToStr*: array[TTypeAttachedOp, string] = ["=destroy", "=", "=sink", "=deepcopy"]
 
 proc `$`*(x: TLockLevel): string =
   if x.ord == UnspecifiedLockLevel.ord: result = "<unspecified>"
@@ -1341,10 +1344,7 @@ proc assignType*(dest, src: PType) =
   dest.n = src.n
   dest.size = src.size
   dest.align = src.align
-  dest.destructor = src.destructor
-  dest.deepCopy = src.deepCopy
-  dest.sink = src.sink
-  dest.assignment = src.assignment
+  dest.attachedOps = src.attachedOps
   dest.lockLevel = src.lockLevel
   # this fixes 'type TLock = TSysLock':
   if src.sym != nil:
@@ -1831,3 +1831,7 @@ proc addParam*(procType: PType; param: PSym) =
   param.position = procType.len-1
   addSon(procType.n, newSymNode(param))
   rawAddSon(procType, param.typ)
+
+template destructor*(t: PType): PSym = t.attachedOps[attachedDestructor]
+template assignment*(t: PType): PSym = t.attachedOps[attachedAsgn]
+template asink*(t: PType): PSym = t.attachedOps[attachedSink]
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index fb0f7dbf4..7d5a761bc 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -1346,10 +1346,10 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
     # results are not deterministic!
     genTupleInfo(m, t, origType, result, info)
   else: internalError(m.config, "genTypeInfo(" & $t.kind & ')')
-  if t.deepCopy != nil:
-    genDeepCopyProc(m, t.deepCopy, result)
-  elif origType.deepCopy != nil:
-    genDeepCopyProc(m, origType.deepCopy, result)
+  if t.attachedOps[attachedDeepCopy] != nil:
+    genDeepCopyProc(m, t.attachedOps[attachedDeepCopy], result)
+  elif origType.attachedOps[attachedDeepCopy] != nil:
+    genDeepCopyProc(m, origType.attachedOps[attachedDeepCopy], result)
   result = prefixTI.rope & result & ")".rope
 
 proc genTypeSection(m: BModule, n: PNode) =
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index 7901ed4dc..1f225aee4 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -136,7 +136,7 @@ to do it.
 import
   intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
   strutils, options, dfa, lowerings, tables, modulegraphs, msgs,
-  lineinfos, parampatterns
+  lineinfos, parampatterns, sighashes
 
 const
   InterestingSyms = {skVar, skResult, skLet, skForVar, skTemp}
@@ -314,24 +314,34 @@ proc makePtrType(c: Con, baseType: PType): PType =
   result = newType(tyPtr, c.owner)
   addSonSkipIntLit(result, baseType)
 
-template genOp(opr, opname, ri) =
-  let op = opr
+proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
+  var op = t.attachedOps[kind]
+
+  when false:
+    if op == nil:
+      # give up and find the canonical type instead:
+      let h = sighashes.hashType(t, {CoType, CoConsiderOwned})
+      let canon = c.graph.canonTypes.getOrDefault(h)
+      if canon != nil:
+        op = canon.attachedOps[kind]
+
   if op == nil:
-    globalError(c.graph.config, dest.info, "internal error: '" & opname &
+    globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] &
       "' operator not found for type " & typeToString(t))
   elif op.ast[genericParamsPos].kind != nkEmpty:
-    globalError(c.graph.config, dest.info, "internal error: '" & opname &
+    globalError(c.graph.config, dest.info, "internal error: '" & AttachedOpToStr[kind] &
       "' operator is generic")
-  if sfError in op.flags: checkForErrorPragma(c, t, ri, opname)
+  if sfError in op.flags: checkForErrorPragma(c, t, ri, AttachedOpToStr[kind])
   let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
   addrExp.add(dest)
   result = newTree(nkCall, newSymNode(op), addrExp)
 
 proc genSink(c: Con; t: PType; dest, ri: PNode): PNode =
   let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
-  let op = if t.sink != nil: t.sink else: t.assignment
-  if op != nil:
-    genOp(op, "=sink", ri)
+  let k = if t.attachedOps[attachedSink] != nil: attachedSink
+           else: attachedAsgn
+  if t.attachedOps[k] != nil:
+    result = genOp(c, t, k, dest, ri)
   else:
     # in rare cases only =destroy exists but no sink or assignment
     # (see Pony object in tmove_objconstr.nim)
@@ -342,15 +352,15 @@ proc genCopy(c: Con; t: PType; dest, ri: PNode): PNode =
   if tfHasOwned in t.flags:
     checkForErrorPragma(c, t, ri, "=")
   let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
-  genOp(t.assignment, "=", ri)
+  result = genOp(c, t, attachedAsgn, dest, ri)
 
 proc genCopyNoCheck(c: Con; t: PType; dest, ri: PNode): PNode =
   let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
-  genOp(t.assignment, "=", ri)
+  result = genOp(c, t, attachedAsgn, dest, ri)
 
 proc genDestroy(c: Con; t: PType; dest: PNode): PNode =
   let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
-  genOp(t.destructor, "=destroy", nil)
+  result = genOp(c, t, attachedDestructor, dest, nil)
 
 proc addTopVar(c: var Con; v: PNode) =
   c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode)
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim
index 310263875..5fbf86071 100644
--- a/compiler/liftdestructors.nim
+++ b/compiler/liftdestructors.nim
@@ -197,7 +197,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
         assert t.typeInst != nil
         # patch generic destructor:
         op = c.c.instTypeBoundOp(c.c, op, t.typeInst, c.info, attachedAsgn, 1)
-        t.destructor = op
+        t.attachedOps[attachedDestructor] = op
 
       markUsed(c.graph.config, c.info, op, c.graph.usageSym)
       onUse(c.info, op)
@@ -207,9 +207,9 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
   of attachedAsgn:
     result = considerAsgnOrSink(c, t, body, x, y, t.assignment)
   of attachedSink:
-    result = considerAsgnOrSink(c, t, body, x, y, t.sink)
+    result = considerAsgnOrSink(c, t, body, x, y, t.asink)
   of attachedDeepCopy:
-    let op = t.deepCopy
+    let op = t.attachedOps[attachedDeepCopy]
     if op != nil:
       markUsed(c.graph.config, c.info, op, c.graph.usageSym)
       onUse(c.info, op)
@@ -323,8 +323,8 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
     body.add moveCall
     # alternatively we could do this:
     when false:
-      doAssert t.sink != nil
-      body.add newAsgnCall(c.graph, t.sink, x, y)
+      doAssert t.asink != nil
+      body.add newAsgnCall(c.graph, t.asink, x, y)
   of attachedDestructor:
     doAssert t.destructor != nil
     body.add destructorCall(c.graph, t.destructor, x)
@@ -502,27 +502,10 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
 proc produceSymDistinctType(c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym =
   assert typ.kind == tyDistinct
   let baseType = typ[0]
-  case kind
-  of attachedAsgn:
-    if baseType.assignment == nil:
-      discard produceSym(c, baseType, kind, info)
-    typ.assignment = baseType.assignment
-    result = typ.assignment
-  of attachedSink:
-    if baseType.sink == nil:
-      discard produceSym(c, baseType, kind, info)
-    typ.sink = baseType.sink
-    result = typ.sink
-  of attachedDeepCopy:
-    if baseType.deepCopy == nil:
-      discard produceSym(c, baseType, kind, info)
-    typ.deepCopy = baseType.deepCopy
-    result = typ.deepCopy
-  of attachedDestructor:
-    if baseType.destructor == nil:
-      discard produceSym(c, baseType, kind, info)
-    typ.destructor = baseType.destructor
-    result = typ.destructor
+  if baseType.attachedOps[kind] == nil:
+    discard produceSym(c, baseType, kind, info)
+  typ.attachedOps[kind] = baseType.attachedOps[kind]
+  result = typ.attachedOps[kind]
 
 proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
               info: TLineInfo): PSym =
@@ -536,11 +519,7 @@ proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
   a.c = c
   let g = c.graph
   let body = newNodeI(nkStmtList, info)
-  let procname = case kind
-                 of attachedAsgn: getIdent(g.cache, "=")
-                 of attachedSink: getIdent(g.cache, "=sink")
-                 of attachedDeepCopy: getIdent(g.cache, "=deepcopy")
-                 of attachedDestructor: getIdent(g.cache, "=destroy")
+  let procname = getIdent(g.cache, AttachedOpToStr[kind])
 
   result = newSym(skProc, procname, typ.owner, info)
   a.fn = result
@@ -557,11 +536,7 @@ proc produceSym(c: PContext; typ: PType; kind: TTypeAttachedOp;
     result.typ.addParam src
 
   # register this operation already:
-  case kind
-  of attachedAsgn: typ.assignment = result
-  of attachedSink: typ.sink = result
-  of attachedDeepCopy: typ.deepCopy = result
-  of attachedDestructor: typ.destructor = result
+  typ.attachedOps[kind] = result
 
   var tk: TTypeKind
   if optNimV2 in c.graph.config.globalOptions:
@@ -636,23 +611,15 @@ proc createTypeBoundOps(c: PContext; orig: PType; info: TLineInfo) =
   # 5. We have a (custom) generic destructor.
   let typ = canon.skipTypes({tyGenericInst, tyAlias})
   # we generate the destructor first so that other operators can depend on it:
-  if typ.destructor == nil:
-    discard produceSym(c, typ, attachedDestructor, info)
-  else:
-    inst(typ.destructor, typ)
-  if typ.assignment == nil:
-    discard produceSym(c, typ, attachedAsgn, info)
-  else:
-    inst(typ.assignment, typ)
-  if typ.sink == nil:
-    discard produceSym(c, typ, attachedSink, info)
-  else:
-    inst(typ.sink, typ)
+  for k in attachedDestructor..attachedSink:
+    if typ.attachedOps[k] == nil:
+      discard produceSym(c, typ, k, info)
+    else:
+      inst(typ.attachedOps[k], typ)
 
   if overwrite:
-    orig.destructor = typ.destructor
-    orig.assignment = typ.assignment
-    orig.sink = typ.sink
+    for k in attachedDestructor..attachedSink:
+      orig.attachedOps[k] = typ.attachedOps[k]
 
   if not isTrival(orig.destructor):
     #or not isTrival(orig.assignment) or
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index f7a7f20dc..4b269dd4a 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -72,12 +72,6 @@ type
 
   TExprFlags* = set[TExprFlag]
 
-  TTypeAttachedOp* = enum
-    attachedAsgn,
-    attachedSink,
-    attachedDeepCopy,
-    attachedDestructor
-
   PContext* = ref TContext
   TContext* = object of TPassContext # a context represents a module
     enforceVoidContext*: PType
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 067b3bc9c..4054fd71a 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1568,7 +1568,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
       if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
         obj = canonType(c, obj)
         if obj.destructor.isNil:
-          obj.destructor = s
+          obj.attachedOps[attachedDestructor] = s
         else:
           prevDestructor(c, obj.destructor, obj, n.info)
         noError = true
@@ -1592,7 +1592,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
         elif t.kind == tyGenericInvocation: t = t.sons[0]
         else: break
       if t.kind in {tyObject, tyDistinct, tyEnum, tySequence, tyString}:
-        if t.deepCopy.isNil: t.deepCopy = s
+        if t.attachedOps[attachedDeepCopy].isNil: t.attachedOps[attachedDeepCopy] = s
         else:
           localError(c.config, n.info, errGenerated,
                      "cannot bind another 'deepCopy' to: " & typeToString(t))
@@ -1631,11 +1631,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
         # attach these ops to the canonical tySequence
         obj = canonType(c, obj)
         #echo "ATTACHING TO ", obj.id, " ", s.name.s, " ", cast[int](obj)
-        let opr = if s.name.s == "=": addr(obj.assignment) else: addr(obj.sink)
-        if opr[].isNil:
-          opr[] = s
+        let k = if name == "=": attachedAsgn else: attachedSink
+        if obj.attachedOps[k].isNil:
+          obj.attachedOps[k] = s
         else:
-          prevDestructor(c, opr[], obj, n.info)
+          prevDestructor(c, obj.attachedOps[k], obj, n.info)
         if obj.owner.getModule != s.getModule:
           localError(c.config, n.info, errGenerated,
             "type bound operation `" & name & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
@@ -1828,7 +1828,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
 
   if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
   if s.name.s[0] in {'.', '('}:
-    if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}:
+    if s.name.s in [".", ".()", ".="] and {Feature.destructor, dotOperators} * c.features == {}:
       localError(c.config, n.info, "the overloaded " & s.name.s &
         " operator has to be enabled with {.experimental: \"dotOperators\".}")
     elif s.name.s == "()" and callOperator notin c.features:
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 931a54f96..5d2c4203c 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -380,13 +380,13 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
   if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
   rawAddSon(result, newbody)
   checkPartialConstructedType(cl.c.config, cl.info, newbody)
-  let dc = newbody.deepCopy
+  let dc = newbody.attachedOps[attachedDeepCopy]
   if not cl.allowMetaTypes:
-    if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
+    if dc != nil and sfFromGeneric notin newbody.attachedOps[attachedDeepCopy].flags:
       # 'deepCopy' needs to be instantiated for
       # generics *when the type is constructed*:
-      newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
-                                              attachedDeepCopy, 1)
+      newbody.attachedOps[attachedDeepCopy] = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
+                                                                   attachedDeepCopy, 1)
     if bodyIsNew and newbody.typeInst == nil:
       #doassert newbody.typeInst == nil
       newbody.typeInst = result
@@ -592,7 +592,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
         skipIntLiteralParams(result)
 
       of tySequence:
-        if cl.isReturnType and cl.c.config.selectedGc == gcDestructors and result.destructor.isNil and
+        if cl.isReturnType and cl.c.config.selectedGc == gcDestructors and
+            result.attachedOps[attachedDestructor].isNil and
             result[0].kind != tyEmpty and optNimV2 notin cl.c.config.globalOptions:
           let s = cl.c.graph.sysTypes[tySequence]
           var old = copyType(s, s.owner, keepId=false)
@@ -601,9 +602,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
           old.n = nil
           old.flags = {tfHasAsgn}
           old.addSonSkipIntLit result[0]
-          result.destructor = old.destructor
-          result.assignment = old.assignment
-          result.sink = old.sink
+          result.attachedOps = old.attachedOps
           cl.c.typesWithOps.add((result, old))
 
       else: discard
@@ -619,19 +618,19 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
         result.n = replaceObjBranches(cl, result.n)
 
 template typeBound(c, newty, oldty, field, info) =
-  let opr = newty.field
+  let opr = newty.attachedOps[field]
   if opr != nil and sfFromGeneric notin opr.flags:
     # '=' needs to be instantiated for generics when the type is constructed:
     #echo "DESTROY: instantiating ", astToStr(field), " for ", typeToString(oldty)
-    newty.field = c.instTypeBoundOp(c, opr, oldty, info, attachedAsgn, 1)
+    newty.attachedOps[field] = c.instTypeBoundOp(c, opr, oldty, info, attachedAsgn, 1)
 
 proc instAllTypeBoundOp*(c: PContext, info: TLineInfo) =
   var i = 0
   while i < c.typesWithOps.len:
     let (newty, oldty) = c.typesWithOps[i]
-    typeBound(c, newty, oldty, destructor, info)
-    typeBound(c, newty, oldty, sink, info)
-    typeBound(c, newty, oldty, assignment, info)
+    typeBound(c, newty, oldty, attachedDestructor, info)
+    typeBound(c, newty, oldty, attachedSink, info)
+    typeBound(c, newty, oldty, attachedAsgn, info)
     inc i
   setLen(c.typesWithOps, 0)