123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842 |
- discard """
- cmd: "nim c --gc:arc $file"
- output: '''5
- (w: 5)
- (w: -5)
- c.text = hello
- c.text = hello
- p.text = hello
- p.toks = @["hello"]
- c.text = hello
- c[].text = hello
- pA.text = hello
- pA.toks = @["hello"]
- c.text = hello
- c.text = hello
- pD.text = hello
- pD.toks = @["hello"]
- c.text = hello
- c.text = hello
- pOD.text = hello
- pOD.toks = @["hello"]
- fff
- fff
- 2
- fff
- fff
- 2
- fff
- fff
- 2
- mmm
- fff
- fff
- fff
- 3
- mmm
- sink me (sink)
- assign me (not sink)
- 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
- '''
- """
- # move bug
- type
- TMyObj = object
- p: pointer
- len: int
- var destroyCounter = 0
- proc `=destroy`(o: var TMyObj) =
- if o.p != nil:
- dealloc o.p
- o.p = nil
- inc destroyCounter
- proc `=`(dst: var TMyObj, src: TMyObj) =
- `=destroy`(dst)
- dst.p = alloc(src.len)
- dst.len = src.len
- proc `=sink`(dst: var TMyObj, src: TMyObj) =
- `=destroy`(dst)
- dst.p = src.p
- dst.len = src.len
- type
- TObjKind = enum Z, A, B
- TCaseObj = object
- case kind: TObjKind
- of Z: discard
- of A:
- x1: int # this int plays important role
- x2: TMyObj
- of B:
- y: TMyObj
- proc use(a: TCaseObj) = discard
- proc moveBug(i: var int) =
- var a: array[2, TCaseObj]
- a[i] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5))) # 1
- a[i+1] = a[i] # 2
- inc i
- use(a[i-1])
- var x = 0
- moveBug(x)
- proc moveBug2(): (TCaseObj, TCaseObj) =
- var a: array[2, TCaseObj]
- a[0] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5)))
- a[1] = a[0] # can move 3
- result[0] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5))) # 4
- result[1] = result[0] # 5
- proc main =
- discard moveBug2()
- main()
- echo destroyCounter
- # bug #13314
- type
- O = object
- v: int
- R = ref object
- w: int
- proc `$`(r: R): string = $r[]
- proc tbug13314 =
- var t5 = R(w: 5)
- var execute = proc () =
- echo t5
- execute()
- t5.w = -5
- execute()
- tbug13314()
- #-------------------------------------------------------------------------
- # bug #13368
- import strutils
- proc procStat() =
- for line in @["a b", "c d", "e f"]:
- let cols = line.splitWhitespace(maxSplit=1)
- let x = cols[0]
- let (nm, rest) = (cols[0], cols[1])
- procStat()
- # bug #14269
- import sugar, strutils
- type
- Cursor = object
- text: string
- Parsed = object
- text: string
- toks: seq[string]
- proc tokenize(c: var Cursor): seq[string] =
- dump c.text
- return c.text.splitWhitespace()
- proc parse(): Parsed =
- var c = Cursor(text: "hello")
- dump c.text
- return Parsed(text: c.text, toks: c.tokenize) # note: c.tokenized uses c.text
- let p = parse()
- dump p.text
- dump p.toks
- proc tokenizeA(c: ptr Cursor): seq[string] =
- dump c[].text
- return c[].text.splitWhitespace()
- proc parseA(): Parsed =
- var c = Cursor(text: "hello")
- dump c.text
- return Parsed(text: c.text, toks: c.addr.tokenizeA) # note: c.tokenized uses c.text
- let pA = parseA()
- dump pA.text
- dump pA.toks
- proc tokenizeD(c: Cursor): seq[string] =
- dump c.text
- return c.text.splitWhitespace()
- proc parseD(): Parsed =
- var c = cast[ptr Cursor](alloc0(sizeof(Cursor)))
- c[] = Cursor(text: "hello")
- dump c.text
- return Parsed(text: c.text, toks: c[].tokenizeD) # note: c.tokenized uses c.text
- let pD = parseD()
- dump pD.text
- dump pD.toks
- # Bug would only pop up with owned refs
- proc tokenizeOD(c: Cursor): seq[string] =
- dump c.text
- return c.text.splitWhitespace()
- proc parseOD(): Parsed =
- var c = new Cursor
- c[] = Cursor(text: "hello")
- dump c.text
- return Parsed(text: c.text, toks: c[].tokenizeOD) # note: c.tokenized uses c.text
- let pOD = parseOD()
- dump pOD.text
- dump pOD.toks
- when false:
- # Bug would only pop up with owned refs and implicit derefs, but since they don't work together..
- {.experimental: "implicitDeref".}
- proc tokenizeOHD(c: Cursor): seq[string] =
- dump c.text
- return c.text.splitWhitespace()
- proc parseOHD(): Parsed =
- var c = new Cursor
- c[] = Cursor(text: "hello")
- dump c.text
- return Parsed(text: c.text, toks: c.tokenizeOHD) # note: c.tokenized uses c.text
- let pOHD = parseOHD()
- dump pOHD.text
- dump pOHD.toks
- # bug #13456
- 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)
- var current = newSeq[T](k)
- for i in 0..k-1:
- pos[k-i-1] = i
- var done = false
- while not done:
- for i in 0..k-1:
- current[i] = s[pos[k-i-1]]
- yield current
- var i = 0
- while i < k:
- pos[i] += 1
- if pos[i] < n-i:
- for j in 0..i-1:
- pos[j] = pos[i] + i - j
- break
- i += 1
- if i >= k:
- break
- type
- UndefEx = object of ValueError
- proc main2 =
- var delayedSyms = @[1, 2, 3]
- var unp: seq[int]
- block myb:
- for a in 1 .. 2:
- if delayedSyms.len > a:
- unp = delayedSyms
- for t in unp.combinations(a + 1):
- try:
- var h = false
- for k in t:
- echo "fff"
- if h: continue
- if true:
- raise newException(UndefEx, "forward declaration")
- break myb
- except UndefEx:
- echo t.len
- echo "mmm"
- main2()
- type ME = object
- who: string
- proc `=`(x: var ME, y: ME) =
- if y.who.len > 0: echo "assign ",y.who
- proc `=sink`(x: var ME, y: ME) =
- if y.who.len > 0: echo "sink ",y.who
- var dump: ME
- template use(x) = dump = x
- template def(x) = x = dump
- var c = true
- proc shouldSink() =
- var x = ME(who: "me (sink)")
- use(x) # we analyse this
- if c: def(x)
- else: def(x)
- use(x) # ok, with the [else] part.
- shouldSink()
- dump = ME()
- proc shouldNotSink() =
- var x = ME(who: "me (not sink)")
- use(x) # we analyse this
- if c: def(x)
- use(x) # Not ok without the '[else]'
- shouldNotSink()
- # bug #14568
- import os
- type O2 = object
- s: seq[int]
- proc `=sink`(dest: var O2, src: O2) =
- echo "sinked and not optimized to a bitcopy"
- var testSeq: O2
- proc update() =
- # testSeq.add(0) # uncommenting this line fixes the leak
- testSeq = O2(s: @[])
- testSeq.s.add(0)
- 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()
|