destructors for case values
This commit is contained in:
parent
985113ee2a
commit
65970efd97
3 changed files with 65 additions and 17 deletions
|
|
@ -885,6 +885,7 @@ proc assignType(dest, src: PType) =
|
||||||
dest.size = src.size
|
dest.size = src.size
|
||||||
dest.align = src.align
|
dest.align = src.align
|
||||||
dest.containerID = src.containerID
|
dest.containerID = src.containerID
|
||||||
|
dest.destructor = src.destructor
|
||||||
# this fixes 'type TLock = TSysLock':
|
# this fixes 'type TLock = TSysLock':
|
||||||
if src.sym != nil:
|
if src.sym != nil:
|
||||||
if dest.sym != nil:
|
if dest.sym != nil:
|
||||||
|
|
|
||||||
|
|
@ -875,16 +875,58 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
||||||
|
|
||||||
# special marker that indicates that we've already tried
|
# special marker values that indicates that we are
|
||||||
# to generate a destructor for some type, but it turned out
|
# 1) AnalyzingDestructor: currenlty analyzing the type for destructor
|
||||||
# to be trivial
|
# generation (needed for recursive types)
|
||||||
var DestructorIsTrivial: PSym
|
# 2) DestructorIsTrivial: completed the anlysis before and determined
|
||||||
|
# that the type has a trivial destructor
|
||||||
|
var AnalyzingDestructor, DestructorIsTrivial: PSym
|
||||||
|
new(AnalyzingDestructor)
|
||||||
new(DestructorIsTrivial)
|
new(DestructorIsTrivial)
|
||||||
|
|
||||||
var
|
var
|
||||||
destructorParam = getIdent"this_"
|
destructorParam = getIdent"this_"
|
||||||
rangeDestructorProc: PSym
|
rangeDestructorProc: PSym
|
||||||
|
|
||||||
|
proc destroyField(c: PContext, field: PSym, holder: PNode): PNode =
|
||||||
|
if instantiateDestructor(c, field.typ):
|
||||||
|
result = newNode(nkCall, field.info, @[
|
||||||
|
useSym(field.typ.destructor),
|
||||||
|
newNode(nkDotExpr, field.info, @[holder, useSym(field)])])
|
||||||
|
|
||||||
|
proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
|
||||||
|
var nonTrivialFields = 0
|
||||||
|
result = newNode(nkCaseStmt, n.info, @[])
|
||||||
|
# case x.kind
|
||||||
|
result.addSon(newNode(nkDotExpr, n.info, @[holder, n.sons[0]]))
|
||||||
|
for i in countup(1, n.len - 1):
|
||||||
|
# of A, B:
|
||||||
|
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, @[])
|
||||||
|
template addField(f: expr): stmt =
|
||||||
|
let stmt = destroyField(c, f, holder)
|
||||||
|
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:
|
||||||
|
internalAssert false
|
||||||
|
|
||||||
|
caseBranch.addSon(destroyRecList)
|
||||||
|
result.addSon(caseBranch)
|
||||||
|
# maybe no fields were destroyed?
|
||||||
|
if nonTrivialFields == 0:
|
||||||
|
result = nil
|
||||||
|
else:
|
||||||
|
debug result
|
||||||
|
|
||||||
proc generateDestructor(c: PContext, t: PType): PNode =
|
proc generateDestructor(c: PContext, t: PType): PNode =
|
||||||
## generate a destructor for a user-defined object ot tuple type
|
## generate a destructor for a user-defined object ot tuple type
|
||||||
## returns nil if the destructor turns out to be trivial
|
## returns nil if the destructor turns out to be trivial
|
||||||
|
|
@ -897,19 +939,19 @@ proc generateDestructor(c: PContext, t: PType): PNode =
|
||||||
# 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())
|
||||||
# call the destructods of all fields
|
# call the destructods of all fields
|
||||||
for s in countup(0, t.n.sons.len - 1):
|
for s in countup(0, t.n.sons.len - 1):
|
||||||
internalAssert t.n.sons[s].kind == nkSym
|
case t.n.sons[s].kind
|
||||||
let field = t.n.sons[s].sym
|
of nkRecCase:
|
||||||
if instantiateDestructor(c, field.typ):
|
let stmt = destroyCase(c, t.n.sons[s], destructedObj)
|
||||||
addLine(newNode(nkCall, field.info, @[
|
if stmt != nil: addLine(stmt)
|
||||||
useSym(field.typ.destructor),
|
of nkSym:
|
||||||
newNode(nkDotExpr, field.info, @[
|
let stmt = destroyField(c, t.n.sons[s].sym, destructedObj)
|
||||||
newIdentNode(destructorParam, t.sym.info),
|
if stmt != nil: addLine(stmt)
|
||||||
useSym(field)
|
else:
|
||||||
])
|
internalAssert false
|
||||||
]))
|
|
||||||
# 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
|
||||||
|
|
||||||
|
|
@ -920,7 +962,9 @@ proc instantiateDestructor*(c: PContext, typ: PType): bool =
|
||||||
var t = skipTypes(typ, {tyConst, tyMutable})
|
var t = skipTypes(typ, {tyConst, tyMutable})
|
||||||
|
|
||||||
if t.destructor != nil:
|
if t.destructor != nil:
|
||||||
return t.destructor != DestructorIsTrivial
|
# XXX: This is not entirely correct for recursive types, but we need
|
||||||
|
# it temporarily to hide the "destroy is alrady defined" problem
|
||||||
|
return t.destructor notin [AnalyzingDestructor, DestructorIsTrivial]
|
||||||
|
|
||||||
case t.kind
|
case t.kind
|
||||||
of tySequence, tyArray, tyArrayConstr, tyOpenArray:
|
of tySequence, tyArray, tyArrayConstr, tyOpenArray:
|
||||||
|
|
@ -932,6 +976,7 @@ proc instantiateDestructor*(c: PContext, typ: PType): bool =
|
||||||
else:
|
else:
|
||||||
return false
|
return false
|
||||||
of tyTuple, tyObject:
|
of tyTuple, tyObject:
|
||||||
|
t.destructor = AnalyzingDestructor
|
||||||
let generated = generateDestructor(c, t)
|
let generated = generateDestructor(c, t)
|
||||||
if generated != nil:
|
if generated != nil:
|
||||||
internalAssert t.sym != nil
|
internalAssert t.sym != nil
|
||||||
|
|
|
||||||
|
|
@ -306,7 +306,9 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||||
covered: var biggestInt) =
|
covered: var biggestInt) =
|
||||||
for i in countup(0, sonsLen(branch) - 2):
|
for i in countup(0, sonsLen(branch) - 2):
|
||||||
var b = branch.sons[i]
|
var b = branch.sons[i]
|
||||||
if isRange(b):
|
if b.kind == nkRange:
|
||||||
|
branch.sons[i] = b
|
||||||
|
elif isRange(b):
|
||||||
branch.sons[i] = semCaseBranchRange(c, t, b, covered)
|
branch.sons[i] = semCaseBranchRange(c, t, b, covered)
|
||||||
else:
|
else:
|
||||||
var r = semConstExpr(c, b)
|
var r = semConstExpr(c, b)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue