summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2019-03-05 17:29:48 +0100
committerAndreas Rumpf <rumpf_a@web.de>2019-03-05 19:58:54 +0100
commit4be36d77f6b5d9c32a5f35919dfbb825e9551b0e (patch)
tree1a3ae91b141cd23d9631de62e088239d2a993176
parent20a21aa1848726a60493432b7337ecbfd491f7ac (diff)
downloadNim-4be36d77f6b5d9c32a5f35919dfbb825e9551b0e.tar.gz
introduce tfHasOwned for fast must-move checkings; removed tfAcyclic as the GC has ignored this hint for quite some time now
-rw-r--r--compiler/ast.nim9
-rw-r--r--compiler/cgen.nim5
-rw-r--r--compiler/dfa.nim2
-rw-r--r--compiler/pragmas.nim2
-rw-r--r--compiler/semtypes.nim4
-rw-r--r--compiler/semtypinst.nim6
-rw-r--r--compiler/transf.nim3
-rw-r--r--compiler/types.nim25
-rw-r--r--doc/manual.rst37
9 files changed, 30 insertions, 63 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index b325e6d42..9ce102c2f 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -479,7 +479,7 @@ type
     tfNoSideEffect,   # procedure type does not allow side effects
     tfFinal,          # is the object final?
     tfInheritable,    # is the object inheritable?
-    tfAcyclic,        # type is acyclic (for GC optimization)
+    tfHasOwned,       # type contains an 'owned' type and must be moved
     tfEnumHasHoles,   # enum cannot be mapped into a range
     tfShallow,        # type can be shallow copied on assignment
     tfThread,         # proc type is marked as ``thread``; alias for ``gcsafe``
@@ -1472,6 +1472,13 @@ proc propagateToOwner*(owner, elem: PType) =
       o2.flags.incl tfHasAsgn
       owner.flags.incl tfHasAsgn
 
+  if tfHasOwned in elem.flags:
+    let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink})
+    if o2.kind in {tyTuple, tyObject, tyArray,
+                   tySequence, tyOpt, tySet, tyDistinct}:
+      o2.flags.incl tfHasOwned
+      owner.flags.incl tfHasOwned
+
   if owner.kind notin {tyProc, tyGenericInst, tyGenericBody,
                        tyGenericInvocation, tyPtr}:
     let elemB = elem.skipTypes({tyGenericInst, tyAlias, tySink})
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 45daa00d9..09076c520 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -42,8 +42,6 @@ when not declared(dynlib.libCandidates):
 when options.hasTinyCBackend:
   import tccgen
 
-# implementation
-
 proc hcrOn(m: BModule): bool = m.config.hcrOn
 proc hcrOn(p: BProc): bool = p.module.config.hcrOn
 
@@ -295,6 +293,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
     includeHeader(p.module, "<new>")
     linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t))
 
+  if optNimV2 in p.config.globalOptions: return
   case analyseObjectWithTypeField(t)
   of frNone:
     discard
@@ -303,7 +302,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
     if not takeAddr: r = "(*$1)" % [r]
     var s = skipTypes(t, abstractInst)
     if not p.module.compileToCpp:
-      while (s.kind == tyObject) and (s.sons[0] != nil):
+      while s.kind == tyObject and s.sons[0] != nil:
         add(r, ".Sup")
         s = skipTypes(s.sons[0], skipPtrs)
     linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t, a.lode.info))
diff --git a/compiler/dfa.nim b/compiler/dfa.nim
index 968b16945..cecb8394c 100644
--- a/compiler/dfa.nim
+++ b/compiler/dfa.nim
@@ -596,7 +596,7 @@ proc genCall(c: var Con; n: PNode) =
     gen(c, n[i])
     when false:
       if t != nil and i < t.len and t.sons[i].kind == tyVar:
-        # XXX This is wrong! Pass by var is a 'might def', not a 'must def'
+        # This is wrong! Pass by var is a 'might def', not a 'must def'
         # like the other defs we emit. This is not good enough for a move
         # optimizer.
         genDef(c, n[i])
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index addc9e9f3..364006dd1 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -933,7 +933,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
       of wAcyclic:
         noVal(c, it)
         if sym.typ == nil: invalidPragma(c, it)
-        else: incl(sym.typ.flags, tfAcyclic)
+        # now: ignored
       of wShallow:
         noVal(c, it)
         if sym.typ == nil: invalidPragma(c, it)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index e717c6e07..0fabd5531 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1854,7 +1854,9 @@ proc processMagicType(c: PContext, m: PSym) =
     case m.name.s
     of "lent": setMagicType(c.config, m, tyLent, c.config.target.ptrSize)
     of "sink": setMagicType(c.config, m, tySink, szUncomputedSize)
-    of "owned": setMagicType(c.config, m, tyOwned, c.config.target.ptrSize)
+    of "owned":
+      setMagicType(c.config, m, tyOwned, c.config.target.ptrSize)
+      incl m.typ.flags, tfHasOwned
     else: localError(c.config, m.info, errTypeExpected)
   else: localError(c.config, m.info, errTypeExpected)
 
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 483588e6b..e3380c0e3 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -16,16 +16,12 @@ const
   tfInstClearedFlags = {tfHasMeta, tfUnresolved}
 
 proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) =
-  if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
-    localError(conf, info, "invalid pragma: acyclic")
-  elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
+  if t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
     localError(conf, info, "type 'var var' is not allowed")
 
 proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
   var t = typ.skipTypes({tyDistinct})
   if t.kind in tyTypeClasses: discard
-  elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
-    localError(conf, info, "invalid pragma: acyclic")
   elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
     localError(conf, info, "type 'var var' is not allowed")
   elif computeSize(conf, t) == szIllegalRecursion:
diff --git a/compiler/transf.nim b/compiler/transf.nim
index ec390da9a..ed4a7018d 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -893,7 +893,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
                   nkBlockStmt, nkBlockExpr}:
       oldDeferAnchor = c.deferAnchor
       c.deferAnchor = n
-  if n.typ != nil and tfHasAsgn in n.typ.flags:
+  if (n.typ != nil and tfHasAsgn in n.typ.flags) or
+      optNimV2 in c.graph.config.globalOptions:
     c.needsDestroyPass = true
   case n.kind
   of nkSym:
diff --git a/compiler/types.nim b/compiler/types.nim
index 86e5e756a..b71888906 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -68,17 +68,6 @@ const
   typedescPtrs* = abstractPtrs + {tyTypeDesc}
   typedescInst* = abstractInst + {tyTypeDesc, tyOwned}
 
-type
-  TTypeFieldResult* = enum
-    frNone,                   # type has no object type field
-    frHeader,                 # type has an object type field only in the header
-    frEmbedded                # type has an object type field somewhere embedded
-
-proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult
-  # this does a complex analysis whether a call to ``objectInit`` needs to be
-  # made or intializing of the type field suffices or if there is no type field
-  # at all in this type.
-
 proc invalidGenericInst*(f: PType): bool =
   result = f.kind == tyGenericInst and lastSon(f) == nil
 
@@ -242,11 +231,16 @@ proc containsObject*(t: PType): bool =
   result = searchTypeFor(t, isObjectPredicate)
 
 proc isObjectWithTypeFieldPredicate(t: PType): bool =
-
   result = t.kind == tyObject and t.sons[0] == nil and
       not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and
       tfFinal notin t.flags
 
+type
+  TTypeFieldResult* = enum
+    frNone,                   # type has no object type field
+    frHeader,                 # type has an object type field only in the header
+    frEmbedded                # type has an object type field somewhere embedded
+
 proc analyseObjectWithTypeFieldAux(t: PType,
                                    marker: var IntSet): TTypeFieldResult =
   var res: TTypeFieldResult
@@ -276,7 +270,10 @@ proc analyseObjectWithTypeFieldAux(t: PType,
   else:
     discard
 
-proc analyseObjectWithTypeField(t: PType): TTypeFieldResult =
+proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult =
+  # this does a complex analysis whether a call to ``objectInit`` needs to be
+  # made or intializing of the type field suffices or if there is no type field
+  # at all in this type.
   var marker = initIntSet()
   result = analyseObjectWithTypeFieldAux(t, marker)
 
@@ -323,9 +320,7 @@ proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool =
 proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool =
   result = false
   if typ == nil: return
-  if tfAcyclic in typ.flags: return
   var t = skipTypes(typ, abstractInst+{tyOwned}-{tyTypeDesc})
-  if tfAcyclic in t.flags: return
   case t.kind
   of tyTuple, tyObject, tyRef, tySequence, tyArray, tyOpenArray, tyVarargs:
     if not containsOrIncl(marker, t.id):
diff --git a/doc/manual.rst b/doc/manual.rst
index a2d51cf08..09daf4a95 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -6925,41 +6925,8 @@ The ``noreturn`` pragma is used to mark a proc that never returns.
 
 acyclic pragma
 --------------
-The ``acyclic`` pragma can be used for object types to mark them as acyclic
-even though they seem to be cyclic. This is an **optimization** for the garbage
-collector to not consider objects of this type as part of a cycle:
-
-.. code-block:: nim
-  type
-    Node = ref NodeObj
-    NodeObj {.acyclic.} = object
-      left, right: Node
-      data: string
-
-Or if we directly use a ref object:
-
-.. code-block:: nim
-  type
-    Node = ref object {.acyclic.}
-      left, right: Node
-      data: string
-
-In the example a tree structure is declared with the ``Node`` type. Note that
-the type definition is recursive and the GC has to assume that objects of
-this type may form a cyclic graph. The ``acyclic`` pragma passes the
-information that this cannot happen to the GC. If the programmer uses the
-``acyclic`` pragma for data types that are in reality cyclic, the GC may leak
-memory, but nothing worse happens.
-
-**Future directions**: The ``acyclic`` pragma may become a property of a
-``ref`` type:
-
-.. code-block:: nim
-  type
-    Node = acyclic ref NodeObj
-    NodeObj = object
-      left, right: Node
-      data: string
+The ``acyclic`` pragma applies to type declarations. It is deprecated and
+ignored.
 
 
 final pragma