diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 2a6742ca7b..8f5a667951 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1361,7 +1361,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) if a.storage == OnHeap and usesWriteBarrier(p.config): - if canFormAcycle(a.t): + if canFormAcycle(p.module.g.graph, a.t): linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", [a.rdLoc]) else: linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", [a.rdLoc]) @@ -1398,7 +1398,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = var call: TLoc initLoc(call, locExpr, dest.lode, OnHeap) if dest.storage == OnHeap and usesWriteBarrier(p.config): - if canFormAcycle(dest.t): + if canFormAcycle(p.module.g.graph, dest.t): linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", [dest.rdLoc]) else: linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", [dest.rdLoc]) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 04dd0ecacb..ed6988d592 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1026,7 +1026,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; # compute type flags for GC optimization var flags = 0 if not containsGarbageCollectedRef(typ): flags = flags or 1 - if not canFormAcycle(typ): flags = flags or 2 + if not canFormAcycle(m.g.graph, typ): flags = flags or 2 #else echo("can contain a cycle: " & typeToString(typ)) if flags != 0: m.s[cfsTypeInit3].addf("$1.flags = $2;$n", [nameHcr, rope(flags)]) @@ -1312,7 +1312,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = result = theProc.loc.r when false: - if not canFormAcycle(t) and op == attachedTrace: + if not canFormAcycle(m.g.graph, t) and op == attachedTrace: echo "ayclic but has this =trace ", t, " ", theProc.ast else: when false: @@ -1339,7 +1339,7 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn let traceImpl = genHook(m, t, info, attachedTrace) var flags = 0 - if not canFormAcycle(t): flags = flags or 1 + if not canFormAcycle(m.g.graph, t): flags = flags or 1 addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.flags = $6;", [ name, destroyImpl, getTypeDesc(m, t), typeName, diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 539956dd3e..d5eb6b58c2 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -345,13 +345,13 @@ proc isCriticalLink(dest: PNode): bool {.inline.} = proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) = if c.graph.config.selectedGC == gcOrc: let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct}) - if cyclicType(t): + if cyclicType(c.graph, t): result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest)) proc genMarkCyclic(c: var Con; result, dest: PNode) = if c.graph.config.selectedGC == gcOrc: let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct}) - if cyclicType(t): + if cyclicType(c.graph, t): if t.kind == tyRef: result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest) else: diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index a5fcf9184b..de238c771c 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -518,7 +518,7 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = forallElements(c, t, body, x, y) body.add genBuiltin(c, mDestroy, "destroy", x) of attachedTrace: - if canFormAcycle(t.elemType): + if canFormAcycle(c.g, t.elemType): # follow all elements: forallElements(c, t, body, x, y) @@ -553,7 +553,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = doAssert t.destructor != nil body.add destructorCall(c, t.destructor, x) of attachedTrace: - if t.kind != tyString and canFormAcycle(t.elemType): + if t.kind != tyString and canFormAcycle(c.g, t.elemType): let op = getAttachedOp(c.g, t, c.kind) if op == nil: return # protect from recursion @@ -574,9 +574,9 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedTrace: discard "strings are atomic and have no inner elements that are to trace" -proc cyclicType*(t: PType): bool = +proc cyclicType*(g: ModuleGraph, t: PType): bool = case t.kind - of tyRef: result = types.canFormAcycle(t.lastSon) + of tyRef: result = types.canFormAcycle(g, t.lastSon) of tyProc: result = t.callConv == ccClosure else: result = false @@ -604,7 +604,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let elemType = t.lastSon createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen) - let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType) + let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(c.g, elemType) let tmp = if isCyclic and c.kind in {attachedAsgn, attachedSink}: @@ -929,7 +929,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp result.typ.addParam src if kind == attachedAsgn and g.config.selectedGC == gcOrc and - cyclicType(typ.skipTypes(abstractInst)): + cyclicType(g, typ.skipTypes(abstractInst)): let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"), nextSymId(idgen), result, info) cycleParam.typ = getSysType(g, info, tyBool) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index e950688c4a..49c64086ca 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -195,6 +195,10 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym) arg = arg.base.skipTypes(skippedTypes + {tyGenericInst}) if not rec: break result = getTypeDescNode(c, arg, operand.owner, traitCall.info) + of "isCyclic": + var operand = operand.skipTypes({tyGenericInst}) + let isCyclic = canFormAcycle(c.graph, operand) + result = newIntNodeT(toInt128(ord(isCyclic)), traitCall, c.idgen, c.graph) else: localError(c.config, traitCall.info, "unknown trait: " & s) result = newNodeI(nkEmpty, traitCall.info) diff --git a/compiler/types.nim b/compiler/types.nim index 7da1efa1ef..339d4f0bca 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -368,41 +368,62 @@ proc containsHiddenPointer*(typ: PType): bool = # that need to be copied deeply) result = searchTypeFor(typ, isHiddenPointer) -proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool -proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = +proc canFormAcycleAux(g: ModuleGraph; marker: var IntSet, typ: PType, orig: PType, withRef: bool, hasTrace: bool): bool +proc canFormAcycleNode(g: ModuleGraph; marker: var IntSet, n: PNode, orig: PType, withRef: bool, hasTrace: bool): bool = result = false if n != nil: - result = canFormAcycleAux(marker, n.typ, startId) + result = canFormAcycleAux(g, marker, n.typ, orig, withRef, hasTrace) if not result: case n.kind of nkNone..nkNilLit: discard else: for i in 0..