From 35c8b5e3bcc13ade6441f1b53ee8d3acacffded3 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 17 Oct 2017 22:04:40 +0200 Subject: [PATCH] destructors: irresponsibly simple tcustomseq test works --- compiler/semasgn.nim | 13 +--- compiler/semtypinst.nim | 5 +- tests/destructor/tcustomseqs.nim | 126 +++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 11 deletions(-) create mode 100644 tests/destructor/tcustomseqs.nim diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 19d31ec736..cb47280977 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -318,16 +318,9 @@ proc overloadedAsgn(c: PContext; dest, src: PNode): PNode = proc liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) = ## In the semantic pass this is called in strategic places ## to ensure we lift assignment, destructors and moves properly. - ## Since this is done in the sem* routines generics already have - ## been resolved for us and do not complicate the logic any further. - ## We have to ensure that the 'tfHasDesctructor' flags bubbles up - ## in the generic instantiations though. ## The later 'destroyer' pass depends on it. if not newDestructors or not hasDestructor(typ): return # we generate the destructor first so that other operators can depend on it: - if typ.destructor == nil: - liftBody(c, typ, attachedDestructor, info) - if typ.assignment == nil: - liftBody(c, typ, attachedAsgn, info) - if typ.sink == nil: - liftBody(c, typ, attachedSink, info) + if typ.destructor == nil: liftBody(c, typ, attachedDestructor, info) + if typ.assignment == nil: liftBody(c, typ, attachedAsgn, info) + if typ.sink == nil: liftBody(c, typ, attachedSink, info) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 5d0f0177cc..3b99ea562a 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -363,7 +363,10 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # '=' needs to be instantiated for generics when the type is constructed: newbody.field = cl.c.instTypeBoundOp(cl.c, opr, result, cl.info, attachedAsgn, 1) - if not newDestructors: typeBound(assignment) + if newDestructors: + typeBound(destructor) + typeBound(sink) + typeBound(assignment) let methods = skipTypes(bbody, abstractPtrs).methods for col, meth in items(methods): # we instantiate the known methods belonging to that type, this causes diff --git a/tests/destructor/tcustomseqs.nim b/tests/destructor/tcustomseqs.nim new file mode 100644 index 0000000000..45059d7def --- /dev/null +++ b/tests/destructor/tcustomseqs.nim @@ -0,0 +1,126 @@ +discard """ + output: '''1 +2 +3 +4 +5 +6 +after 1 1''' + cmd: '''nim c --newruntime $file''' +""" + +import typetraits + +type + myseq*[T] = object + len, cap: int + data: ptr UncheckedArray[T] + +# XXX make code memory safe for overflows in '*' +var + allocCount, deallocCount: int + +proc `=destroy`*[T](x: var myseq[T]) = + if x.data != nil: + when not supportsCopyMem(T): + for i in 0..= x.cap: resize(x) + result = addr(x.data[x.len]) + inc x.len + +template add*[T](x: var seq[T]; y: T) = + reserveSlot(x)[] = y + +proc shrink*[T](x: var myseq[T]; newLen: int) = + assert newLen <= x.len + assert newLen >= 0 + when not supportsCopyMem(T): + for i in countdown(x.len - 1, newLen - 1): + `=destroy`(x.data[i]) + x.len = newLen + +proc grow*[T](x: var myseq[T]; newLen: int; value: T) = + if newLen <= x.len: return + assert newLen >= 0 + if x.cap == 0: x.cap = newLen + else: x.cap = max(newLen, (x.cap * 3) shr 1) + if x.data == nil: inc allocCount + x.data = cast[type(x.data)](realloc(x.data, x.cap * sizeof(T))) + for i in x.len..