summary refs log tree commit diff stats
path: root/tests/arc
diff options
context:
space:
mode:
Diffstat (limited to 'tests/arc')
-rw-r--r--tests/arc/t17812.nim12
-rw-r--r--tests/arc/t18645.nim18
-rw-r--r--tests/arc/t18977.nim26
-rw-r--r--tests/arc/t19231.nim18
-rw-r--r--tests/arc/t19364.nim30
-rw-r--r--tests/arc/t19862.nim2
-rw-r--r--tests/arc/t20456.nim7
-rw-r--r--tests/arc/t20588.nim25
-rw-r--r--tests/arc/t21184.nim77
-rw-r--r--tests/arc/t22218.nim25
-rw-r--r--tests/arc/t22237.nim55
-rw-r--r--tests/arc/t22478.nim46
-rw-r--r--tests/arc/t22787.nim37
-rw-r--r--tests/arc/t23247.nim52
-rw-r--r--tests/arc/taliased_reassign.nim41
-rw-r--r--tests/arc/tarc_macro.nim57
-rw-r--r--tests/arc/tarc_orc.nim151
-rw-r--r--tests/arc/tarcmisc.nim349
-rw-r--r--tests/arc/tasyncleak.nim2
-rw-r--r--tests/arc/tcaseobj.nim115
-rw-r--r--tests/arc/tcaseobjcopy.nim23
-rw-r--r--tests/arc/tcomputedgoto.nim15
-rw-r--r--tests/arc/tcomputedgotocopy.nim11
-rw-r--r--tests/arc/tcontrolflow.nim2
-rw-r--r--tests/arc/tdup.nim71
-rw-r--r--tests/arc/texplicit_sink.nim29
-rw-r--r--tests/arc/thard_alignment.nim4
-rw-r--r--tests/arc/titeration_doesnt_copy.nim67
-rw-r--r--tests/arc/tmalloc.nim16
-rw-r--r--tests/arc/tmove_regression.nim22
-rw-r--r--tests/arc/tmovebug.nim25
-rw-r--r--tests/arc/topenarray.nim62
-rw-r--r--tests/arc/topt_no_cursor.nim72
-rw-r--r--tests/arc/topt_refcursors.nim8
-rw-r--r--tests/arc/topt_wasmoved_destroy_pairs.nim14
-rw-r--r--tests/arc/trepr.nim8
-rw-r--r--tests/arc/tstringliteral.nim17
-rw-r--r--tests/arc/tweave.nim3
-rw-r--r--tests/arc/twrong_sinkinference.nim2
39 files changed, 1536 insertions, 80 deletions
diff --git a/tests/arc/t17812.nim b/tests/arc/t17812.nim
index bcd5f3a93..dd8ac89b0 100644
--- a/tests/arc/t17812.nim
+++ b/tests/arc/t17812.nim
@@ -27,3 +27,15 @@ block: # bug #17812
     proc `$`(o: MyObj): string = o.repr
 
     doAssert ($MyObj()).len > 0
+
+# bug #22175
+
+type Xxx = object
+  value: string
+
+proc complete(xxx: ref Xxx, v: sink string) =
+  xxx.value = move(v)
+
+let yyy = (ref Xxx)()
+
+yyy.complete("test")
diff --git a/tests/arc/t18645.nim b/tests/arc/t18645.nim
new file mode 100644
index 000000000..c5fddd4bb
--- /dev/null
+++ b/tests/arc/t18645.nim
@@ -0,0 +1,18 @@
+discard """
+  matrix: "--gc:arc; --gc:refc"
+  output: '''
+1
+2
+3
+'''
+"""
+
+proc bitTypeIdUnion() =
+  var bitId {.global.} = block:
+    0
+  inc bitId
+  echo bitId
+
+bitTypeIdUnion()
+bitTypeIdUnion()
+bitTypeIdUnion()
diff --git a/tests/arc/t18977.nim b/tests/arc/t18977.nim
new file mode 100644
index 000000000..c775551a4
--- /dev/null
+++ b/tests/arc/t18977.nim
@@ -0,0 +1,26 @@
+discard """
+  matrix: "--mm:arc"
+"""
+
+type
+  E = enum
+    a, b, c, d
+  X = object
+    v: int
+  O = object
+    case kind: E
+    of a:
+      a: int
+    of {b, c}:
+      b: float
+    else:
+      d: X
+
+proc `=destroy`(x: var X) =
+  echo "x destroyed"
+
+var o = O(kind: d, d: X(v: 12345))
+doAssert o.d.v == 12345
+
+doAssertRaises(FieldDefect):
+  o.kind = a
diff --git a/tests/arc/t19231.nim b/tests/arc/t19231.nim
new file mode 100644
index 000000000..40fcf277c
--- /dev/null
+++ b/tests/arc/t19231.nim
@@ -0,0 +1,18 @@
+discard """
+  matrix: "--mm:orc"
+  targets: "c cpp"
+"""
+
+type
+  Game* = ref object
+
+proc free*(game: Game) =
+  var mixNumOpened:cint = 0
+  for i in 0..<mixNumOpened:
+    mixNumOpened -= 1
+
+proc newGame*(): Game =
+  new result, free
+
+var
+  game*: Game
diff --git a/tests/arc/t19364.nim b/tests/arc/t19364.nim
new file mode 100644
index 000000000..f520f3291
--- /dev/null
+++ b/tests/arc/t19364.nim
@@ -0,0 +1,30 @@
+discard """
+  cmd: '''nim c --gc:arc --expandArc:fooLeaks $file'''
+  nimout: '''
+--expandArc: fooLeaks
+
+var
+  tmpTuple_cursor
+  a_cursor
+  b_cursor
+  c_cursor
+tmpTuple_cursor = refTuple
+a_cursor = tmpTuple_cursor[0]
+b_cursor = tmpTuple_cursor[1]
+c_cursor = tmpTuple_cursor[2]
+-- end of expandArc ------------------------
+'''
+"""
+
+func fooLeaks(refTuple: tuple[a,
+                              b,
+                              c: seq[float]]): float =
+  let (a, b, c) = refTuple
+
+let refset = (a: newSeq[float](25_000_000),
+              b: newSeq[float](25_000_000),
+              c: newSeq[float](25_000_000))
+
+var res = newSeq[float](1_000_000)
+for i in 0 .. res.high:
+  res[i] = fooLeaks(refset)
diff --git a/tests/arc/t19862.nim b/tests/arc/t19862.nim
index f7146ec26..6d3f57692 100644
--- a/tests/arc/t19862.nim
+++ b/tests/arc/t19862.nim
@@ -2,6 +2,8 @@ discard """
   matrix: "--gc:refc; --gc:arc"
 """
 
+import std/widestrs
+
 # bug #19862
 type NewString = object
 
diff --git a/tests/arc/t20456.nim b/tests/arc/t20456.nim
new file mode 100644
index 000000000..ace79255a
--- /dev/null
+++ b/tests/arc/t20456.nim
@@ -0,0 +1,7 @@
+discard """
+  cmd: "nim check $file"
+  action: "compile"
+"""
+
+when not defined(gcOrc):
+  {.error: "orc".}
diff --git a/tests/arc/t20588.nim b/tests/arc/t20588.nim
new file mode 100644
index 000000000..008bd1dcd
--- /dev/null
+++ b/tests/arc/t20588.nim
@@ -0,0 +1,25 @@
+discard """
+  cmd: "nim check --warnings:off --hints:off $file"
+  errormsg: ""
+  nimout: '''
+t20588.nim(20, 12) Error: illegal type conversion to 'auto'
+t20588.nim(21, 14) Error: illegal type conversion to 'typed'
+t20588.nim(22, 16) Error: illegal type conversion to 'untyped'
+t20588.nim(24, 7) Error: illegal type conversion to 'any'
+'''
+"""
+
+
+
+
+
+
+
+
+
+discard 0.0.auto
+discard typed("abc")
+discard untyped(4)
+var a = newSeq[bool](1000)
+if any(a):
+  echo "ok?"
\ No newline at end of file
diff --git a/tests/arc/t21184.nim b/tests/arc/t21184.nim
new file mode 100644
index 000000000..91d0c42c7
--- /dev/null
+++ b/tests/arc/t21184.nim
@@ -0,0 +1,77 @@
+discard """
+  matrix: "--mm:orc"
+"""
+
+import std/[with]
+
+type
+  Node* {.acyclic.} = ref object of RootObj
+    name: string
+    data: pointer
+    children: seq[Node]
+  TextNode = ref object of Node
+    text: string
+
+proc fakeEcho(s: string) =
+  if s.len < 0:
+    echo s
+
+proc newNode[T: Node](parent: Node): T =
+  new result
+  result.data = alloc0(250)
+  parent.children.add(result)
+
+proc newRootNode(): Node =
+  new result
+  result.data = alloc0(250)
+
+method printNode(node: Node) {.base.} =
+  fakeEcho node.name
+
+method printNode(node: TextNode) =
+  procCall printNode(Node(node))
+  fakeEcho node.text
+
+proc printChildren(node: Node) =
+  for child in node.children:
+    child.printNode()
+    printChildren(child)
+
+proc free(node: Node) =
+  for child in node.children:
+    free(child)
+  dealloc(node.data)
+
+template node(parent: Node, body: untyped): untyped =
+  var node = newNode[Node](parent)
+  with node:
+    body
+
+proc textNode(parent: Node, text: string) =
+  var node = newNode[TextNode](parent)
+  node.text = text
+
+template withRootNode(body: untyped): untyped =
+  var root = newRootNode()
+  root.name = "root"
+  with root:
+    body
+  root.printNode()
+  printChildren(root)
+  root.free()
+
+proc doTest() =
+  withRootNode:
+    node:
+      name = "child1"
+      node:
+        name = "child2"
+        node:
+          name = "child3"
+          textNode "Hello, world!"
+
+
+# bug #21171
+if isMainModule:
+  for i in 0..100000:
+    doTest()
diff --git a/tests/arc/t22218.nim b/tests/arc/t22218.nim
new file mode 100644
index 000000000..7837ed1d0
--- /dev/null
+++ b/tests/arc/t22218.nim
@@ -0,0 +1,25 @@
+discard """
+  cmd: "nim c --mm:arc $file"
+  errormsg: "'=copy' is not available for type <Obj>; requires a copy because it's not the last read of 'chan[]'; routine: test"
+"""
+
+# bug #22218
+type Obj[T] = object
+  v: T
+
+proc `=copy`[T](
+    dest: var Obj[T],
+    source: Obj[T]
+  ) {.error: "A channel cannot be copied".}
+
+from system/ansi_c import c_calloc
+
+proc test() =
+    var v: bool = true
+    var chan = cast[ptr Obj[int]](c_calloc(1, csize_t sizeof(Obj[int])))
+    var copy = chan[]
+
+    echo chan.v
+    echo v
+
+test()
\ No newline at end of file
diff --git a/tests/arc/t22237.nim b/tests/arc/t22237.nim
new file mode 100644
index 000000000..c6dbf768a
--- /dev/null
+++ b/tests/arc/t22237.nim
@@ -0,0 +1,55 @@
+discard """
+  matrix: "--mm:arc; --mm:orc"
+"""
+
+import std/macros
+import std/streams
+
+# bug #22237
+
+proc iterlines_closure2(f: File | Stream): iterator (): string =
+  result = iterator(): string =
+    for line in f.lines:
+      if line.len == 0:
+        break
+      yield line
+
+proc test() =
+  let f = newStringStream("""
+    1
+    2
+
+    3
+    4
+
+    5
+    6
+    7
+
+    8
+""")
+  while not f.atEnd():
+    let iterator_inst = iterlines_closure2(f)
+    for item in iterator_inst(): # Fails with "SIGSEGV: Illegal storage access. (Attempt to read from nil?)"
+      discard
+
+test()
+
+# bug #21160
+import sequtils
+
+iterator allMoves(fls: seq[int]): seq[int] =
+  yield fls
+
+proc neighbors(flrs: seq[int]): iterator: seq[int] =
+  return iterator(): seq[int] =
+    for flrs2 in allMoves(flrs):
+      yield flrs2
+      for flrs3 in allMoves(flrs2):
+        yield flrs3
+
+let f = @[1]
+for _ in neighbors(f):
+  discard
+for _ in neighbors(f):
+  discard
diff --git a/tests/arc/t22478.nim b/tests/arc/t22478.nim
new file mode 100644
index 000000000..5373fa161
--- /dev/null
+++ b/tests/arc/t22478.nim
@@ -0,0 +1,46 @@
+discard """
+  matrix: "-d:nimNoLentIterators --mm:arc"
+  output: '''PUSH DATA: {"test.message":{"test":{"nested":"v1"}}}'''
+  joinable: false
+"""
+
+# bug #22748
+import std/[json, typetraits, times]
+
+# publish
+
+proc publish*[T](payload: T) =
+  discard
+
+type MetricsPoint* = JsonNode
+
+proc push*(stat: string, data: JsonNode, usec: int64 = 0) =
+  let payload = newJObject()
+
+  # this results in a infinite recursion unless we deepCopy()
+  payload[stat] = data #.deepCopy
+
+  echo "PUSH DATA: ", payload
+
+  publish[MetricsPoint](payload)
+
+var scopes {.threadvar.}: seq[JsonNode]
+
+type WithTimeCallback*[T] = proc(data: var JsonNode): T
+
+proc pushScoped*[T](metric: string, blk: WithTimeCallback[T]): T {.gcsafe.} =
+  scopes.add newJObject()
+  defer: discard scopes.pop()
+
+  let stc = (cpuTime() * 1000_000).int64
+  result = blk(scopes[^1])
+  let dfc = (cpuTime() * 1000_000).int64 - stc
+
+  push(metric, scopes[^1], dfc)
+
+# demo code
+
+discard pushScoped[int]("test.message") do (data: var JsonNode) -> int:
+  data["test"] = %*{
+    "nested": "v1"
+  }
\ No newline at end of file
diff --git a/tests/arc/t22787.nim b/tests/arc/t22787.nim
new file mode 100644
index 000000000..5840a984b
--- /dev/null
+++ b/tests/arc/t22787.nim
@@ -0,0 +1,37 @@
+discard """
+  joinable: false
+"""
+
+import std/assertions
+
+proc foo =
+  var s:seq[string]
+  var res = ""
+
+  for i in 0..3:
+    s.add ("test" & $i)
+    s.add ("test" & $i)
+
+  var lastname:string
+
+  for i in s:
+    var name = i[0..4]
+
+    if name != lastname:
+      res.add "NEW:" & name & "\n"
+    else:
+      res.add name & ">" & lastname & "\n"
+
+    lastname = name
+
+  doAssert res == """
+NEW:test0
+test0>test0
+NEW:test1
+test1>test1
+NEW:test2
+test2>test2
+NEW:test3
+test3>test3
+"""
+foo()
\ No newline at end of file
diff --git a/tests/arc/t23247.nim b/tests/arc/t23247.nim
new file mode 100644
index 000000000..0fadc50cd
--- /dev/null
+++ b/tests/arc/t23247.nim
@@ -0,0 +1,52 @@
+discard """
+  matrix: ";-d:useMalloc"
+"""
+
+# bug #23247
+import std/hashes
+
+func baseAddr[T](x: openArray[T]): ptr T =
+  # Return the address of the zero:th element of x or `nil` if x is empty
+  if x.len == 0: nil else: cast[ptr T](x)
+
+func makeUncheckedArray[T](p: ptr T): ptr UncheckedArray[T] =
+  cast[ptr UncheckedArray[T]](p)
+
+type
+  LabelKey = object
+    data: seq[string]
+    refs: ptr UncheckedArray[string]
+    refslen: int
+
+  Gauge = ref object
+    metrics: seq[seq[seq[string]]]
+
+template values(key: LabelKey): openArray[string] =
+  if key.refslen > 0:
+    key.refs.toOpenArray(0, key.refslen - 1)
+  else:
+    key.data
+
+proc hash(key: LabelKey): Hash =
+  hash(key.values)
+
+proc view(T: type LabelKey, values: openArray[string]): T =
+  # TODO some day, we might get view types - until then..
+  LabelKey(refs: baseAddr(values).makeUncheckedArray(), refslen: values.len())
+
+template withValue2(k: untyped) =
+  discard hash(k)
+
+proc setGauge(
+    collector: Gauge,
+    labelValues: openArray[string],
+) =
+  let v = LabelKey.view(labelValues)
+  withValue2(v)
+  collector.metrics.add @[@labelValues, @labelValues]
+  discard @labelValues
+
+var nim_gc_mem_bytes = Gauge()
+let threadID = $getThreadId()
+setGauge(nim_gc_mem_bytes, @[threadID])
+setGauge(nim_gc_mem_bytes, @[threadID])
\ No newline at end of file
diff --git a/tests/arc/taliased_reassign.nim b/tests/arc/taliased_reassign.nim
new file mode 100644
index 000000000..5563fae8c
--- /dev/null
+++ b/tests/arc/taliased_reassign.nim
@@ -0,0 +1,41 @@
+discard """
+  matrix: "--mm:orc"
+"""
+
+# bug #20993
+
+type
+  Dual[int] = object # must be generic (even if fully specified)
+    p: int
+proc D(p: int): Dual[int] = Dual[int](p: p)
+proc `+`(x: Dual[int], y: Dual[int]): Dual[int] = D(x.p + y.p)
+
+type
+  Tensor[T] = object
+    buf: seq[T]
+proc newTensor*[T](s: int): Tensor[T] = Tensor[T](buf: newSeq[T](s))
+proc `[]`*[T](t: Tensor[T], idx: int): T = t.buf[idx]
+proc `[]=`*[T](t: var Tensor[T], idx: int, val: T) = t.buf[idx] = val
+
+proc `+.`[T](t1, t2: Tensor[T]): Tensor[T] =
+  let n = t1.buf.len
+  result = newTensor[T](n)
+  for i in 0 ..< n:
+    result[i] = t1[i] + t2[i]
+
+proc toTensor*[T](a: sink seq[T]): Tensor[T] =
+  ## This breaks it: Using `T` instead makes it work
+  type U = typeof(a[0])
+  var t: Tensor[U] # Tensor[T] works
+  t.buf = a
+  result = t
+
+proc loss() =
+  var B = toTensor(@[D(123)])
+  let a = toTensor(@[D(-10)])
+  B = B +. a
+  doAssert B[0].p == 113, "I want to be 113, but I am " & $B[0].p
+
+loss()
+
+
diff --git a/tests/arc/tarc_macro.nim b/tests/arc/tarc_macro.nim
new file mode 100644
index 000000000..33ade1da4
--- /dev/null
+++ b/tests/arc/tarc_macro.nim
@@ -0,0 +1,57 @@
+import macros
+
+var destroyCalled = false
+macro bar() =
+  let s = newTree(nnkAccQuoted, ident"=destroy")
+  # let s = ident"`=destroy`" # this would not work
+  result = quote do:
+    type Foo = object
+    # proc `=destroy`(a: var Foo) = destroyCalled = true # this would not work
+    proc `s`(a: var Foo) = destroyCalled = true
+    block:
+      let a = Foo()
+bar()
+doAssert destroyCalled
+
+# custom `op`
+var destroyCalled2 = false
+macro bar(ident) =
+  var x = 1.5
+  result = quote("@") do:
+    type Foo = object
+    let `@ident` = 0 # custom op interpolated symbols need quoted (``)
+    proc `=destroy`(a: var Foo) =
+      doAssert @x == 1.5
+      doAssert compiles(@x == 1.5)
+      let b1 = @[1,2]
+      let b2 = @@[1,2]
+      doAssert $b1 == "[1, 2]"
+      doAssert $b2 == "@[1, 2]"
+      destroyCalled2 = true
+    block:
+      let a = Foo()
+bar(someident)
+doAssert destroyCalled2
+
+proc `&%`(x: int): int = 1
+proc `&%`(x, y: int): int = 2
+
+macro bar2() =
+  var x = 3
+  result = quote("&%") do:
+    var y = &%x # quoting operator
+    doAssert &%&%y == 1 # unary operator => need to escape
+    doAssert y &% y == 2 # binary operator => no need to escape
+    doAssert y == 3
+bar2()
+
+block:
+  macro foo(a: openArray[string] = []): string =
+    echo a # Segfault doesn't happen if this is removed
+    newLit ""
+
+  proc bar(a: static[openArray[string]] = []) =
+    const tmp = foo(a)
+
+  # bug #22909
+  doAssert not compiles(bar())
diff --git a/tests/arc/tarc_orc.nim b/tests/arc/tarc_orc.nim
index c6a7845b0..f2c7de2fc 100644
--- a/tests/arc/tarc_orc.nim
+++ b/tests/arc/tarc_orc.nim
@@ -33,3 +33,154 @@ proc bug20303() =
   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: var 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: var 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()
+
+block:
+  type
+    TestObj = object of RootObj
+      name: string
+    
+    TestSubObj = object of TestObj
+      objname: string
+
+  proc `=destroy`(x: TestObj) =
+    `=destroy`(x.name)
+
+  proc `=destroy`(x: TestSubObj) =
+    `=destroy`(x.objname)
+    `=destroy`(TestObj(x))
+
+  proc testCase() =
+    let t1 {.used.} = TestSubObj(objname: "tso1", name: "to1")
+
+  proc main() =
+    testCase()
+
+  main()
+
+block: # bug #23858
+  type Object = object
+    a: int
+    b: ref int
+  var x = 0
+  proc fn(): auto {.cdecl.} =
+    inc x
+    return Object()
+  discard fn()
+  doAssert x == 1
+
+block: # bug #24147
+  type
+    O = object of RootObj
+      val: string
+    OO = object of O
+
+  proc `=copy`(dest: var O, src: O) =
+      dest.val = src.val
+
+  let oo = OO(val: "hello world")
+  var ooCopy : OO
+  `=copy`(ooCopy, oo)
diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim
index 45d1514cd..b4476ef4f 100644
--- a/tests/arc/tarcmisc.nim
+++ b/tests/arc/tarcmisc.nim
@@ -1,5 +1,7 @@
 discard """
   output: '''
+Destructor for TestTestObj
+=destroy called
 123xyzabc
 destroyed: false
 destroyed: false
@@ -26,18 +28,90 @@ new line after - @['a']
 finalizer
 aaaaa
 hello
-ok
 true
 copying
 123
 42
-closed
+@["", "d", ""]
+ok
 destroying variable: 20
 destroying variable: 10
+closed
 '''
-  cmd: "nim c --gc:arc --deepcopy:on -d:nimAllocPagesViaMalloc $file"
+  cmd: "nim c --mm:arc --deepcopy:on -d:nimAllocPagesViaMalloc $file"
 """
 
+block: # bug #23627
+  type
+    TestObj = object of RootObj
+
+    Test2 = object of RootObj
+      foo: TestObj
+
+    TestTestObj = object of RootObj
+      shit: TestObj
+
+  proc `=destroy`(x: TestTestObj) =
+    echo "Destructor for TestTestObj"
+    let test = Test2(foo: TestObj())
+
+  proc testCaseT() =
+    let tt1 {.used.} = TestTestObj(shit: TestObj())
+
+
+  proc main() =
+    testCaseT()
+
+  main()
+
+
+# bug #9401
+
+type
+  MyObj = object
+    len: int
+    data: ptr UncheckedArray[float]
+
+proc `=destroy`*(m: MyObj) =
+
+  echo "=destroy called"
+
+  if m.data != nil:
+    deallocShared(m.data)
+
+type
+  MyObjDistinct = distinct MyObj
+
+proc `=copy`*(m: var MyObj, m2: MyObj) =
+  if m.data == m2.data: return
+  if m.data != nil:
+    `=destroy`(m)
+  m.len = m2.len
+  if m.len > 0:
+    m.data = cast[ptr UncheckedArray[float]](allocShared(sizeof(float) * m.len))
+    copyMem(m.data, m2.data, sizeof(float) * m.len)
+
+
+proc `=sink`*(m: var MyObj, m2: MyObj) =
+  if m.data != m2.data:
+    if m.data != nil:
+      `=destroy`(m)
+    m.len = m2.len
+    m.data = m2.data
+
+proc newMyObj(len: int): MyObj =
+  result.len = len
+  result.data = cast[ptr UncheckedArray[float]](allocShared(sizeof(float) * len))
+
+proc newMyObjDistinct(len: int): MyObjDistinct =
+  MyObjDistinct(newMyObj(len))
+
+proc fooDistinct =
+  doAssert newMyObjDistinct(2).MyObj.len == 2
+
+fooDistinct()
+
+
 proc takeSink(x: sink string): bool = true
 
 proc b(x: sink string): string =
@@ -55,7 +129,7 @@ bbb("123")
 type Variable = ref object
   value: int
 
-proc `=destroy`(self: var typeof(Variable()[])) =
+proc `=destroy`(self: typeof(Variable()[])) =
   echo "destroying variable: ",self.value
 
 proc newVariable(value: int): Variable =
@@ -75,7 +149,7 @@ proc test(count: int) =
 test(3)
 
 proc test2(count: int) =
-  #block: #XXX: Fails with block currently
+  block: #XXX: Fails with block currently
     var v {.global.} = newVariable(20)
 
     var count = count - 1
@@ -109,7 +183,7 @@ type
   B = ref object of A
     x: int
 
-proc `=destroy`(x: var AObj) =
+proc `=destroy`(x: AObj) =
   close(x.io)
   echo "closed"
 
@@ -497,3 +571,266 @@ proc fooz(sec: var InputSectionBase) =
 var sec = create(InputSection)
 sec[] = InputSection(relocations: newSeq[int]())
 fooz sec[]
+
+block:
+  type
+    Data = ref object
+      id: int
+  proc main =
+    var x = Data(id: 99)
+    var y = x
+    x[] = Data(id: 778)[]
+    doAssert y.id == 778
+    doAssert x[].id == 778
+  main()
+
+block: # bug #19857
+  type
+    ValueKind = enum VNull, VFloat, VObject # need 3 elements. Cannot remove VNull or VObject
+
+    Value = object
+      case kind: ValueKind
+      of VFloat: fnum: float
+      of VObject: tab: Table[int, int] # OrderedTable[T, U] also makes it fail.
+                                      # "simpler" types also work though
+      else: discard # VNull can be like this, but VObject must be filled
+
+    # required. Pure proc works
+    FormulaNode = proc(c: OrderedTable[string, int]): Value
+
+  proc toF(v: Value): float =
+    doAssert v.kind == VFloat
+    case v.kind
+    of VFloat: result = v.fnum
+    else: discard
+
+
+  proc foo() =
+    let fuck = initOrderedTable[string, int]()
+    proc cb(fuck: OrderedTable[string, int]): Value =
+                            # works:
+                            #result = Value(kind: VFloat, fnum: fuck["field_that_does_not_exist"].float)
+                            # broken:
+      discard "actuall runs!"
+      let t = fuck["field_that_does_not_exist"]
+      echo "never runs, but we crash after! ", t
+
+    doAssertRaises(KeyError):
+      let fn = FormulaNode(cb)
+      let v = fn(fuck)
+      #echo v
+      let res = v.toF()
+
+  foo()
+
+import std/options
+
+# bug #21592
+type Event* = object
+  code*: string
+
+type App* = ref object of RootObj
+  id*: string
+
+method process*(self: App): Option[Event] {.base.} =
+  raise Exception.new_exception("not impl")
+
+# bug #21617
+type Test2 = ref object of RootObj
+
+method bug(t: Test2): seq[float] {.base.} = discard
+
+block: # bug #22664
+  type
+    ElementKind = enum String, Number
+    Element = object
+      case kind: ElementKind
+      of String:
+        str: string
+      of Number:
+        num: float
+    Calc = ref object
+      stack: seq[Element]
+
+  var calc = new Calc
+
+  calc.stack.add Element(kind: Number, num: 200.0)
+  doAssert $calc.stack == "@[(kind: Number, num: 200.0)]"
+  let calc2 = calc
+  calc2.stack = calc.stack # This nulls out the object in the stack
+  doAssert $calc.stack == "@[(kind: Number, num: 200.0)]"
+  doAssert $calc2.stack == "@[(kind: Number, num: 200.0)]"
+
+block: # bug #19250
+  type
+    Bar[T] = object
+      err: proc(): string
+
+    Foo[T] = object
+      run: proc(): Bar[T]
+
+  proc bar[T](err: proc(): string): Bar[T] =
+    assert not err.isNil
+    Bar[T](err: err)
+
+  proc foo(): Foo[char] = 
+    result.run = proc(): Bar[char] =
+      # works
+      # result = Bar[char](err: proc(): string = "x")
+      # not work
+      result = bar[char](proc(): string = "x")
+
+  proc bug[T](fs: Foo[T]): Foo[T] =
+    result.run = proc(): Bar[T] =
+      let res = fs.run()
+      
+      # works
+      # var errors = @[res.err] 
+      
+      # not work
+      var errors: seq[proc(): string]
+      errors.add res.err
+      
+      return bar[T] do () -> string:
+        for err in errors:
+          result.add res.err()
+
+  doAssert bug(foo()).run().err() == "x"
+
+block: # bug #22259
+  type
+    ProcWrapper = tuple
+      p: proc() {.closure.}
+
+
+  proc f(wrapper: ProcWrapper) =
+    let s = @[wrapper.p]
+    let a = [wrapper.p]
+
+  proc main =
+    # let wrapper: ProcWrapper = ProcWrapper(p: proc {.closure.} = echo 10)
+    let wrapper: ProcWrapper = (p: proc {.closure.} = echo 10)
+    f(wrapper)
+
+  main()
+
+block:
+  block: # bug #22923
+    block:
+      let
+        a: int = 100
+        b: int32 = 200'i32
+
+      let
+        x = arrayWith(a, 8) # compiles
+        y = arrayWith(b, 8) # internal error
+        z = arrayWith(14, 8) # integer literal also results in a crash
+
+      doAssert x == [100, 100, 100, 100, 100, 100, 100, 100]
+      doAssert $y == "[200, 200, 200, 200, 200, 200, 200, 200]"
+      doAssert z == [14, 14, 14, 14, 14, 14, 14, 14]
+
+    block:
+      let a: string = "nim"
+      doAssert arrayWith(a, 3) == ["nim", "nim", "nim"]
+
+      let b: char = 'c'
+      doAssert arrayWith(b, 3) == ['c', 'c', 'c']
+
+      let c: uint = 300'u
+      doAssert $arrayWith(c, 3) == "[300, 300, 300]"
+
+block: # bug #23505
+  type
+    K = object
+    C = object
+      value: ptr K
+
+  proc init(T: type C): C =
+    let tmp = new K
+    C(value: addr tmp[])
+
+  discard init(C)
+
+block: # bug #23524
+  type MyType = object
+    a: int
+
+  proc `=destroy`(typ: MyType) = discard
+
+  var t1 = MyType(a: 100)
+  var t2 = t1 # Should be a copy?
+
+  proc main() =
+    t2 = t1
+    doAssert t1.a == 100
+    doAssert t2.a == 100
+
+  main()
+
+block: # bug #23907
+  type
+    Thingy = object
+      value: int
+
+    ExecProc[C] = proc(value: sink C): int {.nimcall.}
+
+  proc `=copy`(a: var Thingy, b: Thingy) {.error.}
+
+  var thingyDestroyCount = 0
+
+  proc `=destroy`(thingy: Thingy) =
+    assert(thingyDestroyCount <= 0)
+    thingyDestroyCount += 1
+
+  proc store(value: sink Thingy): int =
+    result = value.value
+
+  let callback: ExecProc[Thingy] = store
+
+  doAssert callback(Thingy(value: 123)) == 123
+
+import std/strutils
+
+block: # bug #23974
+  func g(e: seq[string]): lent seq[string] = result = e
+  proc k(f: string): seq[string] = f.split("/")
+  proc n() =
+    const r = "/d/"
+    let t =
+      if true:
+        k(r).g()
+      else:
+        k("/" & r).g()
+    echo t
+
+  n()
+
+block: # bug #23973
+  func g(e: seq[string]): lent seq[string] = result = e
+  proc k(f: string): seq[string] = f.split("/")
+  proc n() =
+    const r = "/test/empty"  # or "/test/empty/1"
+    let a = k(r).g()
+    let t =
+      if true:
+        k(r).g()
+      else:
+        k("/" & r).g()   # or raiseAssert ""
+    doAssert t == a
+
+  n()
+
+block: # bug #24141
+  func reverse(s: var openArray[char]) =
+    s[0] = 'f'
+
+  func rev(s: var string) =
+    s.reverse
+
+  proc main =
+    var abc = "abc"
+    abc.rev
+    doAssert abc == "fbc"
+
+  main()
diff --git a/tests/arc/tasyncleak.nim b/tests/arc/tasyncleak.nim
index eb0c45213..8e3a7b3e7 100644
--- a/tests/arc/tasyncleak.nim
+++ b/tests/arc/tasyncleak.nim
@@ -1,5 +1,5 @@
 discard """
-  outputsub: "(allocCount: 4302, deallocCount: 4300)"
+  outputsub: "(allocCount: 4050, deallocCount: 4048)"
   cmd: "nim c --gc:orc -d:nimAllocStats $file"
 """
 
diff --git a/tests/arc/tcaseobj.nim b/tests/arc/tcaseobj.nim
index d52833e4d..3499f5c1e 100644
--- a/tests/arc/tcaseobj.nim
+++ b/tests/arc/tcaseobj.nim
@@ -60,7 +60,7 @@ proc `=destroy`(o: var TMyObj) =
     o.p = nil
     echo "myobj destroyed"
 
-proc `=`(dst: var TMyObj, src: TMyObj) =
+proc `=copy`(dst: var TMyObj, src: TMyObj) =
   `=destroy`(dst)
   dst.p = alloc(src.len)
   dst.len = src.len
@@ -170,18 +170,24 @@ proc test_myobject =
   x.x1 = "x1"
   x.x2 = "x2"
   x.y1 = "ljhkjhkjh"
-  x.kind1 = true
+  {.cast(uncheckedAssign).}:
+    x.kind1 = true
   x.y2 = @["1", "2"]
-  x.kind2 = true
+  {.cast(uncheckedAssign).}:
+    x.kind2 = true
   x.z1 = "yes"
-  x.kind2 = false
+  {.cast(uncheckedAssign).}:
+    x.kind2 = false
   x.z2 = @["1", "2"]
-  x.kind2 = true
+  {.cast(uncheckedAssign).}:
+    x.kind2 = true
   x.z1 = "yes"
   x.kind2 = true # should be no effect
   doAssert(x.z1 == "yes")
-  x.kind2 = false
-  x.kind1 = x.kind2 # support self assignment with effect
+  {.cast(uncheckedAssign).}:
+    x.kind2 = false
+  {.cast(uncheckedAssign).}:
+    x.kind1 = x.kind2 # support self assignment with effect
 
   try:
     x.kind1 = x.flag # flag is not accesible
@@ -207,8 +213,9 @@ type
       error*: string
 
 proc init(): RocksDBResult[string] =
-  result.ok = true
-  result.value = "ok"
+  {.cast(uncheckedAssign).}:
+    result.ok = true
+    result.value = "ok"
 
 echo init()
 
@@ -222,7 +229,8 @@ type MyObj = object
     of true: x1: string
 
 var a = MyObj(kind: false, x0: 1234)
-a.kind = true
+{.cast(uncheckedAssign).}:
+  a.kind = true
 doAssert(a.x1 == "")
 
 block:
@@ -269,3 +277,90 @@ proc bug20305 =
   echo x.pChildren
 
 bug20305()
+
+# bug #21023
+block:
+  block:
+    type
+      MGErrorKind = enum
+        mgeUnexpected, mgeNotFound
+
+    type Foo = object
+      kind: MGErrorKind
+      ex: Exception
+
+    type Boo = object
+      a: seq[int]
+
+    type
+      Result2 = object
+        case o: bool
+        of false:
+          e: Foo
+        of true:
+          v: Boo
+
+    proc startSessionSync(): Result2 =
+      return Result2(o: true)
+
+    proc mainSync =
+      let ff = startSessionSync()
+      doAssert ff.o == true
+
+    mainSync()
+
+  block:
+    type
+      MGErrorKind = enum
+        mgeUnexpected, mgeNotFound
+
+    type Foo = object
+      kind: MGErrorKind
+      ex: Exception
+
+    type Boo = object
+      a: seq[int]
+
+    type
+      Result2 = object
+        case o: bool
+        of false:
+          e: Foo
+        of true:
+          v: Boo
+          s: int
+
+    proc startSessionSync(): Result2 =
+      return Result2(o: true, s: 12)
+
+    proc mainSync =
+      let ff = startSessionSync()
+      doAssert ff.s == 12
+
+    mainSync()
+
+import std/sequtils
+
+# bug #23690
+type
+  SomeObj* = object of RootObj
+
+  Item* = object
+    case kind*: 0..1
+    of 0:
+      a*: int
+      b*: SomeObj
+    of 1:
+      c*: string
+
+  ItemExt* = object
+    a*: Item
+    b*: string
+
+proc do1(x: int): seq[(string, Item)] =
+  result = @[("zero", Item(kind: 1, c: "first"))]
+
+proc do2(x: int, e: ItemExt): seq[(string, ItemExt)] =
+  do1(x).map(proc(v: (string, Item)): auto = (v[0], ItemExt(a: v[1], b: e.b)))
+
+doAssert $do2(0, ItemExt(a: Item(kind: 1, c: "second"), b: "third")) == """@[("zero", (a: (kind: 1, c: "first"), b: "third"))]"""
diff --git a/tests/arc/tcaseobjcopy.nim b/tests/arc/tcaseobjcopy.nim
index ed07b404e..fb26a4973 100644
--- a/tests/arc/tcaseobjcopy.nim
+++ b/tests/arc/tcaseobjcopy.nim
@@ -169,18 +169,23 @@ proc test_myobject =
   x.x1 = "x1"
   x.x2 = "x2"
   x.y1 = "ljhkjhkjh"
-  x.kind1 = true
+  {.cast(uncheckedAssign).}:
+    x.kind1 = true
   x.y2 = @["1", "2"]
-  x.kind2 = true
+  {.cast(uncheckedAssign).}:
+    x.kind2 = true
   x.z1 = "yes"
-  x.kind2 = false
+  {.cast(uncheckedAssign).}:
+    x.kind2 = false
   x.z2 = @["1", "2"]
-  x.kind2 = true
+  {.cast(uncheckedAssign).}:
+    x.kind2 = true
   x.z1 = "yes"
   x.kind2 = true # should be no effect
   doAssert(x.z1 == "yes")
-  x.kind2 = false
-  x.kind1 = x.kind2 # support self assignment with effect
+  {.cast(uncheckedAssign).}:
+    x.kind2 = false
+    x.kind1 = x.kind2 # support self assignment with effect
 
   try:
     x.kind1 = x.flag # flag is not accesible
@@ -206,7 +211,8 @@ type
       error*: string
 
 proc init(): RocksDBResult[string] =
-  result.ok = true
+  {.cast(uncheckedAssign).}:
+    result.ok = true
   result.value = "ok"
 
 echo init()
@@ -221,7 +227,8 @@ type MyObj = object
     of true: x1: string
 
 var a = MyObj(kind: false, x0: 1234)
-a.kind = true
+{.cast(uncheckedAssign).}:
+  a.kind = true
 doAssert(a.x1 == "")
 
 block:
diff --git a/tests/arc/tcomputedgoto.nim b/tests/arc/tcomputedgoto.nim
index 541a748c6..07487684a 100644
--- a/tests/arc/tcomputedgoto.nim
+++ b/tests/arc/tcomputedgoto.nim
@@ -1,16 +1,19 @@
 discard """
-  cmd: '''nim c --gc:arc $file'''
-  output: '''2
-2'''
+  cmd: '''nim c --mm:arc $file'''
+  output: '''
+2
+2
+destroyed
+'''
 """
 
 type
   ObjWithDestructor = object
     a: int
-proc `=destroy`(self: var ObjWithDestructor) =
+proc `=destroy`(self: ObjWithDestructor) =
   echo "destroyed"
 
-proc `=`(self: var ObjWithDestructor, other: ObjWithDestructor) =
+proc `=copy`(self: var ObjWithDestructor, other: ObjWithDestructor) =
   echo "copied"
 
 proc test(a: range[0..1], arg: ObjWithDestructor) =
@@ -38,4 +41,4 @@ proc test(a: range[0..1], arg: ObjWithDestructor) =
       if iteration == 2:
         break
 
-test(1, ObjWithDestructor())
\ No newline at end of file
+test(1, ObjWithDestructor())
diff --git a/tests/arc/tcomputedgotocopy.nim b/tests/arc/tcomputedgotocopy.nim
index 8337123ba..07487684a 100644
--- a/tests/arc/tcomputedgotocopy.nim
+++ b/tests/arc/tcomputedgotocopy.nim
@@ -1,13 +1,16 @@
 discard """
-  cmd: '''nim c --gc:arc $file'''
-  output: '''2
-2'''
+  cmd: '''nim c --mm:arc $file'''
+  output: '''
+2
+2
+destroyed
+'''
 """
 
 type
   ObjWithDestructor = object
     a: int
-proc `=destroy`(self: var ObjWithDestructor) =
+proc `=destroy`(self: ObjWithDestructor) =
   echo "destroyed"
 
 proc `=copy`(self: var ObjWithDestructor, other: ObjWithDestructor) =
diff --git a/tests/arc/tcontrolflow.nim b/tests/arc/tcontrolflow.nim
index 80cc2b187..dbc115903 100644
--- a/tests/arc/tcontrolflow.nim
+++ b/tests/arc/tcontrolflow.nim
@@ -76,7 +76,7 @@ var c = Control(x: 7)
 
 run(c)
 
-proc sysFatal(exceptn: typedesc, message: string) {.inline, noreturn.} =
+proc sysFatal(exceptn: typedesc, message: string) {.inline.} =
   var buf = newStringOfCap(200)
   add(buf, "##")
   add(buf, message)
diff --git a/tests/arc/tdup.nim b/tests/arc/tdup.nim
new file mode 100644
index 000000000..61f262a68
--- /dev/null
+++ b/tests/arc/tdup.nim
@@ -0,0 +1,71 @@
+discard """
+  cmd: "nim c --mm:arc --expandArc:foo --hints:off $file"
+  nimout: '''
+--expandArc: foo
+
+var
+  x
+  :tmpD
+  s
+  :tmpD_1
+x = Ref(id: 8)
+inc:
+  :tmpD = `=dup`(x)
+  :tmpD
+inc:
+  let blitTmp = x
+  blitTmp
+var id_1 = 777
+s = RefCustom(id_2: addr(id_1))
+inc_1 :
+  :tmpD_1 = `=dup_1`(s)
+  :tmpD_1
+inc_1 :
+  let blitTmp_1 = s
+  blitTmp_1
+-- end of expandArc ------------------------
+'''
+"""
+
+type
+  Ref = ref object
+    id: int
+
+  RefCustom = object
+    id: ptr int
+
+proc `=dup`(x: RefCustom): RefCustom =
+  result.id = x.id
+
+proc inc(x: sink Ref) =
+  inc x.id
+
+proc inc(x: sink RefCustom) =
+  inc x.id[]
+
+
+proc foo =
+  var x = Ref(id: 8)
+  inc(x)
+  inc(x)
+  var id = 777
+  var s = RefCustom(id: addr id)
+  inc s
+  inc s
+
+foo()
+
+proc foo2 =
+  var x = Ref(id: 8)
+  inc(x)
+  doAssert x.id == 9
+  inc(x)
+  doAssert x.id == 10
+  var id = 777
+  var s = RefCustom(id: addr id)
+  inc s
+  doAssert s.id[] == 778
+  inc s
+  doAssert s.id[] == 779
+
+foo2()
diff --git a/tests/arc/texplicit_sink.nim b/tests/arc/texplicit_sink.nim
new file mode 100644
index 000000000..4b021ed62
--- /dev/null
+++ b/tests/arc/texplicit_sink.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''de'''
+  cmd: '''nim c --mm:arc --expandArc:main $file'''
+  nimout: '''--expandArc: main
+
+var
+  a
+  b_cursor
+try:
+  a = f "abc"
+  b_cursor = "de"
+  `=sink`(a, b_cursor)
+  echo [a]
+finally:
+  `=destroy`(a)
+-- end of expandArc ------------------------'''
+"""
+
+# bug #20572
+
+proc f(s: string): string = s
+
+proc main =
+  var a = f "abc"
+  var b = "de"
+  `=sink`(a, b)
+  echo a
+
+main()
diff --git a/tests/arc/thard_alignment.nim b/tests/arc/thard_alignment.nim
index baa964c77..30cfddb05 100644
--- a/tests/arc/thard_alignment.nim
+++ b/tests/arc/thard_alignment.nim
@@ -1,9 +1,11 @@
 discard """
 disabled: "arm64"
-cmd: "nim c --gc:arc $file"
+cmd: "nim c --mm:arc -u:nimPreviewNonVarDestructor $file"
 output: "y"
 """
 
+# TODO: fixme: investigate why it failed with non-var destructors
+
 {.passC: "-march=native".}
 
 proc isAlignedCheck(p: pointer, alignment: int) = 
diff --git a/tests/arc/titeration_doesnt_copy.nim b/tests/arc/titeration_doesnt_copy.nim
new file mode 100644
index 000000000..e510a6eff
--- /dev/null
+++ b/tests/arc/titeration_doesnt_copy.nim
@@ -0,0 +1,67 @@
+discard """
+  output: "true"
+"""
+
+type
+  Idx = object
+    i: int
+  Node = object
+    n: int
+    next: seq[Idx]
+  FooBar = object
+    s: seq[Node]
+
+proc `=copy`(dest: var Idx; source: Idx) {.error.}
+proc `=copy`(dest: var Node; source: Node) {.error.}
+proc `=copy`(dest: var FooBar; source: FooBar) {.error.}
+
+proc doSomething(ss: var seq[int], s: FooBar) =
+  for i in 0 .. s.s.len-1:
+    for elm in items s.s[i].next:
+      ss.add s.s[elm.i].n
+
+when isMainModule:
+  const foo = FooBar(s: @[Node(n: 1, next: @[Idx(i: 0)])])
+  var ss: seq[int]
+  doSomething(ss, foo)
+  echo ss == @[1]
+
+from sequtils import mapIt
+from strutils import join
+
+proc toBinSeq*(b: uint8): seq[uint8] =
+  ## Return binary sequence from each bits of uint8.
+  runnableExamples:
+    from sequtils import repeat
+    doAssert 0'u8.toBinSeq == 0'u8.repeat(8)
+    doAssert 0b1010_1010.toBinSeq == @[1'u8, 0, 1, 0, 1, 0, 1, 0]
+  result = @[]
+  var c = b
+  for i in 1..8:
+    result.add (uint8(c and 0b1000_0000) shr 7)
+    c = c shl 1
+
+proc toBinString*(data: openArray[uint8], col: int): string =
+  ## Return binary string from each bits of uint8.
+  runnableExamples:
+    doAssert @[0b0000_1111'u8, 0b1010_1010].toBinString(8) == "0000111110101010"
+    doAssert @[0b1000_0000'u8, 0b0000_0000].toBinString(1) == "10"
+  result = ""
+  for b in items data.mapIt(it.toBinSeq.mapIt(it.`$`[0].char)):
+    for i, c in b:
+      if i < col:
+        result.add c
+
+doAssert @[0b0000_1111'u8, 0b1010_1010].toBinString(8) == "0000111110101010"
+doAssert @[0b1000_0000'u8, 0b0000_0000].toBinString(1) == "10"
+
+block: # bug #23982
+  iterator `..`(a, b: ptr int16): ptr int16 = discard
+  var a: seq[int16] #; let p = a[0].addr
+  var b: seq[ptr int16]
+
+  try:
+    for x in a[0].addr .. b[1]: # `p .. b[1]` works
+      discard
+  except IndexDefect:
+    discard
diff --git a/tests/arc/tmalloc.nim b/tests/arc/tmalloc.nim
new file mode 100644
index 000000000..1d72646c8
--- /dev/null
+++ b/tests/arc/tmalloc.nim
@@ -0,0 +1,16 @@
+discard """
+  matrix: "--mm:arc -d:useMalloc; --mm:arc"
+"""
+
+block: # bug #22058
+  template foo(): auto =
+    {.noSideEffect.}:
+      newSeq[byte](1)
+
+  type V = object
+    v: seq[byte]
+
+  proc bar(): V =
+    V(v: foo())
+
+  doAssert bar().v == @[byte(0)]
diff --git a/tests/arc/tmove_regression.nim b/tests/arc/tmove_regression.nim
new file mode 100644
index 000000000..7d9a867c3
--- /dev/null
+++ b/tests/arc/tmove_regression.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''/1/2
+/1
+/
+'''
+""""
+
+# bug #22001
+
+import std / [os, strutils]
+
+proc finOp2(path, name: string): (string, File) = # Find & open FIRST `name`
+  var current = path
+  while true:
+    if current.isRootDir: break # <- current=="" => current.isRootDir
+    current = current.parentDir
+    let dir = current
+    echo dir.replace('\\', '/')  # Commenting out try/except below hides bug
+    try: result[0] = dir/name; result[1] = open(result[0]); return
+    except CatchableError: discard
+
+discard finOp2("/1/2/3", "4")  # All same if this->inside a proc
diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim
index 002bd6796..8ad7c955c 100644
--- a/tests/arc/tmovebug.nim
+++ b/tests/arc/tmovebug.nim
@@ -93,6 +93,7 @@ destroy
 destroy
 destroy
 sink
+sink
 destroy
 copy
 (f: 1)
@@ -767,8 +768,7 @@ proc initC(): C =
   C(o: initO())
 
 proc pair(): tuple[a: C, b: C] =
-  result.a = initC() # <- when firstWrite tries to find this node to start its analysis it fails, because injectdestructors uses copyTree/shallowCopy
-  result.b = initC()
+  result = (a: initC(), b: initC())# <- when firstWrite tries to find this node to start its analysis it fails, because injectdestructors uses copyTree/shallowCopy
 
 discard pair()
 
@@ -818,3 +818,24 @@ proc atomicClosureOp =
 
 atomicClosureOp()
 
+
+template assertEq(a, b: untyped): untyped =
+  block:
+    let
+      aval = a
+      bval = b
+
+    if aval != bval:
+      quit "bug!"
+
+proc convoluted =
+  let _ = (;
+    var val1: string;
+    if true: val1 = "22"
+    true
+  )
+
+  assertEq val1, "22"
+  assertEq val1, "22"
+
+convoluted()
diff --git a/tests/arc/topenarray.nim b/tests/arc/topenarray.nim
index 03ec7adf2..ba91666ba 100644
--- a/tests/arc/topenarray.nim
+++ b/tests/arc/topenarray.nim
@@ -6,6 +6,8 @@ Nim
 '''
   matrix: "--gc:arc -d:useMalloc; --gc:arc"
 """
+{.experimental: "views".}
+
 block: # bug 18627
   proc setPosition(params: openArray[string]) =
     for i in params.toOpenArray(0, params.len - 1):
@@ -22,3 +24,63 @@ block: # bug 18627
     for i in params.toOpenArray(0, params.len - 1):
       echo i
   uciLoop2()
+
+when defined(nimPreviewSlimSystem):
+  import std/assertions
+
+block: # bug #20954
+  block:
+    doAssertRaises(IndexDefect):
+      var v: array[10, int]
+
+      echo len(toOpenArray(v, 20, 30))
+
+  block:
+    doAssertRaises(IndexDefect):
+      var v: seq[int]
+
+      echo len(toOpenArray(v, 20, 30))
+
+# bug #20422
+
+proc f(a: var string) =
+  var v = a.toOpenArray(1, 3)
+  v[0] = 'a'
+
+var a = "Hello"
+f(a)
+doAssert a == "Hallo"
+
+# bug #22132
+block:
+  func foo[T](arr: openArray[T], idx: int = arr.low): string =
+    doAssert idx == 0
+    return $arr
+
+  let bug = ["0", "c", "a"]
+
+  let str = foo(bug)
+
+  const expected = """["0", "c", "a"]"""
+  doAssert str == expected
+
+  const noBugConst = ["0", "c", "a"]
+  doAssert foo(noBugConst) == expected
+  let noBugSeq = @["0", "c", "a"]
+  doAssert foo(noBugSeq) == expected
+
+block: # bug #20865
+  var p: pointer
+  var x: array[0, int]
+  # echo toOpenArray(x, 0, 1)[0] # Raises IndexDefect
+  doAssertRaises(IndexDefect):
+    echo toOpenArray(cast[ptr array[0, int]](p)[], 0, 1)[0] # Does not raise IndexDefect
+
+block: # bug #20987
+  var v: array[1, byte]
+
+  var p = cast[ptr array[0, byte]](addr v)
+
+  doAssertRaises(IndexDefect):
+    echo toOpenArray(p[], 1, 2)
+
diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim
index 0de7f41b9..0a4984a69 100644
--- a/tests/arc/topt_no_cursor.nim
+++ b/tests/arc/topt_no_cursor.nim
@@ -1,23 +1,20 @@
 discard """
-  output: '''(package: "", ext: "meo")
-doing shady stuff...
-3
-6
-(@[1], @[2])
-192.168.0.1
-192.168.0.1
-192.168.0.1
-192.168.0.1'''
-  cmd: '''nim c --gc:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off --assertions:off --expandArc:extractConfig --expandArc:mergeShadowScope --expandArc:check $file'''
-  nimout: '''--expandArc: newTarget
+  nimoutFull: true
+  cmd: '''nim c -r --warnings:off --hints:off --mm:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off --assertions:off --expandArc:extractConfig --expandArc:mergeShadowScope --expandArc:check $file'''
+  nimout: '''
+--expandArc: newTarget
 
+var
+  splat
+  :tmp
+  :tmp_1
 splat = splitDrive do:
   let blitTmp = path
   blitTmp
 :tmp = splat.drive
-wasMoved(splat.drive)
+`=wasMoved`(splat.drive)
 :tmp_1 = splat.path_1
-wasMoved(splat.path_1)
+`=wasMoved`(splat.path_1)
 result = (
   let blitTmp_1 = :tmp
   blitTmp_1,
@@ -42,14 +39,14 @@ var
   lresult
   lvalue
   lnext
-  _
+  tmpTupleAsgn
 lresult = @[123]
-_ = (
+tmpTupleAsgn = (
   let blitTmp = lresult
   blitTmp, ";")
-lvalue = _[0]
-lnext = _[1]
-result.value = move lvalue
+lvalue = tmpTupleAsgn[0]
+lnext = tmpTupleAsgn[1]
+`=sink`(result.value, move lvalue)
 `=destroy`(lnext)
 `=destroy_1`(lvalue)
 -- end of expandArc ------------------------
@@ -64,11 +61,9 @@ var
 try:
   it_cursor = x
   a = (
-    wasMoved(:tmpD)
-    `=copy`(:tmpD, it_cursor.key)
+    :tmpD = `=dup`(it_cursor.key)
     :tmpD,
-    wasMoved(:tmpD_1)
-    `=copy`(:tmpD_1, it_cursor.val)
+    :tmpD_1 = `=dup`(it_cursor.val)
     :tmpD_1)
   echo [
     :tmpD_2 = `$$`(a)
@@ -96,11 +91,14 @@ try:
             `=copy`(lan_ip, splitted[1])
           echo [lan_ip]
           echo [splitted[1]]
+          {.push, overflowChecks: false.}
           inc(i, 1)
+          {.pop.}
         finally:
           `=destroy`(splitted)
 finally:
   `=destroy_1`(lan_ip)
+-- end of expandArc ------------------------
 --expandArc: mergeShadowScope
 
 var shadowScope
@@ -115,10 +113,11 @@ block :tmp:
       var :tmpD
       sym = shadowScope.symbols[i]
       addInterfaceDecl(c):
-        wasMoved(:tmpD)
-        `=copy_1`(:tmpD, sym)
+        :tmpD = `=dup`(sym)
         :tmpD
+      {.push, overflowChecks: false.}
       inc(i, 1)
+      {.pop.}
 `=destroy`(shadowScope)
 -- end of expandArc ------------------------
 --expandArc: check
@@ -128,19 +127,16 @@ this.isValid = fileExists(this.value)
 if dirExists(this.value):
   var :tmpD
   par = (dir:
-    wasMoved(:tmpD)
-    `=copy`(:tmpD, this.value)
+    :tmpD = `=dup`(this.value)
     :tmpD, front: "") else:
   var
     :tmpD_1
     :tmpD_2
     :tmpD_3
   par = (dir_1: parentDir(this.value), front_1:
-    wasMoved(:tmpD_1)
-    `=copy`(:tmpD_1,
+    :tmpD_1 = `=dup`(
       :tmpD_3 = splitDrive do:
-        wasMoved(:tmpD_2)
-        `=copy`(:tmpD_2, this.value)
+        :tmpD_2 = `=dup`(this.value)
         :tmpD_2
       :tmpD_3.path)
     :tmpD_1)
@@ -150,7 +146,21 @@ if dirExists(par.dir):
 else:
   `=sink`(this.matchDirs, [])
 `=destroy`(par)
--- end of expandArc ------------------------'''
+-- end of expandArc ------------------------
+--expandArc: check
+
+check(this)
+-- end of expandArc ------------------------
+(package: "", ext: "meo")
+doing shady stuff...
+3
+6
+(@[1], @[2])
+192.168.0.1
+192.168.0.1
+192.168.0.1
+192.168.0.1
+'''
 """
 
 import os, std/private/ntpath
diff --git a/tests/arc/topt_refcursors.nim b/tests/arc/topt_refcursors.nim
index c13d81bad..8c638a4a1 100644
--- a/tests/arc/topt_refcursors.nim
+++ b/tests/arc/topt_refcursors.nim
@@ -1,7 +1,8 @@
 discard """
   output: ''''''
   cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file'''
-  nimout: '''--expandArc: traverse
+  nimout: '''
+--expandArc: traverse
 
 var
   it_cursor
@@ -22,12 +23,13 @@ try:
         `=copy`(ri_1, jt.ri)
         echo [jt.s]
         `=sink`(jt, ri_1)
-        wasMoved(ri_1)
+        `=wasMoved`(ri_1)
       finally:
         `=destroy`(ri_1)
 finally:
   `=destroy`(jt)
--- end of expandArc ------------------------'''
+-- end of expandArc ------------------------
+'''
 """
 
 type
diff --git a/tests/arc/topt_wasmoved_destroy_pairs.nim b/tests/arc/topt_wasmoved_destroy_pairs.nim
index 2f971f112..c96340a30 100644
--- a/tests/arc/topt_wasmoved_destroy_pairs.nim
+++ b/tests/arc/topt_wasmoved_destroy_pairs.nim
@@ -1,7 +1,8 @@
 discard """
   output: ''''''
   cmd: '''nim c --gc:arc --expandArc:main --expandArc:tfor --hint:Performance:off $file'''
-  nimout: '''--expandArc: main
+  nimout: '''
+--expandArc: main
 
 var
   a
@@ -29,6 +30,7 @@ try:
   x = f()
   block :tmp:
     var i_cursor
+    mixin inc
     var i_1 = 0
     block :tmp_1:
       while i_1 < 4:
@@ -37,25 +39,25 @@ try:
         if i_cursor == 2:
           return
         add(a):
-          wasMoved(:tmpD)
-          `=copy`(:tmpD, x)
+          :tmpD = `=dup`(x)
           :tmpD
         inc i_1, 1
   if cond:
     add(a):
       let blitTmp = x
-      wasMoved(x)
+      `=wasMoved`(x)
       blitTmp
   else:
     add(b):
       let blitTmp_1 = x
-      wasMoved(x)
+      `=wasMoved`(x)
       blitTmp_1
 finally:
   `=destroy`(x)
   `=destroy_1`(b)
   `=destroy_1`(a)
--- end of expandArc ------------------------'''
+-- end of expandArc ------------------------
+'''
 """
 
 proc f(): seq[int] =
diff --git a/tests/arc/trepr.nim b/tests/arc/trepr.nim
index 50d433208..abf28330a 100644
--- a/tests/arc/trepr.nim
+++ b/tests/arc/trepr.nim
@@ -9,6 +9,7 @@ nil
 2
 Obj(member: ref @["hello"])
 ref (member: ref @["hello"])
+ObjUa(v: 0, a: [...])
 '''
 """
 
@@ -87,3 +88,10 @@ macro extract(): untyped =
   test(parseExpr("discard"))
   
 extract()
+
+type
+  ObjUa = ref object
+    v: int
+    a: UncheckedArray[char]
+
+echo ObjUa().repr
diff --git a/tests/arc/tstringliteral.nim b/tests/arc/tstringliteral.nim
new file mode 100644
index 000000000..c5fac22d8
--- /dev/null
+++ b/tests/arc/tstringliteral.nim
@@ -0,0 +1,17 @@
+discard """
+  matrix: "--mm:arc; --mm:orc"
+"""
+
+block: # issue #24080
+  var a = (s: "a")
+  var b = "a"
+  a.s.setLen 0
+  b = a.s
+  doAssert b == ""
+
+block: # issue #24080, longer string
+  var a = (s: "abc")
+  var b = "abc"
+  a.s.setLen 2
+  b = a.s
+  doAssert b == "ab"
diff --git a/tests/arc/tweave.nim b/tests/arc/tweave.nim
index 220d65f97..1c60ac403 100644
--- a/tests/arc/tweave.nim
+++ b/tests/arc/tweave.nim
@@ -8,6 +8,9 @@ discard """
 
 import std/atomics
 
+when defined(nimPreviewSlimSystem):
+  import std/[assertions, typedthreads]
+
 const MemBlockSize = 256
 
 type
diff --git a/tests/arc/twrong_sinkinference.nim b/tests/arc/twrong_sinkinference.nim
index 59930a9fa..ecf09d28a 100644
--- a/tests/arc/twrong_sinkinference.nim
+++ b/tests/arc/twrong_sinkinference.nim
@@ -1,6 +1,6 @@
 discard """
   cmd: "nim c --gc:arc $file"
-  errormsg: "type mismatch: got <proc (a: string, b: sink string){.noSideEffect, gcsafe, locks: 0.}>"
+  errormsg: "type mismatch: got <proc (a: string, b: sink string){.noSideEffect, gcsafe.}>"
   line: 18
 """