improvements for destructors
This commit is contained in:
parent
d57fe6c904
commit
bb3f648bd2
6 changed files with 91 additions and 35 deletions
|
|
@ -41,7 +41,8 @@ type
|
||||||
inst*: PInstantiation
|
inst*: PInstantiation
|
||||||
|
|
||||||
TExprFlag* = enum
|
TExprFlag* = enum
|
||||||
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType
|
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
|
||||||
|
efAllowDestructor
|
||||||
TExprFlags* = set[TExprFlag]
|
TExprFlags* = set[TExprFlag]
|
||||||
|
|
||||||
PContext* = ref TContext
|
PContext* = ref TContext
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,12 @@ proc semProcvarCheck(c: PContext, n: PNode) =
|
||||||
skConverter}:
|
skConverter}:
|
||||||
performProcvarCheck(c, n, n.sym)
|
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 =
|
proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
# same as 'semExprWithType' but doesn't check for proc vars
|
# same as 'semExprWithType' but doesn't check for proc vars
|
||||||
result = semExpr(c, n, flags)
|
result = semExpr(c, n, flags)
|
||||||
|
|
@ -56,6 +62,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
# XXX tyGenericInst here?
|
# XXX tyGenericInst here?
|
||||||
semProcvarCheck(c, result)
|
semProcvarCheck(c, result)
|
||||||
if result.typ.kind == tyVar: result = newDeref(result)
|
if result.typ.kind == tyVar: result = newDeref(result)
|
||||||
|
semDestructorCheck(c, result, flags)
|
||||||
else:
|
else:
|
||||||
LocalError(n.info, errExprXHasNoType,
|
LocalError(n.info, errExprXHasNoType,
|
||||||
renderTree(result, {renderNoComments}))
|
renderTree(result, {renderNoComments}))
|
||||||
|
|
@ -72,6 +79,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
result.typ = errorType(c)
|
result.typ = errorType(c)
|
||||||
else:
|
else:
|
||||||
semProcvarCheck(c, result)
|
semProcvarCheck(c, result)
|
||||||
|
semDestructorCheck(c, result, flags)
|
||||||
|
|
||||||
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
result = symChoice(c, n, s, scClosed)
|
result = symChoice(c, n, s, scClosed)
|
||||||
|
|
@ -390,7 +398,7 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
|
||||||
typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info)
|
typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info)
|
||||||
result = typ
|
result = typ
|
||||||
|
|
||||||
proc semArrayConstr(c: PContext, n: PNode): PNode =
|
proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result = newNodeI(nkBracket, n.info)
|
result = newNodeI(nkBracket, n.info)
|
||||||
result.typ = newTypeS(tyArrayConstr, c)
|
result.typ = newTypeS(tyArrayConstr, c)
|
||||||
rawAddSon(result.typ, nil) # index type
|
rawAddSon(result.typ, nil) # index type
|
||||||
|
|
@ -419,7 +427,7 @@ proc semArrayConstr(c: PContext, n: PNode): PNode =
|
||||||
localError(x.info, errInvalidOrderInArrayConstructor)
|
localError(x.info, errInvalidOrderInArrayConstructor)
|
||||||
x = x.sons[1]
|
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]))
|
addSon(result, fitNode(c, typ, n.sons[i]))
|
||||||
inc(lastIndex)
|
inc(lastIndex)
|
||||||
addSonSkipIntLit(result.typ, typ)
|
addSonSkipIntLit(result.typ, typ)
|
||||||
|
|
@ -457,7 +465,7 @@ proc fixAbstractType(c: PContext, n: PNode) =
|
||||||
n.sons[i] = it.sons[1]
|
n.sons[i] = it.sons[1]
|
||||||
of nkBracket:
|
of nkBracket:
|
||||||
# an implicitely constructed array (passed to an open array):
|
# an implicitely constructed array (passed to an open array):
|
||||||
n.sons[i] = semArrayConstr(c, it)
|
n.sons[i] = semArrayConstr(c, it, {})
|
||||||
else:
|
else:
|
||||||
nil
|
nil
|
||||||
#if (it.typ == nil):
|
#if (it.typ == nil):
|
||||||
|
|
@ -628,7 +636,7 @@ proc semDirectCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||||
flags: TExprFlags): PNode =
|
flags: TExprFlags): PNode =
|
||||||
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
|
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 =
|
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result = nil
|
result = nil
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
|
|
@ -682,7 +690,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# has side-effects:
|
# has side-effects:
|
||||||
if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
|
if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
|
||||||
elif t != nil and t.kind == tyTypeDesc:
|
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})
|
let destType = t.skipTypes({tyTypeDesc, tyGenericInst})
|
||||||
result = semConv(c, n, symFromType(destType, n.info))
|
result = semConv(c, n, symFromType(destType, n.info))
|
||||||
return
|
return
|
||||||
|
|
@ -1099,11 +1107,13 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
||||||
localError(a.info, errXCannotBeAssignedTo,
|
localError(a.info, errXCannotBeAssignedTo,
|
||||||
renderTree(a, {renderNoComments}))
|
renderTree(a, {renderNoComments}))
|
||||||
else:
|
else:
|
||||||
var
|
let
|
||||||
rhs = semExprWithType(c, n.sons[1])
|
|
||||||
lhs = n.sons[0]
|
lhs = n.sons[0]
|
||||||
if lhs.kind == nkSym and lhs.sym.kind == skResult and
|
lhsIsResult = lhs.kind == nkSym and lhs.sym.kind == skResult
|
||||||
lhs.sym.typ.kind == tyGenericParam:
|
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):
|
if matchTypeClass(lhs.typ, rhs.typ):
|
||||||
InternalAssert c.p.resultSym != nil
|
InternalAssert c.p.resultSym != nil
|
||||||
lhs.typ = rhs.typ
|
lhs.typ = rhs.typ
|
||||||
|
|
@ -1548,7 +1558,7 @@ proc checkPar(n: PNode): TParKind =
|
||||||
LocalError(n.sons[i].info, errNamedExprNotAllowed)
|
LocalError(n.sons[i].info, errNamedExprNotAllowed)
|
||||||
return paNone
|
return paNone
|
||||||
|
|
||||||
proc semTupleFieldsConstr(c: PContext, n: PNode): PNode =
|
proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result = newNodeI(nkPar, n.info)
|
result = newNodeI(nkPar, n.info)
|
||||||
var typ = newTypeS(tyTuple, c)
|
var typ = newTypeS(tyTuple, c)
|
||||||
typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
|
typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
|
||||||
|
|
@ -1562,7 +1572,8 @@ proc semTupleFieldsConstr(c: PContext, n: PNode): PNode =
|
||||||
else: id = n.sons[i].sons[0].sym.name
|
else: id = n.sons[i].sons[0].sym.name
|
||||||
if ContainsOrIncl(ids, id.id):
|
if ContainsOrIncl(ids, id.id):
|
||||||
localError(n.sons[i].info, errFieldInitTwice, id.s)
|
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)
|
var f = newSymS(skField, n.sons[i].sons[0], c)
|
||||||
f.typ = skipIntLit(n.sons[i].sons[1].typ)
|
f.typ = skipIntLit(n.sons[i].sons[1].typ)
|
||||||
rawAddSon(typ, f.typ)
|
rawAddSon(typ, f.typ)
|
||||||
|
|
@ -1571,15 +1582,15 @@ proc semTupleFieldsConstr(c: PContext, n: PNode): PNode =
|
||||||
addSon(result, n.sons[i])
|
addSon(result, n.sons[i])
|
||||||
result.typ = typ
|
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:
|
result = n # we don't modify n, but compute the type:
|
||||||
var typ = newTypeS(tyTuple, c) # leave typ.n nil!
|
var typ = newTypeS(tyTuple, c) # leave typ.n nil!
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
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)
|
addSonSkipIntLit(typ, n.sons[i].typ)
|
||||||
result.typ = 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)
|
var t = semTypeNode(c, n.sons[0], nil)
|
||||||
result = n
|
result = n
|
||||||
result.typ = t
|
result.typ = t
|
||||||
|
|
@ -1600,8 +1611,7 @@ proc semObjConstr(c: PContext, n: PNode): PNode =
|
||||||
else: id = it.sons[0].sym.name
|
else: id = it.sons[0].sym.name
|
||||||
if ContainsOrIncl(ids, id.id):
|
if ContainsOrIncl(ids, id.id):
|
||||||
localError(it.info, errFieldInitTwice, id.s)
|
localError(it.info, errFieldInitTwice, id.s)
|
||||||
var e = semExprWithType(c, it.sons[1])
|
var e = semExprWithType(c, it.sons[1], flags*{efAllowDestructor})
|
||||||
|
|
||||||
var
|
var
|
||||||
check: PNode = nil
|
check: PNode = nil
|
||||||
f: PSym
|
f: PSym
|
||||||
|
|
@ -1830,7 +1840,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
if n.len == 2:
|
if n.len == 2:
|
||||||
result = semConv(c, n, s)
|
result = semConv(c, n, s)
|
||||||
elif n.len == 1:
|
elif n.len == 1:
|
||||||
result = semObjConstr(c, n)
|
result = semObjConstr(c, n, flags)
|
||||||
elif Contains(c.AmbiguousSymbols, s.id):
|
elif Contains(c.AmbiguousSymbols, s.id):
|
||||||
LocalError(n.info, errUseQualifier, s.name.s)
|
LocalError(n.info, errUseQualifier, s.name.s)
|
||||||
elif s.magic == mNone: result = semDirectOp(c, n, flags)
|
elif s.magic == mNone: result = semDirectOp(c, n, flags)
|
||||||
|
|
@ -1869,12 +1879,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of nkPar:
|
of nkPar:
|
||||||
case checkPar(n)
|
case checkPar(n)
|
||||||
of paNone: result = errorNode(c, n)
|
of paNone: result = errorNode(c, n)
|
||||||
of paTuplePositions: result = semTuplePositionsConstr(c, n)
|
of paTuplePositions: result = semTuplePositionsConstr(c, n, flags)
|
||||||
of paTupleFields: result = semTupleFieldsConstr(c, n)
|
of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
|
||||||
of paSingle: result = semExpr(c, n.sons[0], flags)
|
of paSingle: result = semExpr(c, n.sons[0], flags)
|
||||||
of nkCurly: result = semSetConstr(c, n)
|
of nkCurly: result = semSetConstr(c, n)
|
||||||
of nkBracket: result = semArrayConstr(c, n)
|
of nkBracket: result = semArrayConstr(c, n, flags)
|
||||||
of nkObjConstr: result = semObjConstr(c, n)
|
of nkObjConstr: result = semObjConstr(c, n, flags)
|
||||||
of nkLambdaKinds: result = semLambda(c, n, flags)
|
of nkLambdaKinds: result = semLambda(c, n, flags)
|
||||||
of nkDerefExpr: result = semDeref(c, n)
|
of nkDerefExpr: result = semDeref(c, n)
|
||||||
of nkAddr:
|
of nkAddr:
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
typ = nil
|
typ = nil
|
||||||
var def: PNode
|
var def: PNode
|
||||||
if a.sons[length-1].kind != nkEmpty:
|
if a.sons[length-1].kind != nkEmpty:
|
||||||
def = semExprWithType(c, a.sons[length-1])
|
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
|
||||||
# BUGFIX: ``fitNode`` is needed here!
|
# BUGFIX: ``fitNode`` is needed here!
|
||||||
# check type compability between def.typ and typ:
|
# check type compability between def.typ and typ:
|
||||||
if typ != nil: def = fitNode(c, typ, def)
|
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
|
version 0.9.2
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- fix destructors; don't work yet when used as expression; alternative for
|
- document destructors restrictions
|
||||||
version 1: disallow expressions yielding a type with a destructor that are
|
- a project wide override option for 'dynlib'
|
||||||
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``
|
|
||||||
- FFI:
|
- FFI:
|
||||||
* test libffi on windows
|
* test libffi on windows
|
||||||
* test: times.format with the FFI
|
* test: times.format with the FFI
|
||||||
- acyclic vs prunable; introduce GC hints
|
- acyclic vs prunable; introduce GC hints
|
||||||
- CGEN: ``restrict`` pragma + backend support; computed goto support
|
- CGEN: ``restrict`` pragma + backend support; computed goto support
|
||||||
- document NimMain and check whether it works for threading
|
- document NimMain and check whether it works for threading
|
||||||
- a project wide override option for 'dynlib'
|
|
||||||
|
|
||||||
|
|
||||||
Bugs
|
Bugs
|
||||||
|
|
@ -44,6 +39,9 @@ version 0.9.4
|
||||||
- implicit deref for parameter matching; overloading based on 'var T'
|
- implicit deref for parameter matching; overloading based on 'var T'
|
||||||
- ``=`` should be overloadable; requires specialization for ``=``; general
|
- ``=`` should be overloadable; requires specialization for ``=``; general
|
||||||
lift mechanism in the compiler is already implemented for 'fields'
|
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
|
version 0.9.X
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue