diff options
-rw-r--r-- | compiler/semasgn.nim | 7 | ||||
-rw-r--r-- | tests/destructor/tbintree.nim | 97 |
2 files changed, 100 insertions, 4 deletions
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 857c9a1e0..895946281 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -287,16 +287,15 @@ proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp; if kind != attachedDestructor: result.typ.addParam src - # recursion is handled explicitly, but register the type based operation - # here in order to keep things robust against runaway recursions: + liftBodyAux(a, typ, body, newSymNode(dest).newDeref, newSymNode(src)) + # recursion is handled explicitly, do not register the type based operation + # before 'liftBodyAux': case kind of attachedAsgn: typ.assignment = result of attachedSink: typ.sink = result of attachedDeepCopy: typ.deepCopy = result of attachedDestructor: typ.destructor = result - liftBodyAux(a, typ, body, newSymNode(dest).newDeref, newSymNode(src)) - var n = newNodeI(nkProcDef, info, bodyPos+1) for i in 0 .. < n.len: n.sons[i] = emptyNode n.sons[namePos] = newSymNode(result) diff --git a/tests/destructor/tbintree.nim b/tests/destructor/tbintree.nim new file mode 100644 index 000000000..12ba052cf --- /dev/null +++ b/tests/destructor/tbintree.nim @@ -0,0 +1,97 @@ +discard """ + output: '''10.0 +60.0 +90.0 +120.0 +4 1''' + cmd: '''nim c --newruntime $file''' +""" + +import typetraits + +type + opt[T] = object + data: ptr T + +var + allocCount, deallocCount: int + +proc `=destroy`*[T](x: var opt[T]) = + if x.data != nil: + when not supportsCopyMem(T): + `=destroy`(x.data) + dealloc(x.data) + inc deallocCount + x.data = nil + +proc `=`*[T](a: var opt[T]; b: opt[T]) = + if a.data == b.data: return + if a.data != nil: + dealloc(a.data) + inc deallocCount + a.data = nil + if b.data != nil: + a.data = cast[type(a.data)](alloc(sizeof(T))) + inc allocCount + when supportsCopyMem(T): + copyMem(a.data, b.data, sizeof(T)) + else: + a.data[] = b.data[] + +proc `=sink`*[T](a: var opt[T]; b: opt[T]) = + if a.data != nil and a.data != b.data: + dealloc(a.data) + inc deallocCount + a.data = b.data + +proc createOpt*[T](x: T): opt[T] = + result.data = cast[type(result.data)](alloc(sizeof(T))) + inc allocCount + result.data[] = x + +template `[]`[T](x: opt[T]): T = + assert x.p != nil, "attempt to read from moved/destroyed value" + x.p[] + +template `?=`[T](it: untyped; x: opt[T]): bool = + template it: untyped {.inject.} = x.data[] + if x.data != nil: + true + else: + false + +type + Tree = object + data: float + le, ri: opt[Tree] + +proc createTree(data: float): Tree = + result.data = data + +proc insert(t: var opt[Tree]; newVal: float) = + if it ?= t: + if it.data > newVal: + insert(it.le, newVal) + elif it.data < newVal: + insert(it.ri, newVal) + else: + discard "already in the tree" + else: + t = createOpt(Tree(data: newVal)) + +proc write(t: opt[Tree]) = + if it ?= t: + write(it.le) + write stdout, it.data, "\n" + write(it.ri) + +proc main = + var t: opt[Tree] + insert t, 60.0 + insert t, 90.0 + insert t, 10.0 + insert t, 120.0 + write t + +main() +echo allocCount, " ", deallocCount |