diff options
-rwxr-xr-x | compiler/semdata.nim | 6 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 106 | ||||
-rwxr-xr-x | compiler/types.nim | 7 | ||||
-rwxr-xr-x | lib/system/assign.nim | 4 |
4 files changed, 107 insertions, 16 deletions
diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 81e45f71c..c28c8c7a1 100755 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -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})) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 82f43e787..3d00d495d 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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) diff --git a/compiler/types.nim b/compiler/types.nim index 2f201b9de..ecc250a5a 100755 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -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 - diff --git a/lib/system/assign.nim b/lib/system/assign.nim index 59c44a6cc..f29dc547c 100755 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -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) |