diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/astalgo.nim | 2 | ||||
-rw-r--r-- | compiler/msgs.nim | 3 | ||||
-rw-r--r-- | compiler/semdestruct.nim | 80 | ||||
-rw-r--r-- | compiler/semstmts.nim | 2 |
4 files changed, 59 insertions, 28 deletions
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 4b7348566..110ee191f 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -432,6 +432,8 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope = proc debug(n: PSym) = if n == nil: writeln(stdout, "null") + elif n.kind == skUnknown: + writeln(stdout, "skUnknown") else: #writeln(stdout, ropeToStr(symToYaml(n, 0, 1))) writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4", [ diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 1b4d8e47a..d7944a182 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -93,6 +93,7 @@ type errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely, errOnlyACallOpCanBeDelegator, errUsingNoSymbol, + errDestructorNotGenericEnough, errXExpectsTwoArguments, errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, @@ -322,6 +323,8 @@ const errInstantiateXExplicitely: "instantiate '$1' explicitely", errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator", errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", + errDestructorNotGenericEnough: "Destructor signarue is too specific. " & + "A destructor must be associated will all instantiations of a generic type", errXExpectsTwoArguments: "\'$1\' expects two arguments", errXExpectsObjectTypes: "\'$1\' expects object types", errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype", diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim index 6965b36bc..9dbbf2940 100644 --- a/compiler/semdestruct.nim +++ b/compiler/semdestruct.nim @@ -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) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 80327e7eb..f0007d01e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -86,7 +86,7 @@ include semdestruct proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} = if efAllowDestructor notin flags and n.kind in nkCallKinds+{nkObjConstr}: - if instantiateDestructor(c, n.typ): + if instantiateDestructor(c, n.typ) != nil: localError(n.info, errGenerated, "usage of a type with a destructor in a non destructible context") # This still breaks too many things: |