handle nested case objects in destructor generation
This commit is contained in:
parent
492fa86638
commit
c1c6b6e50e
2 changed files with 75 additions and 36 deletions
|
|
@ -55,7 +55,9 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
|
||||||
useSym(destructableT.destructor),
|
useSym(destructableT.destructor),
|
||||||
n.sons[paramsPos][1][0]]))
|
n.sons[paramsPos][1][0]]))
|
||||||
|
|
||||||
proc destroyField(c: PContext, field: PSym, holder: PNode): PNode =
|
proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode
|
||||||
|
|
||||||
|
proc destroySym(c: PContext, field: PSym, holder: PNode): PNode =
|
||||||
let destructableT = instantiateDestructor(c, field.typ)
|
let destructableT = instantiateDestructor(c, field.typ)
|
||||||
if destructableT != nil:
|
if destructableT != nil:
|
||||||
result = newNode(nkCall, field.info, @[
|
result = newNode(nkCall, field.info, @[
|
||||||
|
|
@ -70,56 +72,49 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
|
||||||
for i in countup(1, n.len - 1):
|
for i in countup(1, n.len - 1):
|
||||||
# of A, B:
|
# of A, B:
|
||||||
var caseBranch = newNode(n[i].kind, n[i].info, n[i].sons[0 .. -2])
|
var caseBranch = newNode(n[i].kind, n[i].info, n[i].sons[0 .. -2])
|
||||||
let recList = n[i].lastSon
|
|
||||||
var destroyRecList = newNode(nkStmtList, n[i].info, @[])
|
let stmt = destroyFieldOrFields(c, n[i].lastSon, holder)
|
||||||
template addField(f: expr): stmt =
|
if stmt == nil:
|
||||||
let stmt = destroyField(c, f, holder)
|
caseBranch.addSon(newNode(nkStmtList, n[i].info, @[]))
|
||||||
if stmt != nil:
|
|
||||||
destroyRecList.addSon(stmt)
|
|
||||||
inc nonTrivialFields
|
|
||||||
|
|
||||||
case recList.kind
|
|
||||||
of nkSym:
|
|
||||||
addField(recList.sym)
|
|
||||||
of nkRecList:
|
|
||||||
for j in countup(0, recList.len - 1):
|
|
||||||
addField(recList[j].sym)
|
|
||||||
else:
|
else:
|
||||||
internalAssert false
|
caseBranch.addSon(stmt)
|
||||||
|
nonTrivialFields += stmt.len
|
||||||
caseBranch.addSon(destroyRecList)
|
|
||||||
result.addSon(caseBranch)
|
result.addSon(caseBranch)
|
||||||
|
|
||||||
# maybe no fields were destroyed?
|
# maybe no fields were destroyed?
|
||||||
if nonTrivialFields == 0:
|
if nonTrivialFields == 0:
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
|
proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode =
|
||||||
|
template maybeAddLine(e: expr): stmt =
|
||||||
|
let stmt = e
|
||||||
|
if stmt != nil:
|
||||||
|
if result == nil: result = newNode(nkStmtList)
|
||||||
|
result.addSon(stmt)
|
||||||
|
|
||||||
|
case field.kind
|
||||||
|
of nkRecCase:
|
||||||
|
maybeAddLine destroyCase(c, field, holder)
|
||||||
|
of nkSym:
|
||||||
|
maybeAddLine destroySym(c, field.sym, holder)
|
||||||
|
of nkRecList:
|
||||||
|
for son in field:
|
||||||
|
maybeAddLine destroyFieldOrFields(c, son, holder)
|
||||||
|
else:
|
||||||
|
internalAssert false
|
||||||
|
|
||||||
proc generateDestructor(c: PContext, t: PType): PNode =
|
proc generateDestructor(c: PContext, t: PType): PNode =
|
||||||
## generate a destructor for a user-defined object or tuple type
|
## generate a destructor for a user-defined object or tuple type
|
||||||
## returns nil if the destructor turns out to be trivial
|
## returns nil if the destructor turns out to be trivial
|
||||||
|
|
||||||
template addLine(e: expr): stmt =
|
|
||||||
if result == nil: result = newNode(nkStmtList)
|
|
||||||
result.addSon(e)
|
|
||||||
|
|
||||||
# XXX: This may be true for some C-imported types such as
|
# XXX: This may be true for some C-imported types such as
|
||||||
# Tposix_spawnattr
|
# Tposix_spawnattr
|
||||||
if t.n == nil or t.n.sons == nil: return
|
if t.n == nil or t.n.sons == nil: return
|
||||||
internalAssert t.n.kind == nkRecList
|
internalAssert t.n.kind == nkRecList
|
||||||
let destructedObj = newIdentNode(destructorParam, unknownLineInfo())
|
let destructedObj = newIdentNode(destructorParam, unknownLineInfo())
|
||||||
# call the destructods of all fields
|
# call the destructods of all fields
|
||||||
for s in countup(0, t.n.sons.len - 1):
|
result = destroyFieldOrFields(c, t.n, destructedObj)
|
||||||
case t.n.sons[s].kind
|
|
||||||
of nkRecCase:
|
|
||||||
let stmt = destroyCase(c, t.n.sons[s], destructedObj)
|
|
||||||
if stmt != nil: addLine(stmt)
|
|
||||||
of nkSym:
|
|
||||||
let stmt = destroyField(c, t.n.sons[s].sym, destructedObj)
|
|
||||||
if stmt != nil: addLine(stmt)
|
|
||||||
else:
|
|
||||||
# XXX just skip it for now so that the compiler doesn't crash, but
|
|
||||||
# please zahary fix it! arbitrary nesting of nkRecList/nkRecCase is
|
|
||||||
# possible. Any thread example seems to trigger this.
|
|
||||||
discard
|
|
||||||
# base classes' destructors will be automatically called by
|
# base classes' destructors will be automatically called by
|
||||||
# semProcAux for both auto-generated and user-defined destructors
|
# semProcAux for both auto-generated and user-defined destructors
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,13 @@ myobj destroyed
|
||||||
----
|
----
|
||||||
mygeneric3 constructed
|
mygeneric3 constructed
|
||||||
mygeneric1 destroyed
|
mygeneric1 destroyed
|
||||||
|
----
|
||||||
|
mygeneric1 destroyed
|
||||||
|
----
|
||||||
|
myobj destroyed
|
||||||
|
----
|
||||||
|
----
|
||||||
|
myobj destroyed
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -31,6 +38,22 @@ type
|
||||||
x: A
|
x: A
|
||||||
y: B
|
y: B
|
||||||
z: C
|
z: C
|
||||||
|
|
||||||
|
TObjKind = enum A, B, C, D
|
||||||
|
|
||||||
|
TCaseObj = object
|
||||||
|
case kind: TObjKind
|
||||||
|
of A:
|
||||||
|
x: TMyGeneric1[int]
|
||||||
|
of B, C:
|
||||||
|
y: TMyObj
|
||||||
|
else:
|
||||||
|
case innerKind: TObjKind
|
||||||
|
of A, B, C:
|
||||||
|
p: TMyGeneric3[int, float, string]
|
||||||
|
of D:
|
||||||
|
q: TMyGeneric3[TMyObj, int, int]
|
||||||
|
r: string
|
||||||
|
|
||||||
proc destruct(o: var TMyObj) {.destructor.} =
|
proc destruct(o: var TMyObj) {.destructor.} =
|
||||||
if o.p != nil: dealloc o.p
|
if o.p != nil: dealloc o.p
|
||||||
|
|
@ -82,3 +105,24 @@ mygeneric2[int](10)
|
||||||
echo "----"
|
echo "----"
|
||||||
mygeneric3()
|
mygeneric3()
|
||||||
|
|
||||||
|
proc caseobj =
|
||||||
|
block:
|
||||||
|
echo "----"
|
||||||
|
var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10))
|
||||||
|
|
||||||
|
block:
|
||||||
|
echo "----"
|
||||||
|
var o2 = TCaseObj(kind: B, y: open())
|
||||||
|
|
||||||
|
block:
|
||||||
|
echo "----"
|
||||||
|
var o3 = TCaseObj(kind: D, innerKind: B, r: "test",
|
||||||
|
p: TMyGeneric3[int, float, string](x: 10, y: 1.0, z: "test"))
|
||||||
|
|
||||||
|
block:
|
||||||
|
echo "----"
|
||||||
|
var o4 = TCaseObj(kind: D, innerKind: D, r: "test",
|
||||||
|
q: TMyGeneric3[TMyObj, int, int](x: open(), y: 1, z: 0))
|
||||||
|
|
||||||
|
caseobj()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue