mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-29 01:14:41 +00:00
improvements for destructors
This commit is contained in:
@@ -41,7 +41,8 @@ type
|
||||
inst*: PInstantiation
|
||||
|
||||
TExprFlag* = enum
|
||||
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType
|
||||
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
|
||||
efAllowDestructor
|
||||
TExprFlags* = set[TExprFlag]
|
||||
|
||||
PContext* = ref TContext
|
||||
|
||||
@@ -31,6 +31,12 @@ proc semProcvarCheck(c: PContext, n: PNode) =
|
||||
skConverter}:
|
||||
performProcvarCheck(c, n, n.sym)
|
||||
|
||||
proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} =
|
||||
if efAllowDestructor notin flags and n.kind in nkCallKinds+{nkObjConstr}:
|
||||
if instantiateDestructor(c, n.typ):
|
||||
LocalError(n.info, errGenerated,
|
||||
"usage of a type with a destructor in a non destructible context")
|
||||
|
||||
proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
# same as 'semExprWithType' but doesn't check for proc vars
|
||||
result = semExpr(c, n, flags)
|
||||
@@ -56,6 +62,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
# XXX tyGenericInst here?
|
||||
semProcvarCheck(c, result)
|
||||
if result.typ.kind == tyVar: result = newDeref(result)
|
||||
semDestructorCheck(c, result, flags)
|
||||
else:
|
||||
LocalError(n.info, errExprXHasNoType,
|
||||
renderTree(result, {renderNoComments}))
|
||||
@@ -72,6 +79,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
result.typ = errorType(c)
|
||||
else:
|
||||
semProcvarCheck(c, result)
|
||||
semDestructorCheck(c, result, flags)
|
||||
|
||||
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
@@ -390,13 +398,13 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
|
||||
typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info)
|
||||
result = typ
|
||||
|
||||
proc semArrayConstr(c: PContext, n: PNode): PNode =
|
||||
proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = newNodeI(nkBracket, n.info)
|
||||
result.typ = newTypeS(tyArrayConstr, c)
|
||||
rawAddSon(result.typ, nil) # index type
|
||||
if sonsLen(n) == 0:
|
||||
rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
|
||||
else:
|
||||
else:
|
||||
var x = n.sons[0]
|
||||
var lastIndex: biggestInt = 0
|
||||
var indexType = getSysType(tyInt)
|
||||
@@ -419,7 +427,7 @@ proc semArrayConstr(c: PContext, n: PNode): PNode =
|
||||
localError(x.info, errInvalidOrderInArrayConstructor)
|
||||
x = x.sons[1]
|
||||
|
||||
n.sons[i] = semExprWithType(c, x)
|
||||
n.sons[i] = semExprWithType(c, x, flags*{efAllowDestructor})
|
||||
addSon(result, fitNode(c, typ, n.sons[i]))
|
||||
inc(lastIndex)
|
||||
addSonSkipIntLit(result.typ, typ)
|
||||
@@ -457,7 +465,7 @@ proc fixAbstractType(c: PContext, n: PNode) =
|
||||
n.sons[i] = it.sons[1]
|
||||
of nkBracket:
|
||||
# an implicitely constructed array (passed to an open array):
|
||||
n.sons[i] = semArrayConstr(c, it)
|
||||
n.sons[i] = semArrayConstr(c, it, {})
|
||||
else:
|
||||
nil
|
||||
#if (it.typ == nil):
|
||||
@@ -628,7 +636,7 @@ proc semDirectCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||
flags: TExprFlags): PNode =
|
||||
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
||||
|
||||
proc semObjConstr(c: PContext, n: PNode): PNode
|
||||
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = nil
|
||||
checkMinSonsLen(n, 1)
|
||||
@@ -682,7 +690,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# has side-effects:
|
||||
if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
|
||||
elif t != nil and t.kind == tyTypeDesc:
|
||||
if n.len == 1: return semObjConstr(c, n)
|
||||
if n.len == 1: return semObjConstr(c, n, flags)
|
||||
let destType = t.skipTypes({tyTypeDesc, tyGenericInst})
|
||||
result = semConv(c, n, symFromType(destType, n.info))
|
||||
return
|
||||
@@ -1099,11 +1107,13 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
||||
localError(a.info, errXCannotBeAssignedTo,
|
||||
renderTree(a, {renderNoComments}))
|
||||
else:
|
||||
var
|
||||
rhs = semExprWithType(c, n.sons[1])
|
||||
let
|
||||
lhs = n.sons[0]
|
||||
if lhs.kind == nkSym and lhs.sym.kind == skResult and
|
||||
lhs.sym.typ.kind == tyGenericParam:
|
||||
lhsIsResult = lhs.kind == nkSym and lhs.sym.kind == skResult
|
||||
var
|
||||
rhs = semExprWithType(c, n.sons[1],
|
||||
if lhsIsResult: {efAllowDestructor} else: {})
|
||||
if lhsIsResult and lhs.sym.typ.kind == tyGenericParam:
|
||||
if matchTypeClass(lhs.typ, rhs.typ):
|
||||
InternalAssert c.p.resultSym != nil
|
||||
lhs.typ = rhs.typ
|
||||
@@ -1548,21 +1558,22 @@ proc checkPar(n: PNode): TParKind =
|
||||
LocalError(n.sons[i].info, errNamedExprNotAllowed)
|
||||
return paNone
|
||||
|
||||
proc semTupleFieldsConstr(c: PContext, n: PNode): PNode =
|
||||
proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = newNodeI(nkPar, n.info)
|
||||
var typ = newTypeS(tyTuple, c)
|
||||
typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
|
||||
var ids = initIntSet()
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if (n.sons[i].kind != nkExprColonExpr) or
|
||||
not (n.sons[i].sons[0].kind in {nkSym, nkIdent}):
|
||||
not (n.sons[i].sons[0].kind in {nkSym, nkIdent}):
|
||||
illFormedAst(n.sons[i])
|
||||
var id: PIdent
|
||||
if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident
|
||||
else: id = n.sons[i].sons[0].sym.name
|
||||
if ContainsOrIncl(ids, id.id):
|
||||
localError(n.sons[i].info, errFieldInitTwice, id.s)
|
||||
n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1])
|
||||
n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1],
|
||||
flags*{efAllowDestructor})
|
||||
var f = newSymS(skField, n.sons[i].sons[0], c)
|
||||
f.typ = skipIntLit(n.sons[i].sons[1].typ)
|
||||
rawAddSon(typ, f.typ)
|
||||
@@ -1571,15 +1582,15 @@ proc semTupleFieldsConstr(c: PContext, n: PNode): PNode =
|
||||
addSon(result, n.sons[i])
|
||||
result.typ = typ
|
||||
|
||||
proc semTuplePositionsConstr(c: PContext, n: PNode): PNode =
|
||||
proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = n # we don't modify n, but compute the type:
|
||||
var typ = newTypeS(tyTuple, c) # leave typ.n nil!
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
n.sons[i] = semExprWithType(c, n.sons[i])
|
||||
n.sons[i] = semExprWithType(c, n.sons[i], flags*{efAllowDestructor})
|
||||
addSonSkipIntLit(typ, n.sons[i].typ)
|
||||
result.typ = typ
|
||||
|
||||
proc semObjConstr(c: PContext, n: PNode): PNode =
|
||||
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
var t = semTypeNode(c, n.sons[0], nil)
|
||||
result = n
|
||||
result.typ = t
|
||||
@@ -1600,8 +1611,7 @@ proc semObjConstr(c: PContext, n: PNode): PNode =
|
||||
else: id = it.sons[0].sym.name
|
||||
if ContainsOrIncl(ids, id.id):
|
||||
localError(it.info, errFieldInitTwice, id.s)
|
||||
var e = semExprWithType(c, it.sons[1])
|
||||
|
||||
var e = semExprWithType(c, it.sons[1], flags*{efAllowDestructor})
|
||||
var
|
||||
check: PNode = nil
|
||||
f: PSym
|
||||
@@ -1830,7 +1840,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
if n.len == 2:
|
||||
result = semConv(c, n, s)
|
||||
elif n.len == 1:
|
||||
result = semObjConstr(c, n)
|
||||
result = semObjConstr(c, n, flags)
|
||||
elif Contains(c.AmbiguousSymbols, s.id):
|
||||
LocalError(n.info, errUseQualifier, s.name.s)
|
||||
elif s.magic == mNone: result = semDirectOp(c, n, flags)
|
||||
@@ -1869,12 +1879,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of nkPar:
|
||||
case checkPar(n)
|
||||
of paNone: result = errorNode(c, n)
|
||||
of paTuplePositions: result = semTuplePositionsConstr(c, n)
|
||||
of paTupleFields: result = semTupleFieldsConstr(c, n)
|
||||
of paTuplePositions: result = semTuplePositionsConstr(c, n, flags)
|
||||
of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
|
||||
of paSingle: result = semExpr(c, n.sons[0], flags)
|
||||
of nkCurly: result = semSetConstr(c, n)
|
||||
of nkBracket: result = semArrayConstr(c, n)
|
||||
of nkObjConstr: result = semObjConstr(c, n)
|
||||
of nkBracket: result = semArrayConstr(c, n, flags)
|
||||
of nkObjConstr: result = semObjConstr(c, n, flags)
|
||||
of nkLambdaKinds: result = semLambda(c, n, flags)
|
||||
of nkDerefExpr: result = semDeref(c, n)
|
||||
of nkAddr:
|
||||
|
||||
@@ -203,11 +203,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
var typ: PType
|
||||
if a.sons[length-2].kind != nkEmpty:
|
||||
typ = semTypeNode(c, a.sons[length-2], nil)
|
||||
else:
|
||||
else:
|
||||
typ = nil
|
||||
var def: PNode
|
||||
if a.sons[length-1].kind != nkEmpty:
|
||||
def = semExprWithType(c, a.sons[length-1])
|
||||
if a.sons[length-1].kind != nkEmpty:
|
||||
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
|
||||
# BUGFIX: ``fitNode`` is needed here!
|
||||
# check type compability between def.typ and typ:
|
||||
if typ != nil: def = fitNode(c, typ, def)
|
||||
|
||||
21
tests/reject/tdestructor.nim
Normal file
21
tests/reject/tdestructor.nim
Normal file
@@ -0,0 +1,21 @@
|
||||
discard """
|
||||
line: 20
|
||||
errormsg: " usage of a type with a destructor in a non destructible context"
|
||||
"""
|
||||
|
||||
type
|
||||
TMyObj = object
|
||||
x, y: int
|
||||
p: pointer
|
||||
|
||||
proc destruct(o: var TMyObj) {.destructor.} =
|
||||
if o.p != nil: dealloc o.p
|
||||
|
||||
proc open: TMyObj =
|
||||
result = TMyObj(x: 1, y: 2, p: alloc(3))
|
||||
|
||||
|
||||
proc `$`(x: TMyObj): string = $x.y
|
||||
|
||||
echo open()
|
||||
|
||||
26
tests/run/tdestructor.nim
Normal file
26
tests/run/tdestructor.nim
Normal file
@@ -0,0 +1,26 @@
|
||||
discard """
|
||||
output: '''some text
|
||||
Destructor called!'''
|
||||
"""
|
||||
|
||||
type
|
||||
TMyObj = object
|
||||
x, y: int
|
||||
p: pointer
|
||||
|
||||
proc destruct(o: var TMyObj) {.destructor.} =
|
||||
if o.p != nil: dealloc o.p
|
||||
echo "Destructor called!"
|
||||
|
||||
proc open: TMyObj =
|
||||
# allow for superfluous ()
|
||||
result = (TMyObj(x: 1, y: 2, p: alloc(3)))
|
||||
|
||||
|
||||
proc `$`(x: TMyObj): string = $x.y
|
||||
|
||||
proc main() =
|
||||
var x = open()
|
||||
echo "some text"
|
||||
|
||||
main()
|
||||
12
todo.txt
12
todo.txt
@@ -1,19 +1,14 @@
|
||||
version 0.9.2
|
||||
=============
|
||||
|
||||
- fix destructors; don't work yet when used as expression; alternative for
|
||||
version 1: disallow expressions yielding a type with a destructor that are
|
||||
not in a 'let/var' context (p(a.openFile, b.openFile) makes no sense anyway)
|
||||
- lazy overloading resolution:
|
||||
* get rid of ``expr[typ]``, use perhaps ``static[typ]`` instead
|
||||
* special case ``tyStmt``
|
||||
- document destructors restrictions
|
||||
- a project wide override option for 'dynlib'
|
||||
- FFI:
|
||||
* test libffi on windows
|
||||
* test: times.format with the FFI
|
||||
- acyclic vs prunable; introduce GC hints
|
||||
- CGEN: ``restrict`` pragma + backend support; computed goto support
|
||||
- document NimMain and check whether it works for threading
|
||||
- a project wide override option for 'dynlib'
|
||||
|
||||
|
||||
Bugs
|
||||
@@ -44,6 +39,9 @@ version 0.9.4
|
||||
- implicit deref for parameter matching; overloading based on 'var T'
|
||||
- ``=`` should be overloadable; requires specialization for ``=``; general
|
||||
lift mechanism in the compiler is already implemented for 'fields'
|
||||
- lazy overloading resolution:
|
||||
* get rid of ``expr[typ]``, use perhaps ``static[typ]`` instead
|
||||
* special case ``tyStmt``
|
||||
|
||||
|
||||
version 0.9.X
|
||||
|
||||
Reference in New Issue
Block a user