summary refs log tree commit diff stats
path: root/tests/destructor
diff options
context:
space:
mode:
Diffstat (limited to 'tests/destructor')
-rw-r--r--tests/destructor/const_smart_ptr.nim10
-rw-r--r--tests/destructor/nim.cfg1
-rw-r--r--tests/destructor/t12037.nim8
-rw-r--r--tests/destructor/t16607.nim23
-rw-r--r--tests/destructor/t17198.nim32
-rw-r--r--tests/destructor/t23748.nim31
-rw-r--r--tests/destructor/t23837.nim51
-rw-r--r--tests/destructor/t5342.nim24
-rw-r--r--tests/destructor/t7346.nim3
-rw-r--r--tests/destructor/t9440.nim52
-rw-r--r--tests/destructor/tarc.nim15
-rw-r--r--tests/destructor/tarray_indexing.nim4
-rw-r--r--tests/destructor/tatomicptrs.nim15
-rw-r--r--tests/destructor/tbintree2.nim10
-rw-r--r--tests/destructor/tcaseobj_transitions.nim2
-rw-r--r--tests/destructor/tcomplexobjconstr.nim16
-rw-r--r--tests/destructor/tconsume_twice.nim2
-rw-r--r--tests/destructor/tcustomseqs.nim2
-rw-r--r--tests/destructor/tcustomstrings.nim22
-rw-r--r--tests/destructor/tdestructor3.nim79
-rw-r--r--tests/destructor/tdestructor_too_late.nim2
-rw-r--r--tests/destructor/tdistinctseq.nim8
-rw-r--r--tests/destructor/tdont_return_unowned_from_owned.nim37
-rw-r--r--tests/destructor/tgcdestructors.nim2
-rw-r--r--tests/destructor/tglobaldestructor.nim2
-rw-r--r--tests/destructor/tgotoexc_leak.nim19
-rw-r--r--tests/destructor/tgotoexceptions7.nim3
-rw-r--r--tests/destructor/tgotoexceptions8.nim9
-rw-r--r--tests/destructor/tmatrix.nim11
-rw-r--r--tests/destructor/tmisc_destructors.nim6
-rw-r--r--tests/destructor/tmove.nim18
-rw-r--r--tests/destructor/tmove_objconstr.nim44
-rw-r--r--tests/destructor/tnewruntime_misc.nim20
-rw-r--r--tests/destructor/tnewruntime_strutils.nim45
-rw-r--r--tests/destructor/tnonvardestructor.nim247
-rw-r--r--tests/destructor/topttree.nim1
-rw-r--r--tests/destructor/towned_binary_tree.nim2
-rw-r--r--tests/destructor/tprevent_assign.nim2
-rw-r--r--tests/destructor/tprevent_assign2.nim11
-rw-r--r--tests/destructor/tprevent_assign3.nim11
-rw-r--r--tests/destructor/trecursive.nim2
-rw-r--r--tests/destructor/tsimpleclosure.nim2
-rw-r--r--tests/destructor/tsink.nim70
-rw-r--r--tests/destructor/ttuple.nim2
-rw-r--r--tests/destructor/tuse_ownedref_after_move.nim2
-rw-r--r--tests/destructor/tuse_result_prevents_sinks.nim7
-rw-r--r--tests/destructor/tv2_cast.nim99
-rw-r--r--tests/destructor/twasmoved.nim14
-rw-r--r--tests/destructor/twasmoved_error.nim37
49 files changed, 1005 insertions, 132 deletions
diff --git a/tests/destructor/const_smart_ptr.nim b/tests/destructor/const_smart_ptr.nim
index 4d8c7c9a3..25dd46500 100644
--- a/tests/destructor/const_smart_ptr.nim
+++ b/tests/destructor/const_smart_ptr.nim
@@ -2,13 +2,12 @@ type
   ConstPtr*[T] = object
     val: ptr T
 
-proc `=destroy`*[T](p: var ConstPtr[T]) =
+proc `=destroy`*[T](p: ConstPtr[T]) =
   if p.val != nil:
     `=destroy`(p.val[])
     dealloc(p.val)
-    p.val = nil
 
-proc `=`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.error.}
+proc `=copy`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.error.}
 
 proc `=sink`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.inline.} =
   if dest.val != nil and dest.val != src.val:
@@ -31,12 +30,11 @@ type
     len: int
     data: ptr UncheckedArray[float]
 
-proc `=destroy`*(m: var MySeqNonCopyable) {.inline.} =
+proc `=destroy`*(m: MySeqNonCopyable) {.inline.} =
   if m.data != nil:
     deallocShared(m.data)
-    m.data = nil
 
-proc `=`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.error.}
+proc `=copy`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.error.}
 
 proc `=sink`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.inline.} =
   if m.data != m2.data:
diff --git a/tests/destructor/nim.cfg b/tests/destructor/nim.cfg
new file mode 100644
index 000000000..7c148b797
--- /dev/null
+++ b/tests/destructor/nim.cfg
@@ -0,0 +1 @@
+--sinkInference:on
diff --git a/tests/destructor/t12037.nim b/tests/destructor/t12037.nim
index 1a7d536cc..30266690f 100644
--- a/tests/destructor/t12037.nim
+++ b/tests/destructor/t12037.nim
@@ -1,5 +1,5 @@
 discard """
-  cmd: '''nim c --newruntime $file'''
+  cmd: '''nim c --gc:arc $file'''
   output: '''
 showing original type, length, and contents seq[int] 1 @[42]
 copy length and contents 1 @[42]
@@ -9,11 +9,11 @@ copy length and contents 1 @[42]
 proc test() =
   var sq1 = @[42]
   echo "showing original type, length, and contents ", sq1.typeof, " ", sq1.len, " ", sq1
-  doAssert cast[int](sq1[0].unsafeAddr) != 0
+  doAssert cast[int](sq1[0].addr) != 0
   var sq2 = sq1 # copy of original
   echo "copy length and contents ", sq2.len, " ", sq2
-  doAssert cast[int](sq2[0].unsafeAddr) != 0
-  doAssert cast[int](sq1[0].unsafeAddr) != 0
+  doAssert cast[int](sq2[0].addr) != 0
+  doAssert cast[int](sq1[0].addr) != 0
 
 test()
 
diff --git a/tests/destructor/t16607.nim b/tests/destructor/t16607.nim
new file mode 100644
index 000000000..f98a6d517
--- /dev/null
+++ b/tests/destructor/t16607.nim
@@ -0,0 +1,23 @@
+discard """
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+# bug #16607
+
+type
+  O {.requiresInit.} = object
+    initialized: bool
+
+proc `=destroy`(o: var O) =
+  doAssert o.initialized, "O was destroyed before initialization!"
+
+proc initO(): O =
+  O(initialized: true)
+
+proc pair(): tuple[a, b: O] =
+  result = (a: initO(), b: initO())
+
+proc main() =
+  discard pair()
+
+main()
diff --git a/tests/destructor/t17198.nim b/tests/destructor/t17198.nim
new file mode 100644
index 000000000..098db8245
--- /dev/null
+++ b/tests/destructor/t17198.nim
@@ -0,0 +1,32 @@
+discard """
+  cmd: '''nim c --gc:arc $file'''
+  output: '''
+other
+'''
+"""
+
+import std/macros
+
+macro bigCaseStmt(arg: untyped): untyped =
+  result = nnkCaseStmt.newTree(arg)
+
+  # try to change 2000 to a bigger value if it doesn't crash
+  for x in 0 ..< 2000:
+    result.add nnkOfBranch.newTree(newStrLitNode($x), newStrLitNode($x))
+
+  result.add nnkElse.newTree(newStrLitNode("other"))
+
+macro bigIfElseExpr(): untyped =
+  result = nnkIfExpr.newTree()
+
+  for x in 0 ..< 1000:
+    result.add nnkElifExpr.newTree(newLit(false), newStrLitNode($x))
+
+  result.add nnkElseExpr.newTree(newStrLitNode("other"))
+
+proc test(arg: string): string =
+  echo bigIfElseExpr()
+
+  result = bigCaseStmt(arg)
+
+discard test("test")
diff --git a/tests/destructor/t23748.nim b/tests/destructor/t23748.nim
new file mode 100644
index 000000000..a3738733e
--- /dev/null
+++ b/tests/destructor/t23748.nim
@@ -0,0 +1,31 @@
+discard """
+  matrix: "--gc:refc; --gc:arc"
+  output: '''
+hello 42
+hello 42
+len = 2
+'''
+"""
+
+# bug #23748
+
+type
+  O = ref object
+    s: string
+    cb: seq[proc()]
+
+proc push1(o: O, i: int) =
+  let o = o
+  echo o.s, " ", i
+  o.cb.add(proc() = echo o.s, " ", i)
+
+proc push2(o: O, i: int) =
+  let o = o
+  echo o.s, " ", i
+  proc p() = echo o.s, " ", i
+  o.cb.add(p)
+
+let o = O(s: "hello", cb: @[])
+o.push1(42)
+o.push2(42)
+echo "len = ", o.cb.len
diff --git a/tests/destructor/t23837.nim b/tests/destructor/t23837.nim
new file mode 100644
index 000000000..e219dd6b5
--- /dev/null
+++ b/tests/destructor/t23837.nim
@@ -0,0 +1,51 @@
+discard """
+  output: '''
+Deallocating OwnedString
+HelloWorld
+'''
+  matrix: "--cursorinference:on; --cursorinference:off"
+  target: "c"
+"""
+
+# bug #23837
+{.
+  emit: [
+    """
+#include <stdlib.h>
+#include <string.h>
+char *allocCString() {
+    char *result = (char *) malloc(10 + 1);
+    strcpy(result, "HelloWorld");
+    return result;
+}
+
+"""
+  ]
+.}
+
+proc rawWrapper(): cstring {.importc: "allocCString", cdecl.}
+proc free(p: pointer) {.importc: "free", cdecl.}
+
+# -------------------------
+
+type OwnedString = distinct cstring
+
+proc `=destroy`(s: OwnedString) =
+  free(cstring s)
+  echo "Deallocating OwnedString"
+
+func `$`(s: OwnedString): string {.borrow.}
+
+proc leakyWrapper(): string =
+  let ostring = rawWrapper().OwnedString
+  $ostring
+
+# -------------------------
+
+proc main() =
+  # destructor not called - definitely lost: 11 bytes in 1 blocks
+  # doesn't leak with --cursorInference:off
+  let s = leakyWrapper()
+  echo s
+
+main()
\ No newline at end of file
diff --git a/tests/destructor/t5342.nim b/tests/destructor/t5342.nim
new file mode 100644
index 000000000..0acd5ef9d
--- /dev/null
+++ b/tests/destructor/t5342.nim
@@ -0,0 +1,24 @@
+discard """
+  matrix: "--mm:refc; --mm:arc"
+  targets: "c js"
+  output: '''
+1
+2
+here
+2
+1
+'''
+"""
+
+
+type
+  A = object
+    id: int
+  B = object
+    a: A
+proc `=destroy`(a: var A) = echo a.id
+var x = A(id: 1)
+var y = B(a: A(id: 2))
+`=destroy`(x)
+`=destroy`(y)
+echo "here"
\ No newline at end of file
diff --git a/tests/destructor/t7346.nim b/tests/destructor/t7346.nim
index 9e5292a61..3834d39ff 100644
--- a/tests/destructor/t7346.nim
+++ b/tests/destructor/t7346.nim
@@ -2,8 +2,7 @@ discard """
 joinable: false
 """
 
-when not defined(nimNewRuntime):
-  {.error: "This bug could only be reproduced with --newruntime".}
+# This bug could only be reproduced with --newruntime
 
 type
   Obj = object
diff --git a/tests/destructor/t9440.nim b/tests/destructor/t9440.nim
new file mode 100644
index 000000000..153bb303d
--- /dev/null
+++ b/tests/destructor/t9440.nim
@@ -0,0 +1,52 @@
+discard """
+  matrix: "--gc:refc; --gc:orc; --gc:arc"
+  output: '''
+()
+Destroyed
+()
+Destroyed
+()
+Destroyed
+end
+-------------------------
+()
+Destroyed
+end
+'''
+
+"""
+
+# bug #9440
+block:
+  type
+    X = object
+
+  proc `=destroy`(x: var X) =
+    echo "Destroyed"
+
+  proc main() =
+    for x in 0 .. 2:
+      var obj = X()
+      echo obj
+    # The destructor call is invoked after "end" is printed
+    echo "end"
+
+  main()
+
+echo "-------------------------"
+
+block:
+  type
+    X = object
+
+  proc `=destroy`(x: var X) =
+    echo "Destroyed"
+
+  proc main() =
+    block:
+      var obj = X()
+      echo obj
+      # The destructor is not called when obj goes out of scope
+    echo "end"
+
+  main()
diff --git a/tests/destructor/tarc.nim b/tests/destructor/tarc.nim
index 12ea46b2c..54d75a410 100644
--- a/tests/destructor/tarc.nim
+++ b/tests/destructor/tarc.nim
@@ -8,6 +8,8 @@ Hello
 2
 0
 List
+@["4", "5", "6", "", "", "a", ""]
+@["", "", "a", ""]
 '''
   cmd: '''nim c --gc:arc $file'''
 """
@@ -162,10 +164,21 @@ type
     case kind: TagKind
     of List:
       values: seq[Tag]
-    of Compound: 
+    of Compound:
       compound: Table[string, Tag]
 
 var a = Tag(kind: List)
 var b = a
 echo a.kind
 var c = a
+
+proc testAdd(i: int; yyy: openArray[string]) =
+  var x: seq[string]
+  x.add [$i, $(i+1), $(i+2)]
+  x.add yyy
+  echo x
+
+var y = newSeq[string](4)
+y[2] = "a"
+testAdd(4, y)
+echo y
diff --git a/tests/destructor/tarray_indexing.nim b/tests/destructor/tarray_indexing.nim
index 7efd5a00c..a9dfdf4ed 100644
--- a/tests/destructor/tarray_indexing.nim
+++ b/tests/destructor/tarray_indexing.nim
@@ -1,7 +1,7 @@
 discard """
   output: '''allocating 1048576 65536
 filling page from 1048576 len 65536'''
-  cmd: '''nim c --newruntime $file'''
+  cmd: '''nim c --gc:arc $file'''
 """
 
 # bug #12669
@@ -63,7 +63,7 @@ proc fillPages*(mem: UserProcessMemory, start: uint32, data: seq[byte]) =
         #echo cast[uint64](addr mem.pageAccess[i])
         let page = mem.pageAccess[i]
         assert page != nil
-        #copyMem(page, unsafeAddr data[i * 0x1000 - start], 0x1000)
+        #copyMem(page, addr data[i * 0x1000 - start], 0x1000)
 
 const base = 0x00100000
 
diff --git a/tests/destructor/tatomicptrs.nim b/tests/destructor/tatomicptrs.nim
index 7313afbf5..82870ac82 100644
--- a/tests/destructor/tatomicptrs.nim
+++ b/tests/destructor/tatomicptrs.nim
@@ -27,7 +27,7 @@ template decRef(x): untyped = atomicDec(x.refcount)
 
 proc makeShared*[T](x: sink T): SharedPtr[T] =
   # XXX could benefit from a macro that generates it.
-  result = cast[SharedPtr[T]](allocShared(sizeof(x)))
+  result = cast[SharedPtr[T]](allocShared0(sizeof(x)))
   result.x[] = x
   echo "allocating"
 
@@ -39,7 +39,7 @@ proc `=destroy`*[T](dest: var SharedPtr[T]) =
     echo "deallocating"
     dest.x = nil
 
-proc `=`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
+proc `=copy`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
   var s = src.x
   if s != nil: incRef(s)
   #atomicSwap(dest, s)
@@ -50,6 +50,9 @@ proc `=`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
     deallocShared(s)
     echo "deallocating"
 
+proc `=dup`*[T](src: SharedPtr[T]): SharedPtr[T] =
+  `=copy`(result, src)
+
 proc `=sink`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
   ## XXX make this an atomic store:
   if dest.x != src.x:
@@ -72,6 +75,7 @@ template `.=`*[T](s: SharedPtr[T]; field, value: untyped) =
 from macros import unpackVarargs
 
 template `.()`*[T](s: SharedPtr[T]; field: untyped, args: varargs[untyped]): untyped =
+  # xxx this isn't used, the test should be improved
   unpackVarargs(s.x.field, args)
 
 
@@ -119,7 +123,7 @@ proc `=destroy`*[T](m: var MySeq[T]) {.inline.} =
     deallocShared(m.data)
     m.data = nil
 
-proc `=`*[T](m: var MySeq[T], m2: MySeq[T]) =
+proc `=copy`*[T](m: var MySeq[T], m2: MySeq[T]) =
   if m.data == m2.data: return
   if m.data != nil:
     `=destroy`(m)
@@ -130,17 +134,22 @@ proc `=`*[T](m: var MySeq[T], m2: MySeq[T]) =
     m.data = cast[ptr UncheckedArray[T]](allocShared(bytes))
     copyMem(m.data, m2.data, bytes)
 
+proc `=dup`*[T](m: MySeq[T]): MySeq[T] =
+  `=copy`[T](result, m)
+
 proc `=sink`*[T](m: var MySeq[T], m2: MySeq[T]) {.inline.} =
   if m.data != m2.data:
     if m.data != nil:
       `=destroy`(m)
     m.len = m2.len
     m.data = m2.data
+    m.refcount = m2.refcount
 
 proc len*[T](m: MySeq[T]): int {.inline.} = m.len
 
 proc newMySeq*[T](size: int, initial_value: T): MySeq[T] =
   result.len = size
+  result.refcount = 1
   if size > 0:
     result.data = cast[ptr UncheckedArray[T]](allocShared(sizeof(T) * size))
 
diff --git a/tests/destructor/tbintree2.nim b/tests/destructor/tbintree2.nim
index 6fdda6e54..d56c2850b 100644
--- a/tests/destructor/tbintree2.nim
+++ b/tests/destructor/tbintree2.nim
@@ -21,21 +21,21 @@ proc merge(lower, greater: owned Node): owned Node =
   elif greater.isNil:
     result = lower
   elif lower.y < greater.y:
-    lower.right = merge(lower.right, greater)
+    lower.right = merge(move lower.right, greater)
     result = lower
   else:
-    greater.left = merge(lower, greater.left)
+    greater.left = merge(lower, move greater.left)
     result = greater
 
 proc splitBinary(orig: owned Node, value: int32): (owned Node, owned Node) =
   if orig.isNil:
     result = (nil, nil)
   elif orig.x < value:
-    let splitPair = splitBinary(orig.right, value)
+    let splitPair = splitBinary(move orig.right, value)
     orig.right = splitPair[0]
     result = (orig, splitPair[1])
   else:
-    let splitPair = splitBinary(orig.left, value)
+    let splitPair = splitBinary(move orig.left, value)
     orig.left = splitPair[1]
     result = (splitPair[0], orig)
 
@@ -57,7 +57,7 @@ proc `=destroy`(t: var Tree) {.nodestroy.} =
     let x = s.pop
     if x.left != nil: s.add(x.left)
     if x.right != nil: s.add(x.right)
-    dispose(x)
+    `=dispose`(x)
   `=destroy`(s)
 
 proc hasValue(self: var Tree, x: int32): bool =
diff --git a/tests/destructor/tcaseobj_transitions.nim b/tests/destructor/tcaseobj_transitions.nim
index 4e203f4ef..61464101f 100644
--- a/tests/destructor/tcaseobj_transitions.nim
+++ b/tests/destructor/tcaseobj_transitions.nim
@@ -1,5 +1,5 @@
 discard """
-  cmd: '''nim c --newruntime $file'''
+  cmd: '''nim c --gc:arc $file'''
   output: '''no crash'''
 """
 
diff --git a/tests/destructor/tcomplexobjconstr.nim b/tests/destructor/tcomplexobjconstr.nim
index fd112b6e2..aea0ad1fe 100644
--- a/tests/destructor/tcomplexobjconstr.nim
+++ b/tests/destructor/tcomplexobjconstr.nim
@@ -20,16 +20,16 @@ type
     of true: y*: float
 
 var x = new(MyObject2)
-assert x of MyObject2
-assert x.subobj of MyObject1
-assert x.more[2] of MyObject1
-assert x.more[2] of RootObj
+doAssert x of MyObject2
+doAssert x.subobj of MyObject1
+doAssert x.more[2] of MyObject1
+doAssert x.more[2] of RootObj
 
 var y: MyObject2
-assert y of MyObject2
-assert y.subobj of MyObject1
-assert y.more[2] of MyObject1
-assert y.more[2] of RootObj
+doAssert y of MyObject2
+doAssert y.subobj of MyObject1
+doAssert y.more[2] of MyObject1
+doAssert y.more[2] of RootObj
 
 echo "true"
 
diff --git a/tests/destructor/tconsume_twice.nim b/tests/destructor/tconsume_twice.nim
index 0030267f8..b0a039e9b 100644
--- a/tests/destructor/tconsume_twice.nim
+++ b/tests/destructor/tconsume_twice.nim
@@ -1,6 +1,6 @@
 discard """
   cmd: "nim c --newruntime $file"
-  errormsg: "'=' is not available for type <owned Foo>; requires a copy because it's not the last read of 'a'; another read is done here: tconsume_twice.nim(13, 10); routine: consumeTwice"
+  errormsg: "'=copy' is not available for type <owned Foo>; requires a copy because it's not the last read of 'a'; another read is done here: tconsume_twice.nim(13, 10); routine: consumeTwice"
   line: 11
 """
 type
diff --git a/tests/destructor/tcustomseqs.nim b/tests/destructor/tcustomseqs.nim
index 4087dc4a8..17a19f871 100644
--- a/tests/destructor/tcustomseqs.nim
+++ b/tests/destructor/tcustomseqs.nim
@@ -121,7 +121,7 @@ proc createSeq*[T](elems: varargs[T]): myseq[T] =
   result.data = cast[type(result.data)](alloc(result.cap * sizeof(T)))
   inc allocCount
   when supportsCopyMem(T):
-    copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T))
+    copyMem(result.data, addr(elems[0]), result.cap * sizeof(T))
   else:
     for i in 0..<result.len:
       result.data[i] = elems[i]
diff --git a/tests/destructor/tcustomstrings.nim b/tests/destructor/tcustomstrings.nim
index 9ee2da33a..31891856b 100644
--- a/tests/destructor/tcustomstrings.nim
+++ b/tests/destructor/tcustomstrings.nim
@@ -8,8 +8,6 @@ after 20 20'''
 joinable: false
 """
 
-{.this: self.}
-
 type
   mystring = object
     len, cap: int
@@ -51,7 +49,7 @@ proc resize(self: var mystring) =
   if self.cap == 0: self.cap = 8
   else: self.cap = (self.cap * 3) shr 1
   if self.data == nil: inc allocCount
-  self.data = cast[type(data)](realloc(self.data, self.cap + 1))
+  self.data = cast[type(self.data)](realloc(self.data, self.cap + 1))
 
 proc add*(self: var mystring; c: char) =
   if self.len >= self.cap: resize(self)
@@ -60,22 +58,22 @@ proc add*(self: var mystring; c: char) =
   inc self.len
 
 proc ensure(self: var mystring; newLen: int) =
-  if newLen >= cap:
-    cap = max((cap * 3) shr 1, newLen)
-    if cap > 0:
-      if data == nil: inc allocCount
-      data = cast[type(data)](realloc(data, cap + 1))
+  if newLen >= self.cap:
+    self.cap = max((self.cap * 3) shr 1, newLen)
+    if self.cap > 0:
+      if self.data == nil: inc allocCount
+      self.data = cast[type(self.data)](realloc(self.data, self.cap + 1))
 
 proc add*(self: var mystring; y: mystring) =
-  let newLen = len + y.len
+  let newLen = self.len + y.len
   ensure(self, newLen)
-  copyMem(addr data[len], y.data, y.data.len + 1)
-  len = newLen
+  copyMem(addr self.data[self.len], y.data, y.data.len + 1)
+  self.len = newLen
 
 proc create*(lit: string): mystring =
   let newLen = lit.len
   ensure(result, newLen)
-  copyMem(addr result.data[result.len], unsafeAddr lit[0], newLen + 1)
+  copyMem(addr result.data[result.len], addr lit[0], newLen + 1)
   result.len = newLen
 
 proc `&`*(a, b: mystring): mystring =
diff --git a/tests/destructor/tdestructor3.nim b/tests/destructor/tdestructor3.nim
index b68aedce9..3f5eb2cc1 100644
--- a/tests/destructor/tdestructor3.nim
+++ b/tests/destructor/tdestructor3.nim
@@ -1,5 +1,6 @@
 discard """
-  output: '''assign
+  output: '''
+assign
 destroy
 destroy
 5
@@ -22,17 +23,18 @@ joinable: false
 type T = object
 
 proc `=`(lhs: var T, rhs: T) =
-    echo "assign"
+  echo "assign"
 
 proc `=destroy`(v: var T) =
-    echo "destroy"
+  echo "destroy"
 
 proc use(x: T) = discard
 
 proc usedToBeBlock =
-    var v1 : T
-    var v2 : T = v1
-    use v1
+  var v1 = T()
+  var v2: T = v1
+  discard addr(v2) # prevent cursorfication
+  use v1
 
 usedToBeBlock()
 
@@ -104,12 +106,12 @@ test()
 #------------------------------------------------------------
 # Issue #12883
 
-type 
+type
   TopObject = object
     internal: UniquePtr[int]
 
 proc deleteTop(p: ptr TopObject) =
-  if p != nil:    
+  if p != nil:
     `=destroy`(p[]) # !!! this operation used to leak the integer
     deallocshared(p)
 
@@ -117,12 +119,67 @@ proc createTop(): ptr TopObject =
   result = cast[ptr TopObject](allocShared0(sizeof(TopObject)))
   result.internal = newUniquePtr(1)
 
-proc test2() = 
+proc test2() =
   let x = createTop()
   echo $x.internal
   deleteTop(x)
 
-echo "---------------"  
+echo "---------------"
 echo "app begin"
 test2()
-echo "app end"
\ No newline at end of file
+echo "app end"
+
+# bug #14601
+
+when true: # D20200607T202043
+  type Foo2 = object
+    x: int
+    x2: array[10, int]
+
+  type Vec = object
+    vals: seq[Foo2]
+
+  proc `=destroy`*(a: var Foo2) {.inline.} =
+    discard
+
+  proc initFoo2(x: int): Foo2 = Foo2(x: x)
+
+  proc add2(v: var Vec, a: Foo2) = # ditto with `a: sink Foo2`
+    v.vals.add a
+
+  proc add3(v: var Vec, a: Foo2) = # ditto with `a: sink Foo2`
+    v.vals = @[a]
+
+  proc add4(v: var Vec, a: sink Foo2) = # ditto with `a: sink Foo2`
+    v.vals.add a
+
+  proc add5(v: var Vec, a: sink Foo2) = # ditto with `a: sink Foo2`
+    v.vals = @[a]
+
+  proc main2()=
+    var a: Vec
+    var b = Foo2(x: 10)
+    a.add2 b # ok
+    a.vals.add Foo2(x: 10) # ok
+    a.add2 initFoo2(x = 10) # ok
+    a.add2 Foo2(x: 10) # bug
+    a.add3 initFoo2(x = 10) # ok
+    a.add3 Foo2(x: 10) # bug
+    a.add4 initFoo2(x = 10) # ok
+    a.add4 Foo2(x: 10) # bug
+    a.add5 initFoo2(x = 10) # ok
+    a.add5 Foo2(x: 10) # bug
+  main2()
+
+
+
+#------------------------------------------------------------
+# Issue #15825
+
+type
+  Union = string | int | char
+
+proc run(a: sink Union) =
+  discard
+
+run("123")
diff --git a/tests/destructor/tdestructor_too_late.nim b/tests/destructor/tdestructor_too_late.nim
index d279280ba..76d1dde84 100644
--- a/tests/destructor/tdestructor_too_late.nim
+++ b/tests/destructor/tdestructor_too_late.nim
@@ -1,5 +1,5 @@
 discard """
-  errmsg: "cannot bind another '=destroy' to: Obj; previous declaration was constructed here implicitly: tdestructor_too_late.nim(7, 16)"
+  errormsg: "cannot bind another '=destroy' to: Obj; previous declaration was constructed here implicitly: tdestructor_too_late.nim(7, 16)"
 """
 type Obj* = object
   v*: int
diff --git a/tests/destructor/tdistinctseq.nim b/tests/destructor/tdistinctseq.nim
new file mode 100644
index 000000000..5a2ac5ead
--- /dev/null
+++ b/tests/destructor/tdistinctseq.nim
@@ -0,0 +1,8 @@
+discard """
+  matrix: "-u:nimPreviewNonVarDestructor;"
+"""
+type DistinctSeq* = distinct seq[int]
+
+# `=destroy`(cast[ptr DistinctSeq](0)[])
+var x = @[].DistinctSeq
+`=destroy`(x)
diff --git a/tests/destructor/tdont_return_unowned_from_owned.nim b/tests/destructor/tdont_return_unowned_from_owned.nim
index a726960c6..ffe87cd76 100644
--- a/tests/destructor/tdont_return_unowned_from_owned.nim
+++ b/tests/destructor/tdont_return_unowned_from_owned.nim
@@ -1,8 +1,12 @@
 discard """
   cmd: "nim check --newruntime --hints:off $file"
-  nimout: '''tdont_return_unowned_from_owned.nim(36, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type
-tdont_return_unowned_from_owned.nim(39, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type
-tdont_return_unowned_from_owned.nim(42, 6) Error: type mismatch: got <Obj>
+  nimout: '''
+tdont_return_unowned_from_owned.nim(26, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref
+tdont_return_unowned_from_owned.nim(27, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref
+tdont_return_unowned_from_owned.nim(31, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type
+tdont_return_unowned_from_owned.nim(43, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type
+tdont_return_unowned_from_owned.nim(46, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type
+tdont_return_unowned_from_owned.nim(49, 6) Error: type mismatch: got <Obj>
 but expected one of:
 proc new[T](a: var ref T; finalizer: proc (x: ref T) {.nimcall.})
   first type mismatch at position: 2
@@ -10,18 +14,21 @@ proc new[T](a: var ref T; finalizer: proc (x: ref T) {.nimcall.})
 2 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them
 
 expression: new(result)
-tdont_return_unowned_from_owned.nim(42, 6) Error: illformed AST:
-tdont_return_unowned_from_owned.nim(50, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref
-tdont_return_unowned_from_owned.nim(51, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref
-tdont_return_unowned_from_owned.nim(55, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type
+tdont_return_unowned_from_owned.nim(49, 6) Error: illformed AST: 
 '''
-  errormsg: "cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type"
-  line: 55
+  errormsg: "illformed AST:"
 """
 
 
 
+proc testA(result: var (RootRef, RootRef)) =
+  let r: owned RootRef = RootRef()
+  result[0] = r
+  result[1] = RootRef()
 
+proc testB(): RootRef =
+  let r: owned RootRef = RootRef()
+  result = r
 
 
 
@@ -39,17 +46,11 @@ proc newObjB(): Obj =
   result = Obj()
 
 proc newObjC(): Obj =
-  new(result)
+  new(result) # illFormedAst raises GlobalError,
+              # without pipeline parsing, it needs to placed at the end
+              # in case that it disturbs other errors
 
 let a = newObjA()
 let b = newObjB()
 let c = newObjC()
 
-proc testA(result: var (RootRef, RootRef)) =
-  let r: owned RootRef = RootRef()
-  result[0] = r
-  result[1] = RootRef()
-
-proc testB(): RootRef =
-  let r: owned RootRef = RootRef()
-  result = r
diff --git a/tests/destructor/tgcdestructors.nim b/tests/destructor/tgcdestructors.nim
index 4731bf694..07a3731a0 100644
--- a/tests/destructor/tgcdestructors.nim
+++ b/tests/destructor/tgcdestructors.nim
@@ -1,5 +1,5 @@
 discard """
-  cmd: '''nim c -d:nimAllocStats --newruntime $file'''
+  cmd: '''nim c -d:nimAllocStats --gc:arc $file'''
   output: '''hi
 ho
 ha
diff --git a/tests/destructor/tglobaldestructor.nim b/tests/destructor/tglobaldestructor.nim
index 403f670a0..4d002a092 100644
--- a/tests/destructor/tglobaldestructor.nim
+++ b/tests/destructor/tglobaldestructor.nim
@@ -1,5 +1,5 @@
 discard """
-  cmd: '''nim c --newruntime $file'''
+  cmd: '''nim c --gc:arc $file'''
   output: '''(v: 42)
 igotdestroyed'''
 """
diff --git a/tests/destructor/tgotoexc_leak.nim b/tests/destructor/tgotoexc_leak.nim
new file mode 100644
index 000000000..c8a234085
--- /dev/null
+++ b/tests/destructor/tgotoexc_leak.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''0
+true'''
+  cmd: "nim c --gc:arc $file"
+"""
+
+# bug #22398
+
+for i in 0 ..< 10_000:
+  try:
+    try:
+      raise newException(ValueError, "")
+    except CatchableError:
+      discard
+      raise newException(ValueError, "") # or raise getCurrentException(), just raise works ok
+  except ValueError:
+    discard
+echo getOccupiedMem()
+echo getCurrentException() == nil
diff --git a/tests/destructor/tgotoexceptions7.nim b/tests/destructor/tgotoexceptions7.nim
index 6e564a044..c04bd6ba0 100644
--- a/tests/destructor/tgotoexceptions7.nim
+++ b/tests/destructor/tgotoexceptions7.nim
@@ -25,7 +25,8 @@ proc helper = doAssert(false)
 
 proc main(i: int) =
   var obj = Obj(kind: kindA, s: "abc")
-  obj.kind = kindB
+  {.cast(uncheckedAssign).}:
+    obj.kind = kindB
   obj.i = 2
   try:
     var objA = ObjA()
diff --git a/tests/destructor/tgotoexceptions8.nim b/tests/destructor/tgotoexceptions8.nim
index e968cdce2..8ed2ed0ba 100644
--- a/tests/destructor/tgotoexceptions8.nim
+++ b/tests/destructor/tgotoexceptions8.nim
@@ -8,7 +8,8 @@ outer finally
 msg1
 msg2
 finally2
-finally1'''
+finally1
+true'''
   cmd: "nim c --gc:arc $file"
 """
 
@@ -67,3 +68,9 @@ when true:
       echo "finally1"
 
   nested_finally()
+
+# bug #14925
+proc test(b: bool) =
+  echo b
+
+test(try: true except: false)
diff --git a/tests/destructor/tmatrix.nim b/tests/destructor/tmatrix.nim
index a3bd59df3..2fd5af789 100644
--- a/tests/destructor/tmatrix.nim
+++ b/tests/destructor/tmatrix.nim
@@ -31,7 +31,7 @@ proc `=sink`*(a: var Matrix; b: Matrix) =
   a.m = b.m
   a.n = b.n
 
-proc `=`*(a: var Matrix; b: Matrix) =
+proc `=copy`*(a: var Matrix; b: Matrix) =
   if a.data != nil and a.data != b.data:
     dealloc(a.data)
     deallocCount.inc
@@ -43,6 +43,9 @@ proc `=`*(a: var Matrix; b: Matrix) =
     allocCount.inc
     copyMem(a.data, b.data, b.m * b.n * sizeof(float))
 
+proc `=dup`*(a: Matrix): Matrix =
+  `=copy`(result, a)
+
 proc matrix*(m, n: int, s: float): Matrix =
   ## Construct an m-by-n constant matrix.
   result.m = m
@@ -96,14 +99,16 @@ proc info =
   allocCount = 0
   deallocCount = 0
 
+proc copy(a: Matrix): Matrix = a
+
 proc test1 =
   var a = matrix(5, 5, 1.0)
-  var b = a
+  var b = copy a
   var c = a + b
 
 proc test2 =
   var a = matrix(5, 5, 1.0)
-  var b = a
+  var b = copy a
   var c = -a
 
 proc test3 =
diff --git a/tests/destructor/tmisc_destructors.nim b/tests/destructor/tmisc_destructors.nim
index 73c54eab3..082cb0f78 100644
--- a/tests/destructor/tmisc_destructors.nim
+++ b/tests/destructor/tmisc_destructors.nim
@@ -21,11 +21,13 @@ proc `=sink`(dest: var Foo, src: Foo) =
 proc `=`(dest: var Foo, src: Foo) =
   assign_counter.inc
 
+proc createFoo(): Foo = Foo(boo: 0)
+
 proc test(): auto =
-  var a, b: Foo
+  var a, b = createFoo()
   return (a, b, Foo(boo: 5))
 
-var (a, b, _) = test()
+var (ag, bg, _) = test()
 
 doAssert assign_counter == 0
 doAssert sink_counter == 0
diff --git a/tests/destructor/tmove.nim b/tests/destructor/tmove.nim
new file mode 100644
index 000000000..2762aff90
--- /dev/null
+++ b/tests/destructor/tmove.nim
@@ -0,0 +1,18 @@
+discard """
+  targets: "c cpp"
+"""
+
+block:
+  var called = 0
+
+  proc bar(a: var int): var int =
+    inc called
+    result = a
+
+  proc foo =
+    var a = 2
+    var s = move bar(a)
+    doAssert called == 1
+    doAssert s == 2
+
+  foo()
diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim
index 5366f4957..cdc1eb1c0 100644
--- a/tests/destructor/tmove_objconstr.nim
+++ b/tests/destructor/tmove_objconstr.nim
@@ -2,14 +2,13 @@
 discard """
 output:  '''test created
 test destroyed 0
-Pony is dying!
 1
 2
 3
 4
 Pony is dying!'''
 joinable: false
-target: "C"
+targets: "c"
 """
 
 # bug #4214
@@ -51,7 +50,7 @@ proc `=destroy`(o: var Pony) =
   echo "Pony is dying!"
 
 proc getPony: Pony =
-  result.name = "Sparkles"
+  result = Pony(name: "Sparkles")
 
 iterator items(p: Pony): int =
   for i in 1..4:
@@ -113,7 +112,7 @@ proc myfunc2(x, y: int): tuple[a: MySeqNonCopyable, b:int, c:MySeqNonCopyable] =
   var cc = newMySeq(y, 5.0)
   (a: case x:
     of 1:
-      let (z1, z2) = myfunc(x,y)
+      let (z1, z2) = myfunc(x, y)
       z2
     elif x > 5: raise newException(ValueError, "new error")
     else: newMySeq(x, 1.0),
@@ -138,28 +137,29 @@ doAssert seq3[0] == 1.0
 var seq4, seq5: MySeqNonCopyable
 (seq4, i, seq5) = myfunc2(2, 3)
 
-seq4 = block:
-  var tmp = newMySeq(4, 1.0)
-  tmp[0] = 3.0
-  tmp
+proc foo =
+  seq4 = block:
+    var tmp = newMySeq(4, 1.0)
+    tmp[0] = 3.0
+    tmp
 
-doAssert seq4[0] == 3.0
+  doAssert seq4[0] == 3.0
 
-import macros
 
-seq4 =
-  if i > 0: newMySeq(2, 5.0)
-  elif i < -100: raise newException(ValueError, "Parse Error")
-  else: newMySeq(2, 3.0)
+  seq4 =
+    if i > 0: newMySeq(2, 5.0)
+    elif i < -100: raise newException(ValueError, "Parse Error")
+    else: newMySeq(2, 3.0)
 
-seq4 =
-  case (char) i:
-    of 'A', {'W'..'Z'}: newMySeq(2, 5.0)
-    of 'B': quit(-1)
-    else:
-      let (x1, x2, x3) = myfunc2(2, 3)
-      x3
+  seq4 =
+    case (char) i:
+      of 'A', {'W'..'Z'}: newMySeq(2, 5.0)
+      of 'B': quit(-1)
+      else:
+        let (x1, x2, x3) = myfunc2(2, 3)
+        x3
 
+foo()
 
 #------------------------------------------------------------
 #-- Move into array constructor
@@ -179,7 +179,7 @@ proc myfuncLoop(x: int): MySeqNonCopyable =
 discard myfuncLoop(3)
 
 #------------------------------------------------------------
-# Move into table via openarray
+# Move into table via openArray
 #------------------------------------------------------------
 
 type
diff --git a/tests/destructor/tnewruntime_misc.nim b/tests/destructor/tnewruntime_misc.nim
index 1a5b0e3b0..21c70557d 100644
--- a/tests/destructor/tnewruntime_misc.nim
+++ b/tests/destructor/tnewruntime_misc.nim
@@ -7,7 +7,7 @@ axc
 ...
 destroying GenericObj[T] GenericObj[system.int]
 test
-(allocCount: 13, deallocCount: 11)
+(allocCount: 12, deallocCount: 10)
 3'''
 """
 
@@ -25,8 +25,13 @@ putEnv("HEAPTRASHING", "Indeed")
 
 let s1 = getAllocStats()
 
+
+proc newTableOwned[A, B](initialSize = defaultInitialSize): owned(TableRef[A, B]) =
+  new(result)
+  result[] = initTable[A, B](initialSize)
+
 proc main =
-  var w = newTable[string, owned Node]()
+  var w = newTableOwned[string, owned Node]()
   w["key"] = Node(field: "value")
   echo w["key"][]
   echo getEnv("HEAPTRASHING")
@@ -132,7 +137,16 @@ proc xx(xml: string): MyObject =
 
 
 discard xx("test")
-echo getAllocStats() - s1
+
+# Windows has 1 extra allocation in `getEnv` - there it allocates parameter to
+# `_wgetenv` (WideCString). Therefore subtract by 1 to match other OSes'
+# allocation.
+when defined(windows):
+  import std/importutils
+  privateAccess(AllocStats)
+  echo getAllocStats() - s1 - AllocStats(allocCount: 1, deallocCount: 1)
+else:
+  echo getAllocStats() - s1
 
 # bug #13457
 var s = "abcde"
diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim
index b0bceb4b5..9c8d41973 100644
--- a/tests/destructor/tnewruntime_strutils.nim
+++ b/tests/destructor/tnewruntime_strutils.nim
@@ -1,8 +1,12 @@
 discard """
   valgrind: true
-  cmd: '''nim c -d:nimAllocStats --newruntime -d:useMalloc $file'''
+  cmd: '''nim c -d:nimAllocStats --gc:arc -d:useMalloc $file'''
   output: '''
-@[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])]'''
+@[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])]
+14
+First tasks completed.
+Second tasks completed.
+test1'''
 """
 
 import strutils, os, std / wordwrap
@@ -211,3 +215,40 @@ staticTests()
 # bug #12965
 let xaa = @[""].join()
 let xbb = @["", ""].join()
+
+# bug #16365
+
+# Task 1:
+when true:
+  # Task 1_a:
+  var test_string_a = "name_something"
+  echo test_string_a.len()
+  let new_len_a = test_string_a.len - "_something".len()
+  test_string_a.setLen new_len_a
+
+  echo "First tasks completed."
+
+# Task 2:
+when true:
+  # Task 2_a
+  var test_string: string
+  let some_string = "something"
+  for i in some_string.items:
+    test_string.add $i
+
+  # Task 2_b
+  var test_string_b = "name_something"
+  let new_len_b = test_string_b.len - "_something".len()
+  test_string_b.setLen new_len_b
+
+  echo "Second tasks completed."
+
+# bug #17450
+proc main =
+  var i = 1
+  echo:
+    block:
+      "test" & $i
+
+main()
+
diff --git a/tests/destructor/tnonvardestructor.nim b/tests/destructor/tnonvardestructor.nim
new file mode 100644
index 000000000..1b4413790
--- /dev/null
+++ b/tests/destructor/tnonvardestructor.nim
@@ -0,0 +1,247 @@
+discard """

+  targets: "c cpp"

+  matrix: "--mm:arc; --mm:orc"

+"""

+

+block:

+  type

+    PublicKey = array[32, uint8]

+    PrivateKey = array[64, uint8]

+

+  proc ed25519_create_keypair(publicKey: ptr PublicKey; privateKey: ptr PrivateKey) =

+    publicKey[][0] = uint8(88)

+

+  type

+    KeyPair = object

+      public: PublicKey

+      private: PrivateKey

+

+  proc initKeyPair(): KeyPair =

+    ed25519_create_keypair(result.public.addr, result.private.addr)

+

+  let keys = initKeyPair()

+  doAssert keys.public[0] == 88

+

+

+template minIndexByIt: untyped =

+  var other = 3

+  other

+

+proc bug20303() =

+  var hlibs = @["hello", "world", "how", "are", "you"]

+  let res = hlibs[minIndexByIt()]

+  doAssert res == "are"

+

+bug20303()

+

+proc main() = # todo bug with templates

+  block: # bug #11267

+    var a: seq[char] = block: @[]

+    doAssert a == @[]

+    # 2

+    proc b: seq[string] =

+      discard

+      @[]

+    doAssert b() == @[]

+static: main()

+main()

+

+

+type Obj = tuple

+  value: int

+  arr: seq[int]

+

+proc bug(): seq[Obj] =

+  result.add (value: 0, arr: @[])

+  result[^1].value = 1

+  result[^1].arr.add 1

+

+# bug #19990

+let s = bug()

+doAssert s[0] == (value: 1, arr: @[1])

+

+block: # bug #21974

+  type Test[T] = ref object

+      values : seq[T]

+      counter: int

+

+  proc newTest[T](): Test[T] =

+      result         = new(Test[T])

+      result.values  = newSeq[T](16)

+      result.counter = 0

+

+  proc push[T](self: Test[T], value: T) =

+      self.counter += 1

+      if self.counter >= self.values.len:

+          self.values.setLen(self.values.len * 2)

+      self.values[self.counter - 1] = value

+

+  proc pop[T](self: Test[T]): T =

+      result         = self.values[0]

+      self.values[0] = self.values[self.counter - 1] # <--- This line

+      self.counter  -= 1

+

+

+  type X = tuple

+      priority: int

+      value   : string

+

+  var a = newTest[X]()

+  a.push((1, "One"))

+  doAssert a.pop.value == "One"

+

+# bug #21987

+

+type

+  EmbeddedImage* = distinct Image

+  Image = object

+    len: int

+

+proc imageCopy*(image: Image): Image {.nodestroy.}

+

+proc `=destroy`*(x: Image) =

+  discard

+

+proc `=sink`*(dest: var Image; source: Image) =

+  `=destroy`(dest)

+  wasMoved(dest)

+

+proc `=dup`*(source: Image): Image {.nodestroy.} =

+  result = imageCopy(source)

+

+proc `=copy`*(dest: var Image; source: Image) =

+  dest = imageCopy(source) # calls =sink implicitly

+

+proc `=destroy`*(x: EmbeddedImage) = discard

+

+proc `=dup`*(source: EmbeddedImage): EmbeddedImage {.nodestroy.} = source

+

+proc `=copy`*(dest: var EmbeddedImage; source: EmbeddedImage) {.nodestroy.} =

+  dest = source

+

+proc imageCopy*(image: Image): Image =

+  result = image

+

+proc main2 =

+  block:

+    var a = Image(len: 2).EmbeddedImage

+    var b = Image(len: 1).EmbeddedImage

+    b = a

+    doAssert Image(a).len == 2

+    doAssert Image(b).len == 2

+

+  block:

+    var a = Image(len: 2)

+    var b = Image(len: 1)

+    b = a

+    doAssert a.len == 2

+    doAssert b.len == 0

+

+main2()

+

+type

+  Edge = object

+    neighbor {.cursor.}: Node

+

+  NodeObj = object

+    neighbors: seq[Edge]

+    label: string

+    visited: bool

+  Node = ref NodeObj

+

+  Graph = object

+    nodes: seq[Node]

+

+proc `=destroy`(x: NodeObj) =

+  `=destroy`(x.neighbors)

+  `=destroy`(x.label)

+

+proc addNode(self: var Graph; label: string): Node =

+  self.nodes.add(Node(label: label))

+  result = self.nodes[^1]

+

+proc addEdge(self: Graph; source, neighbor: Node) =

+  source.neighbors.add(Edge(neighbor: neighbor))

+

+block:

+  proc main =

+    var graph: Graph

+    let nodeA = graph.addNode("a")

+    let nodeB = graph.addNode("b")

+    let nodeC = graph.addNode("c")

+

+    graph.addEdge(nodeA, neighbor = nodeB)

+    graph.addEdge(nodeA, neighbor = nodeC)

+

+  main()

+

+block:

+  type RefObj = ref object

+

+  proc `[]`(val: static[int]) = # works with different name/overload or without static arg

+    discard

+

+  template noRef(T: typedesc): typedesc = # works without template indirection

+    typeof(default(T)[])

+

+  proc `=destroy`(x: noRef(RefObj)) =

+    discard

+

+  proc foo =

+    var x = new RefObj

+    doAssert $(x[]) == "()"

+

+  # bug #11705

+  foo()

+

+block: # bug #22197

+  type

+    H5IdObj = object

+    H5Id = ref H5IdObj

+

+    FileID = distinct H5Id

+

+    H5GroupObj = object

+      file_id: FileID

+    H5Group = ref H5GroupObj

+

+  ## This would make it work!

+  #proc `=destroy`*(x: FileID) = `=destroy`(cast[H5Id](x))

+  ## If this does not exist, it also works!

+  proc newFileID(): FileID = FileID(H5Id())

+

+  proc `=destroy`(grp: H5GroupObj) =

+    ## Closes the group and resets all references to nil.

+    if cast[pointer](grp.fileId) != nil:

+      `=destroy`(grp.file_id)

+

+  var grp = H5Group()

+  reset(grp.file_id)

+  reset(grp)

+

+import std/tables

+

+block: # bug #22286

+  type

+    A = object

+    B = object

+      a: A

+    C = object

+      b: B

+

+  proc `=destroy`(self: A) =

+    echo "destroyed"

+

+  proc `=destroy`(self: C) =

+    `=destroy`(self.b)

+

+  var c = C()

+

+block: # https://forum.nim-lang.org/t/10642

+  type AObj = object

+    name: string

+    tableField: Table[string, string]

+

+  proc `=destroy`(x: AObj) =

+    `=destroy`(x.name)

+    `=destroy`(x.tableField)

diff --git a/tests/destructor/topttree.nim b/tests/destructor/topttree.nim
index fa5495689..8cf757e8b 100644
--- a/tests/destructor/topttree.nim
+++ b/tests/destructor/topttree.nim
@@ -1,4 +1,5 @@
 discard """
+  disabled: i386
   output: '''10.0
 60.0
 90.0
diff --git a/tests/destructor/towned_binary_tree.nim b/tests/destructor/towned_binary_tree.nim
index 320e33759..fb635e7c6 100644
--- a/tests/destructor/towned_binary_tree.nim
+++ b/tests/destructor/towned_binary_tree.nim
@@ -1,5 +1,5 @@
 discard """
-  cmd: '''nim c -d:nimAllocStats --newruntime $file'''
+  cmd: '''nim c -d:nimAllocStats --gc:arc $file'''
   output: '''31665
 (allocCount: 33334, deallocCount: 33334)'''
 """
diff --git a/tests/destructor/tprevent_assign.nim b/tests/destructor/tprevent_assign.nim
index 108ccc371..4c484ebc1 100644
--- a/tests/destructor/tprevent_assign.nim
+++ b/tests/destructor/tprevent_assign.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
+  errormsg: "'=copy' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
   line: 29
 """
 
diff --git a/tests/destructor/tprevent_assign2.nim b/tests/destructor/tprevent_assign2.nim
index 0e4481710..eb5588b1a 100644
--- a/tests/destructor/tprevent_assign2.nim
+++ b/tests/destructor/tprevent_assign2.nim
@@ -1,7 +1,7 @@
 discard """
-  errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
+  errormsg: "'=dup' is not available for type <Foo>, which is inferred from unavailable '=copy'; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(51, 31); routine: preventThis"
   file: "tprevent_assign2.nim"
-  line: 48
+  line: 49
 """
 
 type
@@ -9,7 +9,8 @@ type
     x: int
 
 proc `=destroy`(f: var Foo) = f.x = 0
-proc `=`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
+proc `=copy`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
+
 proc `=sink`(a: var Foo; b: Foo) = a.x = b.x
 
 proc createTree(x: int): Foo =
@@ -18,7 +19,7 @@ proc createTree(x: int): Foo =
 proc take2(a, b: sink Foo) =
   echo a.x, " ", b.x
 
-proc allowThis() =
+when false:
   var otherTree: Foo
   try:
     for i in 0..3:
@@ -51,5 +52,5 @@ proc preventThis() =
       else:
         discard
 
-allowThis()
+#allowThis()
 preventThis()
diff --git a/tests/destructor/tprevent_assign3.nim b/tests/destructor/tprevent_assign3.nim
index a8a35ea5e..aa834a66c 100644
--- a/tests/destructor/tprevent_assign3.nim
+++ b/tests/destructor/tprevent_assign3.nim
@@ -1,7 +1,7 @@
 discard """
-  errormsg: "'=' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
+  errormsg: "'=dup' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
   file: "tprevent_assign3.nim"
-  line: 46
+  line: 47
 """
 
 type
@@ -9,7 +9,8 @@ type
     x: int
 
 proc `=destroy`(f: var Foo) = f.x = 0
-proc `=`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
+proc `=copy`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
+proc `=dup`(a: Foo): Foo {.error.}
 proc `=sink`(a: var Foo; b: Foo) = a.x = b.x
 
 proc createTree(x: int): Foo =
@@ -18,7 +19,7 @@ proc createTree(x: int): Foo =
 proc take2(a, b: sink Foo) =
   echo a.x, " ", b.x
 
-proc allowThis() =
+when false:
   var otherTree: Foo
   try:
     for i in 0..3:
@@ -47,7 +48,7 @@ proc preventThis2() =
   finally:
     echo otherTree
 
-allowThis()
+#allowThis()
 preventThis2()
 
 
diff --git a/tests/destructor/trecursive.nim b/tests/destructor/trecursive.nim
index 17a40e5a9..e7afa6ba9 100644
--- a/tests/destructor/trecursive.nim
+++ b/tests/destructor/trecursive.nim
@@ -47,7 +47,7 @@ proc `=destroy`(x: var MyObject) =
 proc `=`(x: var MyObject, y: MyObject) {.error.}
 
 proc newMyObject(i: int): MyObject = 
-  result.p = create(int)
+  result.p = createShared(int)
   result.p[] = i
 
 proc test: seq[MyObject] = 
diff --git a/tests/destructor/tsimpleclosure.nim b/tests/destructor/tsimpleclosure.nim
index 35c57a634..9626dd6f8 100644
--- a/tests/destructor/tsimpleclosure.nim
+++ b/tests/destructor/tsimpleclosure.nim
@@ -1,5 +1,5 @@
 discard """
-  cmd: '''nim c -d:nimAllocStats --newruntime $file'''
+  cmd: '''nim c -d:nimAllocStats --gc:arc $file'''
   output: '''a b
 70
 hello
diff --git a/tests/destructor/tsink.nim b/tests/destructor/tsink.nim
new file mode 100644
index 000000000..e8750ad7c
--- /dev/null
+++ b/tests/destructor/tsink.nim
@@ -0,0 +1,70 @@
+discard """
+  matrix: "--mm:arc"
+"""
+
+type AnObject = object of RootObj
+  value*: int
+
+proc mutate(shit: sink AnObject) =
+  shit.value = 1
+
+proc foo = # bug #23359
+  var bar = AnObject(value: 42)
+  mutate(bar)
+  doAssert bar.value == 42
+
+foo()
+
+block: # bug #23902
+  proc foo(a: sink string): auto = (a, a)
+
+  proc bar(a: sink int): auto = return a
+
+  proc foo(a: sink string) =
+    var x = (a, a)
+
+block: # bug #24175
+  block:
+    func mutate(o: sink string): string =
+      o[1] = '1'
+      result = o
+
+    static:
+      let s = "999"
+      let m = mutate(s)
+      doAssert s == "999"
+      doAssert m == "919"
+
+    func foo() =
+      let s = "999"
+      let m = mutate(s)
+      doAssert s == "999"
+      doAssert m == "919"
+
+    static:
+      foo()
+    foo()
+
+  block:
+    type O = object
+      a: int
+
+    func mutate(o: sink O): O =
+      o.a += 1
+      o
+
+    static:
+      let x = O(a: 1)
+      let y = mutate(x)
+      doAssert x.a == 1
+      doAssert y.a == 2
+
+    proc foo() =
+      let x = O(a: 1)
+      let y = mutate(x)
+      doAssert x.a == 1
+      doAssert y.a == 2
+
+    static:
+      foo()
+    foo()
diff --git a/tests/destructor/ttuple.nim b/tests/destructor/ttuple.nim
index 5a2126105..d0ea72c60 100644
--- a/tests/destructor/ttuple.nim
+++ b/tests/destructor/ttuple.nim
@@ -2,7 +2,7 @@
 discard """
    output: '''5.0 10.0
 =destroy
-=destroy   
+=destroy
 '''
 """
 
diff --git a/tests/destructor/tuse_ownedref_after_move.nim b/tests/destructor/tuse_ownedref_after_move.nim
index 46540837c..69348d530 100644
--- a/tests/destructor/tuse_ownedref_after_move.nim
+++ b/tests/destructor/tuse_ownedref_after_move.nim
@@ -1,6 +1,6 @@
 discard """
   cmd: '''nim c --newruntime $file'''
-  errormsg: "'=' is not available for type <owned Button>; requires a copy because it's not the last read of ':envAlt.b1'; another read is done here: tuse_ownedref_after_move.nim(52, 4)"
+  errormsg: "'=copy' is not available for type <owned Button>; requires a copy because it's not the last read of ':envAlt.b1'; routine: main"
   line: 48
 """
 
diff --git a/tests/destructor/tuse_result_prevents_sinks.nim b/tests/destructor/tuse_result_prevents_sinks.nim
index 37b5af9b2..e74c16da3 100644
--- a/tests/destructor/tuse_result_prevents_sinks.nim
+++ b/tests/destructor/tuse_result_prevents_sinks.nim
@@ -1,6 +1,6 @@
 discard """
   output: ""
-  target: "C"
+  targets: "c"
 """
 
 # bug #9594
@@ -17,15 +17,20 @@ proc `=sink`(self: var Foo; other: Foo) =
 
 proc `=destroy`(self: var Foo) = discard
 
+template preventCursorInference(x) =
+  let p = addr(x)
+
 proc test(): Foo =
   result = Foo()
   let temp = result
+  preventCursorInference temp
   doAssert temp.i > 0
   return result
 
 proc testB(): Foo =
   result = Foo()
   let temp = result
+  preventCursorInference temp
   doAssert temp.i > 0
 
 discard test()
diff --git a/tests/destructor/tv2_cast.nim b/tests/destructor/tv2_cast.nim
index 9c05b2ae1..48bdf67dd 100644
--- a/tests/destructor/tv2_cast.nim
+++ b/tests/destructor/tv2_cast.nim
@@ -1,10 +1,81 @@
 discard """
-  cmd: '''nim c --newruntime $file'''
   output: '''@[1]
 @[116, 101, 115, 116]
-@[1953719668, 875770417]'''
+@[1953719668, 875770417]
+destroying O1'''
+  cmd: '''nim c --mm:arc --expandArc:main --expandArc:main1 --expandArc:main2 --expandArc:main3 --hints:off --assertions:off $file'''
+  nimout: '''
+--expandArc: main
+
+var
+  data
+  :tmpD
+data = cast[string](encode(cast[seq[byte]](
+  :tmpD = newString(100)
+  :tmpD)))
+`=destroy`(:tmpD)
+`=destroy`(data)
+-- end of expandArc ------------------------
+--expandArc: main1
+
+var
+  s
+  data
+s = newString(100)
+data = cast[string](encode(toOpenArrayByte(s, 0, len(s) - 1)))
+`=destroy`(data)
+`=destroy`(s)
+-- end of expandArc ------------------------
+--expandArc: main2
+
+var
+  s
+  data
+s = newSeq(100)
+data = cast[string](encode(s))
+`=destroy`(data)
+`=destroy_1`(s)
+-- end of expandArc ------------------------
+--expandArc: main3
+
+var
+  data
+  :tmpD
+data = cast[string](encode do:
+  :tmpD = newSeq(100)
+  :tmpD)
+`=destroy`(:tmpD)
+`=destroy_1`(data)
+-- end of expandArc ------------------------
+'''
 """
 
+func encode*(src: openArray[byte]): seq[byte] =
+  result = newSeq[byte](src.len)
+
+template compress*(src: string): string =
+  cast[string](encode(cast[seq[byte]](src)))
+
+proc main =
+  let data = compress(newString(100))
+main()
+
+proc main1 =
+  var
+    s = newString(100)
+  let data = cast[string](encode(s.toOpenArrayByte(0, s.len-1)))
+main1()
+
+proc main2 =
+  var
+    s = newSeq[byte](100)
+  let data = cast[string](encode(s))
+main2()
+
+proc main3 =
+  let data = cast[string](encode(newSeq[byte](100)))
+main3()
+
 # bug #11018
 discard cast[seq[uint8]](@[1])
 discard cast[seq[uint8]]("test")
@@ -20,4 +91,26 @@ echo a
 
 #issue 11204
 var ac {.compileTime.} = @["a", "b"]
-const bc = ac.len
\ No newline at end of file
+const bc = ac.len
+
+
+type
+  O = object of RootRef
+    i: int
+
+  O1 = object of O
+  O2 = object of O
+
+proc `=destroy`(o: var O) =
+  echo "destroying O"
+
+proc `=destroy`(o: var O1) =
+  echo "destroying O1"
+
+proc `=destroy`(o: var O2) =
+  echo "destroying O2"
+
+proc test =
+  let o3 = cast[ref O2]((ref O1)())
+
+test()
diff --git a/tests/destructor/twasmoved.nim b/tests/destructor/twasmoved.nim
new file mode 100644
index 000000000..566322702
--- /dev/null
+++ b/tests/destructor/twasmoved.nim
@@ -0,0 +1,14 @@
+type
+  Foo = object
+    id: int
+
+proc `=wasMoved`(x: var Foo) =
+  x.id = -1
+
+proc foo =
+  var s = Foo(id: 999)
+  var m = move s
+  doAssert s.id == -1
+  doAssert m.id == 999
+
+foo()
diff --git a/tests/destructor/twasmoved_error.nim b/tests/destructor/twasmoved_error.nim
new file mode 100644
index 000000000..1cd57e3df
--- /dev/null
+++ b/tests/destructor/twasmoved_error.nim
@@ -0,0 +1,37 @@
+discard """
+  cmd: '''nim c --mm:arc $file'''
+  errormsg: "'=wasMoved' is not available for type <Game>; routine: main"
+"""
+
+# bug #19291
+
+const
+  screenWidth = 800
+  screenHeight = 450
+
+var
+  ready = false
+type
+  Game = object
+
+proc `=destroy`(x: var Game) =
+  assert ready, "Window is already opened"
+  ready = false
+
+proc `=sink`(x: var Game; y: Game) {.error.}
+proc `=copy`(x: var Game; y: Game) {.error.}
+proc `=wasMoved`(x: var Game) {.error.}
+
+proc initGame(width, height: int32, title: string): Game =
+  assert not ready, "Window is already closed"
+  ready = true
+
+proc update(x: Game) = discard
+
+proc main =
+  var g = initGame(screenWidth, screenHeight, "Tetris raylib")
+  g.update()
+  var g2 = g
+  echo "hello"
+
+main()