destructors for case values

This commit is contained in:
Zahary Karadjov 2012-06-06 23:00:33 +03:00
commit 65970efd97
3 changed files with 65 additions and 17 deletions

View file

@ -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:

View file

@ -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

View file

@ -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)