mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 14:00:35 +00:00
ARC: implemented a simple cycle detector
This commit is contained in:
@@ -19,6 +19,8 @@ import
|
||||
strutils, options, dfa, lowerings, tables, modulegraphs, msgs,
|
||||
lineinfos, parampatterns, sighashes
|
||||
|
||||
from trees import exprStructuralEquivalent
|
||||
|
||||
type
|
||||
Con = object
|
||||
owner: PSym
|
||||
@@ -461,6 +463,35 @@ proc isCursor(n: PNode): bool =
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc cycleCheck(n: PNode; c: var Con) =
|
||||
if c.graph.config.selectedGC != gcDestructors: return
|
||||
var value = n[1]
|
||||
if value.kind == nkClosure:
|
||||
value = value[1]
|
||||
if value.kind == nkNilLit: return
|
||||
let destTyp = n[0].typ.skipTypes(abstractInst)
|
||||
if destTyp.kind != tyRef and not (destTyp.kind == tyProc and destTyp.callConv == ccClosure):
|
||||
return
|
||||
|
||||
var x = n[0]
|
||||
var field: PNode = nil
|
||||
while true:
|
||||
if x.kind == nkDotExpr:
|
||||
if field == nil: field = x[1]
|
||||
x = x[0]
|
||||
elif x.kind in {nkBracketExpr, nkCheckedFieldExpr, nkDerefExpr, nkHiddenDeref}:
|
||||
x = x[0]
|
||||
else:
|
||||
break
|
||||
if exprStructuralEquivalent(x, value, strictSymEquality = true):
|
||||
let msg =
|
||||
if field != nil:
|
||||
"'$#' creates an uncollectable ref cycle; annotate '$#' with .cursor" % [$n, $field]
|
||||
else:
|
||||
"'$#' creates an uncollectable ref cycle" % [$n]
|
||||
message(c.graph.config, n.info, warnCycleCreated, msg)
|
||||
break
|
||||
|
||||
proc p(n: PNode; c: var Con; consumed = false): PNode =
|
||||
case n.kind
|
||||
of nkCallKinds:
|
||||
@@ -544,6 +575,8 @@ proc p(n: PNode; c: var Con; consumed = false): PNode =
|
||||
if n[1].kind == nkSym and n[0].kind == nkSym and n[0].sym == n[1].sym:
|
||||
result = newNodeI(nkEmpty, n.info)
|
||||
else:
|
||||
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
|
||||
cycleCheck(n, c)
|
||||
result = moveOrCopy(n[0], n[1], c)
|
||||
else:
|
||||
result = copyNode(n)
|
||||
|
||||
@@ -366,13 +366,15 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
|
||||
if upField.typ.skipTypes({tyOwned, tyRef, tyPtr}) != fieldType.skipTypes({tyOwned, tyRef, tyPtr}):
|
||||
localError(c.graph.config, dep.info, "internal error: up references do not agree")
|
||||
|
||||
if c.graph.config.selectedGC == gcDestructors and sfCursor notin upField.flags:
|
||||
localError(c.graph.config, dep.info, "internal error: up reference is not a .cursor")
|
||||
when false:
|
||||
if c.graph.config.selectedGC == gcDestructors and sfCursor notin upField.flags:
|
||||
localError(c.graph.config, dep.info, "internal error: up reference is not a .cursor")
|
||||
else:
|
||||
let result = newSym(skField, upIdent, obj.owner, obj.owner.info)
|
||||
result.typ = fieldType
|
||||
if c.graph.config.selectedGC == gcDestructors:
|
||||
result.flags.incl sfCursor
|
||||
when false:
|
||||
if c.graph.config.selectedGC == gcDestructors:
|
||||
result.flags.incl sfCursor
|
||||
rawAddField(obj, result)
|
||||
|
||||
discard """
|
||||
|
||||
@@ -37,7 +37,7 @@ type
|
||||
warnEachIdentIsTuple,
|
||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||
warnInconsistentSpacing, warnCaseTransition, warnUser,
|
||||
warnInconsistentSpacing, warnCaseTransition, warnCycleCreated, warnUser,
|
||||
hintSuccess, hintSuccessX, hintCC,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed,
|
||||
hintConvToBaseNotNeeded,
|
||||
@@ -94,6 +94,7 @@ const
|
||||
warnResultShadowed: "Special variable 'result' is shadowed.",
|
||||
warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
|
||||
warnCaseTransition: "Potential object case transition, instantiate new object instead",
|
||||
warnCycleCreated: "$1",
|
||||
warnUser: "$1",
|
||||
hintSuccess: "operation successful: $#",
|
||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
|
||||
@@ -139,7 +140,7 @@ const
|
||||
"UnsafeCode", "UnusedImport", "EachIdentIsTuple",
|
||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
|
||||
"Spacing", "CaseTransition", "User"]
|
||||
"Spacing", "CaseTransition", "CycleCreated", "User"]
|
||||
|
||||
HintsToStr* = [
|
||||
"Success", "SuccessX", "CC", "LineTooLong",
|
||||
|
||||
@@ -341,6 +341,8 @@ when defined(windows) or defined(nimdoc):
|
||||
addr lpNumberOfBytesTransferred, addr lpCompletionKey,
|
||||
cast[ptr POVERLAPPED](addr customOverlapped), llTimeout).bool
|
||||
result = true
|
||||
when defined(gcDestructors):
|
||||
GC_ref(customOverlapped)
|
||||
|
||||
# http://stackoverflow.com/a/12277264/492186
|
||||
# TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html
|
||||
|
||||
Reference in New Issue
Block a user