generate default destructors
This commit is contained in:
parent
41a9a941ab
commit
d10b524c9a
4 changed files with 107 additions and 16 deletions
|
|
@ -212,7 +212,11 @@ proc markUsed*(n: PNode, s: PSym) =
|
||||||
if {sfDeprecated, sfError} * s.flags != {}:
|
if {sfDeprecated, sfError} * s.flags != {}:
|
||||||
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
|
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
|
||||||
if sfError in s.flags: LocalError(n.info, errWrongSymbolX, 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) =
|
proc illFormedAst*(n: PNode) =
|
||||||
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
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
|
closeScope(c.tab) # close scope for parameters
|
||||||
popOwner()
|
popOwner()
|
||||||
result.typ = s.typ
|
result.typ = s.typ
|
||||||
|
|
||||||
|
proc instantiateDestructor*(c: PContext, typ: PType): bool
|
||||||
|
|
||||||
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
validPragmas: TSpecialWords): PNode =
|
validPragmas: TSpecialWords): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -743,6 +745,19 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
popOwner()
|
popOwner()
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
s.options = gOptions
|
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:
|
if n.sons[bodyPos].kind != nkEmpty:
|
||||||
# for DLL generation it is annoying to check for sfImportc!
|
# for DLL generation it is annoying to check for sfImportc!
|
||||||
if sfBorrow in s.flags:
|
if sfBorrow in s.flags:
|
||||||
|
|
@ -772,10 +787,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
incl(s.flags, sfForward)
|
incl(s.flags, sfForward)
|
||||||
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
||||||
sideEffectsCheck(c, 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:
|
if s.typ.callConv == ccClosure and s.owner.kind == skModule:
|
||||||
localError(s.info, errXCannotBeClosure, s.name.s)
|
localError(s.info, errXCannotBeClosure, s.name.s)
|
||||||
closeScope(c.tab) # close scope for parameters
|
closeScope(c.tab) # close scope for parameters
|
||||||
|
|
@ -864,6 +875,85 @@ 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
|
||||||
|
# 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):
|
proc insertDestructors(c: PContext, varSection: PNode):
|
||||||
tuple[outer: PNode, inner: PNode] =
|
tuple[outer: PNode, inner: PNode] =
|
||||||
# Accepts a var or let section.
|
# Accepts a var or let section.
|
||||||
|
|
@ -889,7 +979,7 @@ proc insertDestructors(c: PContext, varSection: PNode):
|
||||||
varTyp = varId.sym.typ
|
varTyp = varId.sym.typ
|
||||||
info = varId.info
|
info = varId.info
|
||||||
|
|
||||||
if varTyp != nil and instantiateDestructor(varTyp):
|
if varTyp != nil and instantiateDestructor(c, varTyp):
|
||||||
var tryStmt = newNodeI(nkTryStmt, info)
|
var tryStmt = newNodeI(nkTryStmt, info)
|
||||||
|
|
||||||
if j < totalVars - 1:
|
if j < totalVars - 1:
|
||||||
|
|
@ -910,8 +1000,8 @@ proc insertDestructors(c: PContext, varSection: PNode):
|
||||||
tryStmt.addSon(
|
tryStmt.addSon(
|
||||||
newNode(nkFinally, info, @[
|
newNode(nkFinally, info, @[
|
||||||
semStmt(c, newNode(nkCall, info, @[
|
semStmt(c, newNode(nkCall, info, @[
|
||||||
semSym(c, varId, varTyp.destructor, {}),
|
useSym(varTyp.destructor),
|
||||||
semSym(c, varId, varId.sym, {})]))]))
|
useSym(varId.sym)]))]))
|
||||||
|
|
||||||
result.outer = newNodeI(nkStmtList, info)
|
result.outer = newNodeI(nkStmtList, info)
|
||||||
varSection.sons.setLen(j+1)
|
varSection.sons.setLen(j+1)
|
||||||
|
|
|
||||||
|
|
@ -1062,10 +1062,3 @@ proc getSize(typ: PType): biggestInt =
|
||||||
result = computeSize(typ)
|
result = computeSize(typ)
|
||||||
if result < 0: InternalError("getSize(" & $typ.kind & ')')
|
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 -----------------------------------------
|
# ---------------------- 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 genericReset(dest: Pointer, mt: PNimType) {.compilerProc.}
|
||||||
proc genericResetAux(dest: Pointer, n: ptr TNimNode) =
|
proc genericResetAux(dest: Pointer, n: ptr TNimNode) =
|
||||||
var d = cast[TAddress](dest)
|
var d = cast[TAddress](dest)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue