This commit is contained in:
Zahary Karadjov 2014-01-02 17:55:18 +02:00
commit 02533c260b
5 changed files with 126 additions and 37 deletions

View file

@ -9,6 +9,7 @@
## This module implements destructors.
# included from sem.nim
# special marker values that indicates that we are
# 1) AnalyzingDestructor: currently analyzing the type for destructor
@ -25,10 +26,22 @@ var
destructorPragma = newIdentNode(getIdent"destructor", unknownLineInfo())
rangeDestructorProc*: PSym
proc instantiateDestructor(c: PContext, typ: PType): bool
proc instantiateDestructor(c: PContext, typ: PType): PType
proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
let t = s.typ.sons[1].skipTypes({tyVar})
var t = s.typ.sons[1].skipTypes({tyVar})
if t.kind == tyGenericInvokation:
for i in 1 .. <t.sonsLen:
if t.sons[i].kind != tyGenericParam:
localError(n.info, errDestructorNotGenericEnough)
return
t = t.base
elif t.kind == tyCompositeTypeClass:
t = t.base
if t.kind != tyGenericBody:
localError(n.info, errDestructorNotGenericEnough)
return
t.destructor = s
# automatically insert calls to base classes' destructors
if n.sons[bodyPos].kind != nkEmpty:
@ -36,15 +49,17 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
# when inheriting directly from object
# there will be a single nil son
if t.sons[i] == nil: continue
if instantiateDestructor(c, t.sons[i]):
let destructableT = instantiateDestructor(c, t.sons[i])
if destructableT != nil:
n.sons[bodyPos].addSon(newNode(nkCall, t.sym.info, @[
useSym(t.sons[i].destructor),
useSym(destructableT.destructor),
n.sons[paramsPos][1][0]]))
proc destroyField(c: PContext, field: PSym, holder: PNode): PNode =
if instantiateDestructor(c, field.typ):
let destructableT = instantiateDestructor(c, field.typ)
if destructableT != nil:
result = newNode(nkCall, field.info, @[
useSym(field.typ.destructor),
useSym(destructableT.destructor),
newNode(nkDotExpr, field.info, @[holder, useSym(field)])])
proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
@ -105,26 +120,35 @@ proc generateDestructor(c: PContext, t: PType): PNode =
# base classes' destructors will be automatically called by
# semProcAux for both auto-generated and user-defined destructors
proc instantiateDestructor(c: PContext, typ: PType): bool =
# returns true if the type already had a user-defined
# destructor or if the compiler generated a default
# member-wise one
var t = skipTypes(typ, {tyConst, tyMutable})
proc instantiateDestructor(c: PContext, typ: PType): PType =
# returns nil if a variable of type `typ` doesn't require a
# destructor. Otherwise, returns the type, which holds the
# destructor that must be used for the varialbe.
# The destructor is either user-defined or automatically
# generated by the compiler in a member-wise fashion.
var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias
let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base
else: t
if t.destructor != nil:
if typeHoldingUserDefinition.destructor != nil:
# XXX: This is not entirely correct for recursive types, but we need
# it temporarily to hide the "destroy is already defined" problem
return t.destructor notin [analyzingDestructor, destructorIsTrivial]
if typeHoldingUserDefinition.destructor notin
[analyzingDestructor, destructorIsTrivial]:
return typeHoldingUserDefinition
else:
return nil
t = t.skipTypes({tyGenericInst})
case t.kind
of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
if instantiateDestructor(c, t.sons[0]):
if instantiateDestructor(c, t.sons[0]) != nil:
if rangeDestructorProc == nil:
rangeDestructorProc = searchInScopes(c, getIdent"nimDestroyRange")
t.destructor = rangeDestructorProc
return true
return t
else:
return false
return nil
of tyTuple, tyObject:
t.destructor = analyzingDestructor
let generated = generateDestructor(c, t)
@ -139,21 +163,21 @@ proc instantiateDestructor(c: PContext, typ: PType): bool =
emptyNode,
newNode(nkIdentDefs, i, @[
newIdentNode(destructorParam, i),
useSym(t.sym),
symNodeFromType(c, makeVarType(c, t), t.sym.info),
emptyNode]),
]),
newNode(nkPragma, i, @[destructorPragma]),
emptyNode,
generated
])
discard semProc(c, fullDef)
internalAssert t.destructor != nil
return true
let semantizedDef = semProc(c, fullDef)
t.destructor = semantizedDef[namePos].sym
return t
else:
t.destructor = destructorIsTrivial
return false
return nil
else:
return false
return nil
proc insertDestructors(c: PContext,
varSection: PNode): tuple[outer, inner: PNode] =
@ -179,9 +203,11 @@ proc insertDestructors(c: PContext,
varId = varSection[j][0]
varTyp = varId.sym.typ
info = varId.info
if varTyp != nil and instantiateDestructor(c, varTyp) and
sfGlobal notin varId.sym.flags:
if varTyp == nil or sfGlobal in varId.sym.flags: continue
let destructableT = instantiateDestructor(c, varTyp)
if destructableT != nil:
var tryStmt = newNodeI(nkTryStmt, info)
if j < totalVars - 1:
@ -198,11 +224,11 @@ proc insertDestructors(c: PContext,
else:
result.inner = newNodeI(nkStmtList, info)
tryStmt.addSon(result.inner)
tryStmt.addSon(
newNode(nkFinally, info, @[
semStmt(c, newNode(nkCall, info, @[
useSym(varTyp.destructor),
useSym(destructableT.destructor),
useSym(varId.sym)]))]))
result.outer = newNodeI(nkStmtList, info)