diff options
Diffstat (limited to 'tests/arc/tmovebug.nim')
-rw-r--r-- | tests/arc/tmovebug.nim | 516 |
1 files changed, 515 insertions, 1 deletions
diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim index ec0fce9a8..8ad7c955c 100644 --- a/tests/arc/tmovebug.nim +++ b/tests/arc/tmovebug.nim @@ -40,6 +40,76 @@ sink me (not sink) sinked and not optimized to a bitcopy sinked and not optimized to a bitcopy sinked and not optimized to a bitcopy +(data: @[0, 0]) +(data: @[0, 0]) +(data: @[0, 0]) +(data: @[0, 0]) +(data: @[0, 0]) +(data: @[0, 0]) +(data: @[0, 0]) +100 +hey +hey +(a: "a", b: 2) +ho +(a: "b", b: 3) +(b: "b", a: 2) +ho +(b: "a", a: 3) +hey +break +break +hey +ho +hey +ho +ho +king +live long; long live +king +hi +try +bye +() +() +() +1 +destroy +1 +destroy +1 +destroy +copy (self-assign) +1 +destroy +1 +destroy +1 +destroy +destroy +copy +@[(f: 2), (f: 2), (f: 3)] +destroy +destroy +destroy +sink +sink +destroy +copy +(f: 1) +destroy +destroy +part-to-whole assigment: +sink +(children: @[]) +destroy +sink +(children: @[]) +destroy +copy +destroy +(f: 1) +destroy ''' """ @@ -223,7 +293,7 @@ when false: # bug #13456 -iterator combinations[T](s: openarray[T], k: int): seq[T] = +iterator combinations[T](s: openArray[T], k: int): seq[T] = let n = len(s) assert k >= 0 and k <= n var pos = newSeq[int](k) @@ -325,3 +395,447 @@ proc update() = for i in 1..3: update() + + +# bug #14961 +type + Foo = object + data: seq[int] + +proc initFoo(len: int): Foo = + result = (let s = newSeq[int](len); Foo(data: s) ) + +var f = initFoo(2) +echo initFoo(2) + +proc initFoo2(len: int) = + echo if true: + let s = newSeq[int](len); Foo(data: s) + else: + let s = newSeq[int](len); Foo(data: s) + +initFoo2(2) + +proc initFoo3(len: int) = + echo (block: + let s = newSeq[int](len); Foo(data: s)) + +initFoo3(2) + +proc initFoo4(len: int) = + echo (let s = newSeq[int](len); Foo(data: s)) + +initFoo4(2) + +proc initFoo5(len: int) = + echo (case true + of true: + let s = newSeq[int](len); Foo(data: s) + of false: + let s = newSeq[int](len); Foo(data: s)) + +initFoo5(2) + +proc initFoo6(len: int) = + echo (block: + try: + let s = newSeq[int](len); Foo(data: s) + finally: discard) + +initFoo6(2) + +proc initFoo7(len: int) = + echo (block: + try: + raise newException(CatchableError, "sup") + let s = newSeq[int](len); Foo(data: s) + except CatchableError: + let s = newSeq[int](len); Foo(data: s) ) + +initFoo7(2) + + +# bug #14902 +iterator zip[T](s: openArray[T]): (T, T) = + var i = 0 + while i < 10: + yield (s[i mod 2], s[i mod 2 + 1]) + inc i + +var lastMem = int.high + +proc leak = + const len = 10 + var x = @[newString(len), newString(len), newString(len)] + + var c = 0 + for (a, b) in zip(x): + let newMem = getOccupiedMem() + assert newMem <= lastMem + lastMem = newMem + c += a.len + echo c + +leak() + + +proc consume(a: sink string) = echo a + +proc weirdScopes = + if (let a = "hey"; a.len > 0): + echo a + + while (let a = "hey"; a.len > 0): + echo a + break + + var a = block: (a: "a", b: 2) + echo a + (discard; a) = (echo "ho"; (a: "b", b: 3)) + echo a + + var b = try: (b: "b", a: 2) + except: raise + echo b + (discard; b) = (echo "ho"; (b: "a", a: 3)) + echo b + + var s = "break" + consume((echo "hey"; s)) + echo s + + echo (block: + var a = "hey" + (echo "hey"; "ho")) + + var b2 = "ho" + echo (block: + var a = "hey" + (echo "hey"; b2)) + echo b2 + + type status = enum + alive + + var king = "king" + echo (block: + var a = "a" + when true: + var b = "b" + case alive + of alive: + try: + var c = "c" + if true: + king + else: + "the abyss" + except: + echo "he ded" + "dead king") + echo "live long; long live" + echo king + +weirdScopes() + + +# bug #14985 +proc getScope(): string = + if true: + return "hi" + else: + "else" + +echo getScope() + +proc getScope3(): string = + try: + "try" + except: + return "except" + +echo getScope3() + +proc getScope2(): string = + case true + of true: + return "bye" + else: + "else" + +echo getScope2() + + +#-------------------------------------------------------------------- +#bug #15609 + +type + Wrapper = object + discard + +proc newWrapper(): ref Wrapper = + new(result) + result + + +proc newWrapper2(a: int): ref Wrapper = + new(result) + if a > 0: + result + else: + new(Wrapper) + + +let w1 = newWrapper() +echo $w1[] + +let w2 = newWrapper2(1) +echo $w2[] + +let w3 = newWrapper2(-1) +echo $w3[] + + +#-------------------------------------------------------------------- +#self-assignments + +# Self-assignments that are not statically determinable will get +# turned into `=copy` calls as caseBracketExprCopy demonstrates. +# (`=copy` handles self-assignments at runtime) + +type + OO = object + f: int + W = object + o: OO + +proc `=destroy`(x: var OO) = + if x.f != 0: + echo "destroy" + x.f = 0 + +proc `=sink`(x: var OO, y: OO) = + `=destroy`(x) + echo "sink" + x.f = y.f + +proc `=copy`(x: var OO, y: OO) = + if x.f != y.f: + `=destroy`(x) + echo "copy" + x.f = y.f + else: + echo "copy (self-assign)" + +proc caseSym = + var o = OO(f: 1) + o = o # NOOP + echo o.f # "1" + # "destroy" + +caseSym() + +proc caseDotExpr = + var w = W(o: OO(f: 1)) + w.o = w.o # NOOP + echo w.o.f # "1" + # "destroy" + +caseDotExpr() + +proc caseBracketExpr = + var w = [0: OO(f: 1)] + w[0] = w[0] # NOOP + echo w[0].f # "1" + # "destroy" + +caseBracketExpr() + +proc caseBracketExprCopy = + var w = [0: OO(f: 1)] + let i = 0 + w[i] = w[0] # "copy (self-assign)" + echo w[0].f # "1" + # "destroy" + +caseBracketExprCopy() + +proc caseDotExprAddr = + var w = W(o: OO(f: 1)) + w.o = addr(w.o)[] # NOOP + echo w.o.f # "1" + # "destroy" + +caseDotExprAddr() + +proc caseBracketExprAddr = + var w = [0: OO(f: 1)] + addr(w[0])[] = addr(addr(w[0])[])[] # NOOP + echo w[0].f # "1" + # "destroy" + +caseBracketExprAddr() + +proc caseNotAConstant = + var i = 0 + proc rand: int = + result = i + inc i + var s = @[OO(f: 1), OO(f: 2), OO(f: 3)] + s[rand()] = s[rand()] # "destroy" "copy" + echo s # @[(f: 2), (f: 2), (f: 3)] + +caseNotAConstant() + +proc potentialSelfAssign(i: var int) = + var a: array[2, OO] + a[i] = OO(f: 1) # turned into a memcopy + a[1] = OO(f: 2) + a[i+1] = a[i] # This must not =sink, but =copy + inc i + echo a[i-1] # (f: 1) + +potentialSelfAssign (var xi = 0; xi) + + +#-------------------------------------------------------------------- +echo "part-to-whole assigment:" + +type + Tree = object + children: seq[Tree] + + TreeDefaultHooks = object + children: seq[TreeDefaultHooks] + +proc `=destroy`(x: var Tree) = echo "destroy" +proc `=sink`(x: var Tree, y: Tree) = echo "sink" +proc `=copy`(x: var Tree, y: Tree) = echo "copy" + +proc partToWholeSeq = + var t = Tree(children: @[Tree()]) + t = t.children[0] # This should be sunk, but with the special transform (tmp = t.children[0]; wasMoved(0); `=sink`(t, tmp)) + + var tc = TreeDefaultHooks(children: @[TreeDefaultHooks()]) + tc = tc.children[0] # Ditto; if this were sunk with the normal transform (`=sink`(t, t.children[0]); wasMoved(t.children[0])) + echo tc # then it would crash because t.children[0] does not exist after the call to `=sink` + +partToWholeSeq() + +proc partToWholeSeqRTIndex = + var i = 0 + var t = Tree(children: @[Tree()]) + t = t.children[i] # See comment in partToWholeSeq + + var tc = TreeDefaultHooks(children: @[TreeDefaultHooks()]) + tc = tc.children[i] # See comment in partToWholeSeq + echo tc + +partToWholeSeqRTIndex() + +type List = object + next: ref List + +proc `=destroy`(x: var List) = echo "destroy" +proc `=sink`(x: var List, y: List) = echo "sink" +proc `=copy`(x: var List, y: List) = echo "copy" + +proc partToWholeUnownedRef = + var t = List(next: new List) + t = t.next[] # Copy because t.next is not an owned ref, and thus t.next[] cannot be moved + +partToWholeUnownedRef() + + +#-------------------------------------------------------------------- +# test that nodes that get copied during the transformation +# (like dot exprs) don't loose their firstWrite/lastRead property + +type + OOO = object + initialized: bool + + C = object + o: OOO + +proc `=destroy`(o: var OOO) = + doAssert o.initialized, "OOO was destroyed before initialization!" + +proc initO(): OOO = + OOO(initialized: true) + +proc initC(): C = + C(o: initO()) + +proc pair(): tuple[a: C, b: C] = + 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() + + +# bug #17450 +proc noConsume(x: OO) {.nosinks.} = echo x + +proc main3 = + var i = 1 + noConsume: + block: + OO(f: i) + +main3() + +# misc +proc smoltest(x: bool): bool = + while true: + if true: return x + +discard smoltest(true) + +# bug #18002 +type + TTypeAttachedOp = enum + attachedAsgn + attachedSink + attachedTrace + + PNode = ref object + discard + +proc genAddrOf(n: PNode) = + assert n != nil, "moved?!" + +proc atomicClosureOp = + let x = PNode() + + genAddrOf: + block: + x + + case attachedTrace + of attachedSink: discard + of attachedAsgn: discard + of attachedTrace: genAddrOf(x) + +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() |