mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-20 16:01:29 +00:00
generate default destructors
This commit is contained in:
@@ -212,7 +212,11 @@ proc markUsed*(n: PNode, s: PSym) =
|
||||
if {sfDeprecated, sfError} * s.flags != {}:
|
||||
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
|
||||
if sfError in s.flags: LocalError(n.info, errWrongSymbolX, s.name.s)
|
||||
|
||||
|
||||
proc useSym*(sym: PSym): PNode =
|
||||
result = newSymNode(sym)
|
||||
markUsed(result, sym)
|
||||
|
||||
proc illFormedAst*(n: PNode) =
|
||||
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||
|
||||
|
||||
@@ -681,7 +681,9 @@ proc semLambda(c: PContext, n: PNode): PNode =
|
||||
closeScope(c.tab) # close scope for parameters
|
||||
popOwner()
|
||||
result.typ = s.typ
|
||||
|
||||
|
||||
proc instantiateDestructor*(c: PContext, typ: PType): bool
|
||||
|
||||
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
validPragmas: TSpecialWords): PNode =
|
||||
result = n
|
||||
@@ -743,6 +745,19 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
popOwner()
|
||||
pushOwner(s)
|
||||
s.options = gOptions
|
||||
if result.sons[namePos].sym.name.id == ord(wDestroy) and s.typ.sons.len == 2:
|
||||
let t = s.typ.sons[1].skipTypes({tyVar})
|
||||
t.destructor = s
|
||||
# automatically insert calls to base classes' destructors
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
for i in countup(0, t.sonsLen - 1):
|
||||
# when inheriting directly from object
|
||||
# there will be a single nil son
|
||||
if t.sons[i] == nil: continue
|
||||
if instantiateDestructor(c, t.sons[i]):
|
||||
n.sons[bodyPos].addSon(newNode(nkCall, t.sym.info, @[
|
||||
useSym(t.sons[i].destructor),
|
||||
n.sons[paramsPos][1][0]]))
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
# for DLL generation it is annoying to check for sfImportc!
|
||||
if sfBorrow in s.flags:
|
||||
@@ -772,10 +787,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
incl(s.flags, sfForward)
|
||||
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
||||
sideEffectsCheck(c, s)
|
||||
if result.sons[namePos].sym.name.id == ord(wDestroy):
|
||||
if s.typ.sons.len == 2:
|
||||
let typ = s.typ.sons[1].skipTypes({tyVar})
|
||||
typ.destructor = s
|
||||
if s.typ.callConv == ccClosure and s.owner.kind == skModule:
|
||||
localError(s.info, errXCannotBeClosure, s.name.s)
|
||||
closeScope(c.tab) # close scope for parameters
|
||||
@@ -864,6 +875,85 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||
if result.isNil:
|
||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
||||
|
||||
# special marker that indicates that we've already tried
|
||||
# to generate a destructor for some type, but it turned out
|
||||
# to be trivial
|
||||
var DestructorIsTrivial: PSym
|
||||
new(DestructorIsTrivial)
|
||||
|
||||
var
|
||||
destructorParam = getIdent"this_"
|
||||
rangeDestructorProc: PSym
|
||||
|
||||
proc generateDestructor(c: PContext, t: PType): PNode =
|
||||
## generate a destructor for a user-defined object ot tuple type
|
||||
## returns nil if the destructor turns out to be trivial
|
||||
|
||||
template addLine(e: expr): stmt =
|
||||
if result == nil: result = newNode(nkStmtList)
|
||||
result.addSon(e)
|
||||
|
||||
internalAssert t.n.kind == nkRecList
|
||||
# call the destructods of all fields
|
||||
for s in countup(0, t.n.sons.len - 1):
|
||||
internalAssert t.n.sons[s].kind == nkSym
|
||||
let field = t.n.sons[s].sym
|
||||
if instantiateDestructor(c, field.typ):
|
||||
addLine(newNode(nkCall, field.info, @[
|
||||
useSym(field.typ.destructor),
|
||||
newNode(nkDotExpr, field.info, @[
|
||||
newIdentNode(destructorParam, t.sym.info),
|
||||
useSym(field)
|
||||
])
|
||||
]))
|
||||
# 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})
|
||||
|
||||
if t.destructor != nil:
|
||||
return t.destructor != DestructorIsTrivial
|
||||
|
||||
case t.kind
|
||||
of tySequence, tyArray, tyArrayConstr, tyOpenArray:
|
||||
if instantiateDestructor(c, t.sons[0]):
|
||||
if rangeDestructorProc == nil:
|
||||
rangeDestructorProc = SymtabGet(c.tab, getIdent"nimDestroyRange")
|
||||
t.destructor = rangeDestructorProc
|
||||
return true
|
||||
else:
|
||||
return false
|
||||
of tyTuple, tyObject:
|
||||
let generated = generateDestructor(c, t)
|
||||
if generated != nil:
|
||||
internalAssert t.sym != nil
|
||||
var i = t.sym.info
|
||||
let fullDef = newNode(nkProcDef, i, @[
|
||||
newIdentNode(getIdent"destroy", i),
|
||||
emptyNode,
|
||||
newNode(nkFormalParams, i, @[
|
||||
emptyNode,
|
||||
newNode(nkIdentDefs, i, @[
|
||||
newIdentNode(destructorParam, i),
|
||||
useSym(t.sym),
|
||||
emptyNode]),
|
||||
]),
|
||||
emptyNode,
|
||||
generated
|
||||
])
|
||||
discard semProc(c, fullDef)
|
||||
internalAssert t.destructor != nil
|
||||
return true
|
||||
else:
|
||||
t.destructor = DestructorIsTrivial
|
||||
return false
|
||||
else:
|
||||
return false
|
||||
|
||||
proc insertDestructors(c: PContext, varSection: PNode):
|
||||
tuple[outer: PNode, inner: PNode] =
|
||||
# Accepts a var or let section.
|
||||
@@ -889,7 +979,7 @@ proc insertDestructors(c: PContext, varSection: PNode):
|
||||
varTyp = varId.sym.typ
|
||||
info = varId.info
|
||||
|
||||
if varTyp != nil and instantiateDestructor(varTyp):
|
||||
if varTyp != nil and instantiateDestructor(c, varTyp):
|
||||
var tryStmt = newNodeI(nkTryStmt, info)
|
||||
|
||||
if j < totalVars - 1:
|
||||
@@ -910,8 +1000,8 @@ proc insertDestructors(c: PContext, varSection: PNode):
|
||||
tryStmt.addSon(
|
||||
newNode(nkFinally, info, @[
|
||||
semStmt(c, newNode(nkCall, info, @[
|
||||
semSym(c, varId, varTyp.destructor, {}),
|
||||
semSym(c, varId, varId.sym, {})]))]))
|
||||
useSym(varTyp.destructor),
|
||||
useSym(varId.sym)]))]))
|
||||
|
||||
result.outer = newNodeI(nkStmtList, info)
|
||||
varSection.sons.setLen(j+1)
|
||||
|
||||
@@ -1062,10 +1062,3 @@ proc getSize(typ: PType): biggestInt =
|
||||
result = computeSize(typ)
|
||||
if result < 0: InternalError("getSize(" & $typ.kind & ')')
|
||||
|
||||
proc instantiateDestructor*(typ: PType): bool =
|
||||
# return true if the type already had a user-defined
|
||||
# destructor or if the compiler generated a default
|
||||
# member-wise one
|
||||
if typ.destructor != nil: return true
|
||||
return false
|
||||
|
||||
|
||||
@@ -139,6 +139,10 @@ proc objectInit(dest: Pointer, typ: PNimType) =
|
||||
|
||||
# ---------------------- assign zero -----------------------------------------
|
||||
|
||||
proc nimDestroyRange*[T](r: T) =
|
||||
# internal proc used for destroying sequences and arrays
|
||||
for i in countup(0, r.len - 1): destroy(r[i])
|
||||
|
||||
proc genericReset(dest: Pointer, mt: PNimType) {.compilerProc.}
|
||||
proc genericResetAux(dest: Pointer, n: ptr TNimNode) =
|
||||
var d = cast[TAddress](dest)
|
||||
|
||||
Reference in New Issue
Block a user