summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2023-05-12 02:49:47 +0800
committerGitHub <noreply@github.com>2023-05-11 20:49:47 +0200
commitebbad9e9604d778c32838c981c8748f3675d2659 (patch)
tree72e3bec49ef59c620ce3b59e81e53c03b535234c
parentc00448358121bbf6b5e1fcfe39bb6eb3359d6462 (diff)
downloadNim-ebbad9e9604d778c32838c981c8748f3675d2659.tar.gz
cursor fields cannot form reference cycles (#21832)
* cursor fields cannot form a reference cycle

* fixes typo

* fixes position
-rw-r--r--compiler/types.nim21
-rw-r--r--tests/types/tcyclic.nim20
2 files changed, 28 insertions, 13 deletions
diff --git a/compiler/types.nim b/compiler/types.nim
index 97cc439c0..96dbd26b2 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -374,15 +374,18 @@ proc canFormAcycleAux(g: ModuleGraph; marker: var IntSet, typ: PType, orig: PTyp
 proc canFormAcycleNode(g: ModuleGraph; marker: var IntSet, n: PNode, orig: PType, withRef: bool, hasTrace: bool): bool =
   result = false
   if n != nil:
-    result = canFormAcycleAux(g, marker, n.typ, orig, withRef, hasTrace)
-    if not result:
-      case n.kind
-      of nkNone..nkNilLit:
-        discard
-      else:
-        for i in 0..<n.len:
-          result = canFormAcycleNode(g, marker, n[i], orig, withRef, hasTrace)
-          if result: return
+    var hasCursor = n.kind == nkSym and sfCursor in n.sym.flags
+    # cursor fields don't own the refs, which cannot form reference cycles
+    if hasTrace or not hasCursor:
+      result = canFormAcycleAux(g, marker, n.typ, orig, withRef, hasTrace)
+      if not result:
+        case n.kind
+        of nkNone..nkNilLit:
+          discard
+        else:
+          for i in 0..<n.len:
+            result = canFormAcycleNode(g, marker, n[i], orig, withRef, hasTrace)
+            if result: return
 
 
 proc sameBackendType*(x, y: PType): bool
diff --git a/tests/types/tcyclic.nim b/tests/types/tcyclic.nim
index fc2852c49..651394c8b 100644
--- a/tests/types/tcyclic.nim
+++ b/tests/types/tcyclic.nim
@@ -51,10 +51,7 @@ cyclicNo((Cyclone, ))
 cyclicNo(Acyclic)
 
 cyclicYes(LinkedNode)
-
-when false:
-  # todo fix me
-  cyclicNo(LinkedNodeWithCursor)
+cyclicNo(LinkedNodeWithCursor) # cursor doesn't increase rc, cannot form a cycle
 
 type
   ObjectWithoutCycles = object
@@ -121,3 +118,18 @@ block:
   proc `=trace`(x: var myseq[Node]; env: pointer) = discard
 
   cyclicYes(Node)
+
+block:
+  type
+    Foo = object
+      id: ptr ref Foo
+
+  cyclicNo(Foo)
+
+block:
+  type
+    InheritableObj = object of RootObj
+    InheritableRef = ref object of RootObj
+
+  cyclicYes(InheritableObj)
+  cyclicYes(InheritableRef)