summary refs log tree commit diff stats
path: root/tests/iter
diff options
context:
space:
mode:
Diffstat (limited to 'tests/iter')
-rw-r--r--tests/iter/t1550.nim24
-rw-r--r--tests/iter/t16076.nim45
-rw-r--r--tests/iter/t20891.nim28
-rw-r--r--tests/iter/t21306.nim118
-rw-r--r--tests/iter/t21737.nim22
-rw-r--r--tests/iter/t22148.nim15
-rw-r--r--tests/iter/t22548.nim21
-rw-r--r--tests/iter/t22619.nim83
-rw-r--r--tests/iter/t2771.nim25
-rw-r--r--tests/iter/tanoniter1.nim33
-rw-r--r--tests/iter/tarrayiter.nim14
-rw-r--r--tests/iter/tchainediterators.nim41
-rw-r--r--tests/iter/tclosureiters.nim176
-rw-r--r--tests/iter/tcountup.nim25
-rw-r--r--tests/iter/tgeniteratorinblock.nim54
-rw-r--r--tests/iter/timplicit_auto.nim18
-rw-r--r--tests/iter/titer.nim147
-rw-r--r--tests/iter/titer10.nim51
-rw-r--r--tests/iter/titer11.nim40
-rw-r--r--tests/iter/titer12.nim83
-rw-r--r--tests/iter/titer13.nim83
-rw-r--r--tests/iter/titer14.nim7
-rw-r--r--tests/iter/titer2.nim66
-rw-r--r--tests/iter/titer3.nim54
-rw-r--r--tests/iter/titer4.nim8
-rw-r--r--tests/iter/titer5.nim13
-rw-r--r--tests/iter/titer6.nim35
-rw-r--r--tests/iter/titer7.nim53
-rw-r--r--tests/iter/titer8.nim117
-rw-r--r--tests/iter/titer9.nim20
-rw-r--r--tests/iter/titer_issues.nim411
-rw-r--r--tests/iter/titer_no_tuple_unpack.nim27
-rw-r--r--tests/iter/titerable.nim29
-rw-r--r--tests/iter/titerautoerr1.nim8
-rw-r--r--tests/iter/titerautoerr2.nim8
-rw-r--r--tests/iter/titerautoerr3.nim9
-rw-r--r--tests/iter/titerconcat.nim24
-rw-r--r--tests/iter/titerovl.nim21
-rw-r--r--tests/iter/titerslice.nim9
-rw-r--r--tests/iter/titertypedesc.nim17
-rw-r--r--tests/iter/titervaropenarray.nim15
-rw-r--r--tests/iter/tmoditer.nim88
-rw-r--r--tests/iter/tpermutations.nim69
-rw-r--r--tests/iter/treciter.nim12
-rw-r--r--tests/iter/tscheduler.nim77
-rw-r--r--tests/iter/tshallowcopy_closures.nim36
-rw-r--r--tests/iter/twrap_walkdir.nim17
-rw-r--r--tests/iter/twrongiter.nim13
-rw-r--r--tests/iter/tyieldintry.nim529
49 files changed, 2938 insertions, 0 deletions
diff --git a/tests/iter/t1550.nim b/tests/iter/t1550.nim
new file mode 100644
index 000000000..c971943ee
--- /dev/null
+++ b/tests/iter/t1550.nim
@@ -0,0 +1,24 @@
+discard """
+  targets: "c js"
+"""
+
+type
+  A[T] = iterator(x: T): T {.gcsafe, closure.}
+
+iterator aimp[T](x: T): T {.gcsafe, closure.} =
+  var total = 0
+  while (total < 100):
+    yield total
+    total += x
+
+iterator bimp(y: A[int], z:int): int {.gcsafe, closure.} =
+  for i in y(z):
+    yield i
+
+for x in aimp[int](3):
+  discard x
+
+var y = aimp[int]
+var z = bimp
+for x in z(y, 1):
+  discard x
\ No newline at end of file
diff --git a/tests/iter/t16076.nim b/tests/iter/t16076.nim
new file mode 100644
index 000000000..2eb409068
--- /dev/null
+++ b/tests/iter/t16076.nim
@@ -0,0 +1,45 @@
+discard """
+  targets: "c js"
+"""
+
+proc main() =
+  block: # bug #17485
+    type
+      O = ref object
+        i: int
+
+    iterator t(o: O): int =
+      if o != nil:
+        yield o.i
+      yield 0
+
+    proc m =
+      var data = ""
+      for i in t(nil):
+        data.addInt i
+
+      doAssert data == "0"
+
+    m()
+
+
+  block: # bug #16076
+    type
+      R = ref object
+        z: int
+
+    var data = ""
+
+    iterator foo(x: int; y: R = nil): int {.inline.} =
+      if y == nil:
+        yield x
+      else:
+        yield y.z
+
+    for b in foo(10):
+      data.addInt b
+
+    doAssert data == "10"
+
+static: main()
+main()
diff --git a/tests/iter/t20891.nim b/tests/iter/t20891.nim
new file mode 100644
index 000000000..34deec41b
--- /dev/null
+++ b/tests/iter/t20891.nim
@@ -0,0 +1,28 @@
+import macros, tables
+
+var mapping {.compileTime.}: Table[string, NimNode]
+
+macro register(a: static[string], b: typed): untyped =
+  mapping[a] = b
+
+macro getPtr(a: static[string]): untyped =
+  result = mapping[a]
+
+proc foo() =
+  iterator it() {.closure.} =
+    discard
+  proc getIterPtr(): pointer {.nimcall.} =
+    rawProc(it)
+  register("foo", getIterPtr())
+  discard getIterPtr() # Comment either this to make it work
+foo() # or this
+
+proc bar() =
+  iterator it() {.closure.} =
+    discard getPtr("foo") # Or this
+    discard
+  proc getIterPtr(): pointer {.nimcall.} =
+    rawProc(it)
+  register("bar", getIterPtr())
+  discard getIterPtr()
+bar()
diff --git a/tests/iter/t21306.nim b/tests/iter/t21306.nim
new file mode 100644
index 000000000..4d0396294
--- /dev/null
+++ b/tests/iter/t21306.nim
@@ -0,0 +1,118 @@
+discard """
+  targets: "c js"
+"""
+
+# bug #21306
+type
+  FutureState {.pure.} = enum
+    Pending, Finished, Cancelled, Failed
+
+  FutureBase = ref object of RootObj
+    state: FutureState
+    error: ref CatchableError
+    id: uint
+
+  Future[T] = ref object of FutureBase
+    closure: iterator(f: Future[T]): FutureBase {.raises: [Defect, CatchableError, Exception], gcsafe.}
+    value: T
+
+template setupFutureBase() =
+  new(result)
+  result.state = FutureState.Pending
+
+proc newFutureImpl[T](): Future[T] =
+  setupFutureBase()
+
+template newFuture[T](fromProc: static[string] = ""): Future[T] =
+  newFutureImpl[T]()
+
+proc internalRead[T](fut: Future[T]): T =
+  when T isnot void:
+    return fut.value
+
+template await[T](f: Future[T]): untyped =
+  when declared(chronosInternalRetFuture):
+    when not declaredInScope(chronosInternalTmpFuture):
+      var chronosInternalTmpFuture {.inject.}: FutureBase = f
+    else:
+      chronosInternalTmpFuture = f
+
+    yield chronosInternalTmpFuture
+
+    when T isnot void:
+      cast[type(f)](chronosInternalTmpFuture).internalRead()
+
+type
+  VerifierError {.pure.} = enum
+    Invalid
+    MissingParent
+    UnviableFork
+    Duplicate
+  ProcessingCallback = proc() {.gcsafe, raises: [Defect].}
+  BlockVerifier =
+    proc(signedBlock: int):
+      Future[VerifierError] {.gcsafe, raises: [Defect].}
+
+  SyncQueueKind {.pure.} = enum
+    Forward, Backward
+
+  SyncRequest[T] = object
+    kind: SyncQueueKind
+    index: uint64
+    slot: uint64
+    count: uint64
+    item: T
+
+  SyncResult[T] = object
+    request: SyncRequest[T]
+    data: seq[ref int]
+
+  SyncQueue[T] = ref object
+    kind: SyncQueueKind
+    readyQueue: seq[SyncResult[T]]
+    blockVerifier: BlockVerifier
+
+iterator blocks[T](sq: SyncQueue[T],
+                    sr: SyncResult[T]): ref int =
+  case sq.kind
+  of SyncQueueKind.Forward:
+    for i in countup(0, len(sr.data) - 1):
+      yield sr.data[i]
+  of SyncQueueKind.Backward:
+    for i in countdown(len(sr.data) - 1, 0):
+      yield sr.data[i]
+
+proc push[T](sq: SyncQueue[T]; sr: SyncRequest[T]; data: seq[ref int];
+             processingCb: ProcessingCallback = nil): Future[void] {.
+    stackTrace: off, gcsafe.} =
+  iterator push_436208182(chronosInternalRetFuture: Future[void]): FutureBase {.
+      closure, gcsafe, raises: [Defect, CatchableError, Exception].} =
+    block:
+      template result(): auto {.used.} =
+        {.fatal: "You should not reference the `result` variable inside" &
+            " a void async proc".}
+
+      let item = default(SyncResult[T])
+      for blk in sq.blocks(item):
+        let res = await sq.blockVerifier(blk[])
+
+  var resultFuture = newFuture[void]("push")
+  resultFuture.closure = push_436208182
+  return resultFuture
+
+type
+  SomeTPeer = ref object
+    score: int
+
+proc getSlice(): seq[ref int] =
+  discard
+
+template smokeTest(kkind: SyncQueueKind, start, finish: uint64,
+                   chunkSize: uint64) =
+  var queue: SyncQueue[SomeTPeer]
+  var request: SyncRequest[SomeTPeer]
+  discard queue.push(request, getSlice())
+
+for k in {SyncQueueKind.Forward}:
+  for item in [(uint64(1181), uint64(1399), 41'u64)]:
+    smokeTest(k, item[0], item[1], item[2])
\ No newline at end of file
diff --git a/tests/iter/t21737.nim b/tests/iter/t21737.nim
new file mode 100644
index 000000000..da06faea7
--- /dev/null
+++ b/tests/iter/t21737.nim
@@ -0,0 +1,22 @@
+discard """
+  action: compile
+"""
+
+template mytoSeq*(iter: untyped): untyped =
+  var result: seq[typeof(iter)]# = @[]
+  for x in iter:
+    result.add(x)
+  result
+
+iterator test(dir:int): int =
+  yield 1234
+
+iterator walkGlobKinds (): int =
+  let dir2 = 123
+  let it = mytoSeq(test(dir2))  
+
+proc main()=
+    let it = iterator(): int=
+      for path in walkGlobKinds():
+          yield path
+main()
diff --git a/tests/iter/t22148.nim b/tests/iter/t22148.nim
new file mode 100644
index 000000000..9954eed87
--- /dev/null
+++ b/tests/iter/t22148.nim
@@ -0,0 +1,15 @@
+discard """

+  action: compile

+"""

+

+import std/memfiles

+

+# bug #22148

+proc make*(input: string) =

+  var inp = memfiles.open(input)

+  for line in memSlices(inp):

+    let lineF = MemFile(mem: line.data, size: line.size)

+    for word in memSlices(lineF, ','):

+      discard

+

+make("") # Must call to trigger

diff --git a/tests/iter/t22548.nim b/tests/iter/t22548.nim
new file mode 100644
index 000000000..b9abb75d0
--- /dev/null
+++ b/tests/iter/t22548.nim
@@ -0,0 +1,21 @@
+discard """
+  action: compile
+"""
+
+type Xxx[T] = object
+
+iterator x(v: string): char =
+  var v2: Xxx[int]
+
+  var y: v2.T
+
+  echo y
+
+proc bbb(vv: string): proc () =
+  proc xxx() =
+    for c in x(vv):
+      echo c
+
+  return xxx
+
+bbb("test")()
diff --git a/tests/iter/t22619.nim b/tests/iter/t22619.nim
new file mode 100644
index 000000000..6a98391f3
--- /dev/null
+++ b/tests/iter/t22619.nim
@@ -0,0 +1,83 @@
+# bug #22619
+
+when false: # todo fixme
+  block:
+    type
+      Resource = object
+        value: int
+  
+      Object = object
+        r {.cursor.}: Resource
+        s {.cursor.}: seq[Resource]
+  
+    var numDestroy = 0
+  
+    proc `=copy`(x: var Resource, y: Resource) {.error.} # disallow full copies
+    proc `=destroy`(x: Resource) =
+      inc numDestroy
+  
+    proc test() =
+      # perform the test in procedure so that globals aren't used (their different
+      # semantics with regards to destruction would interfere)
+      var
+        r = Resource(value: 1) # initialize a resource
+        s = @[Resource(value: 2)]
+  
+      # make sure no copy is required in the initializer expression:
+      var o = Object(r: r, s: s)
+  
+      # copying the object doesn't perform a full copy of the cursor fields:
+      var o2 = o
+      discard addr(o2) # prevent `o2` from being turned into a cursor
+  
+      # check that the fields were shallow-copied:
+      doAssert o2.r.value == 1
+      doAssert o2.s[0].value == 2
+  
+      # make sure no copy is required with normal field assignments:
+      o.r = r
+      o.s = s
+  
+  
+      # when `o` and `o2` are destroyed, their destructor must not be called on
+      # their fields
+  
+    test()
+  
+    # one call for the `r` local and one for the object in `s`
+    doAssert numDestroy == 2
+
+block:
+  type Value = distinct int
+
+  var numDestroy = 0
+
+  when defined(gcRefc):
+    proc `=destroy`(x: var Value) =
+      inc numDestroy
+  else:
+    proc `=destroy`(x: Value) =
+      inc numDestroy
+
+  iterator iter(s: seq[Value]): int {.closure.} =
+    # because it is used across yields, `s2` is lifted into the iterator's
+    # environment. Since non-ref cursors in object didn't have their hooks
+    # disabled inside the environments lifted hooks, this led to double
+    # frees
+    var s2 {.cursor.} = s
+    var i = 0
+    let L = s2.len
+    while i < L:
+      yield s2[i].int
+      inc i
+
+  proc test() =
+    var s = @[Value(1), Value(2)]
+    let cl = iter
+    # make sure resuming the iterator works:
+    doAssert cl(s) == 1
+    doAssert cl(s) == 2
+    doAssert cl(s) == 0
+
+  test()
+  doAssert numDestroy == 2
diff --git a/tests/iter/t2771.nim b/tests/iter/t2771.nim
new file mode 100644
index 000000000..71a8a9dcd
--- /dev/null
+++ b/tests/iter/t2771.nim
@@ -0,0 +1,25 @@
+discard """
+  targets: "c js"
+"""
+
+template t1(i: int): int=
+  i+1
+template t2(i: int): int=
+  i+1
+
+doAssert t1(10).t2() == 12
+
+
+template it1(i: int): iterator(): int =
+  iterator result(): int {.closure, gensym.} =
+    yield i+1
+  result
+
+template it2(iter: iterator(): int): iterator(): int =
+  iterator result(): int {.closure, gensym.} =
+    yield iter()+1
+  result
+
+let x2 = it1(10).it2()
+
+doAssert x2() == 12
diff --git a/tests/iter/tanoniter1.nim b/tests/iter/tanoniter1.nim
new file mode 100644
index 000000000..fee16497f
--- /dev/null
+++ b/tests/iter/tanoniter1.nim
@@ -0,0 +1,33 @@
+discard """
+  targets: "c js"
+  output: '''1
+2
+3
+4
+1
+2'''
+"""
+
+proc factory(a, b: int): iterator (): int =
+  iterator foo(): int {.closure.} =
+    var x = a
+    while x <= b:
+      yield x
+      inc x
+  return foo
+
+proc factory2(a, b: int): iterator (): int =
+  return iterator (): int =
+    var x = a
+    while x <= b:
+      yield x
+      inc x
+
+let foo = factory(1, 4)
+
+for f in foo():
+  echo f
+
+let foo2 = factory2(1,2)
+
+for f in foo2(): echo f
diff --git a/tests/iter/tarrayiter.nim b/tests/iter/tarrayiter.nim
new file mode 100644
index 000000000..eb7ba591a
--- /dev/null
+++ b/tests/iter/tarrayiter.nim
@@ -0,0 +1,14 @@
+block:
+  iterator `[]`(a: int, r: int): int = 
+    for q in 0 .. r:
+      yield a
+    
+  for val in 10[2]: discard
+  
+  type Custom = distinct string
+
+  iterator `[]`(a: Custom, r: int): char = 
+    for q in 0 .. r:
+      yield a.string[q]
+      
+  for val in Custom("test")[2]: discard
\ No newline at end of file
diff --git a/tests/iter/tchainediterators.nim b/tests/iter/tchainediterators.nim
new file mode 100644
index 000000000..796672783
--- /dev/null
+++ b/tests/iter/tchainediterators.nim
@@ -0,0 +1,41 @@
+discard """
+  output: '''16
+32
+48
+64
+128
+192
+'''
+  disabled: "true"
+"""
+
+# This all relies on non-documented and questionable features.
+
+iterator gaz(it: iterator{.inline.}): type(it) =
+  for x in it:
+    yield x*2
+
+iterator baz(it: iterator{.inline.}): auto =
+  for x in gaz(it):
+    yield x*2
+
+type T1 = auto
+
+iterator bar(it: iterator: T1{.inline.}): T1 =
+  for x in baz(it):
+    yield x*2
+
+iterator foo[T](x: iterator: T{.inline.}): T =
+  for e in bar(x):
+    yield e*2
+
+var s = @[1, 2, 3]
+
+# pass an iterator several levels deep:
+for x in s.items.foo:
+  echo x
+
+# use some complex iterator as an input for another one:
+for x in s.items.baz.foo:
+  echo x
+
diff --git a/tests/iter/tclosureiters.nim b/tests/iter/tclosureiters.nim
new file mode 100644
index 000000000..4a2639852
--- /dev/null
+++ b/tests/iter/tclosureiters.nim
@@ -0,0 +1,176 @@
+discard """
+  targets: "c js"
+  output: '''0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+5 5
+7 7
+9 9
+0
+0
+0
+0
+1
+2
+70
+0
+(1, 1)
+(1, 2)
+(1, 3)
+(2, 1)
+(2, 2)
+(2, 3)
+(3, 1)
+(3, 2)
+(3, 3)
+'''
+"""
+
+when true:
+  proc main() =
+    let
+      lo=0
+      hi=10
+
+    iterator itA(): int =
+      for x in lo..hi:
+        yield x
+
+    for x in itA():
+      echo x
+
+    var y: int
+
+    iterator itB(): int =
+      while y <= hi:
+        yield y
+        inc y
+
+    y = 5
+    for x in itB():
+      echo x, " ", y
+      inc y
+
+  main()
+
+
+iterator infinite(): int {.closure.} =
+  var i = 0
+  while true:
+    yield i
+    inc i
+
+iterator take[T](it: iterator (): T, numToTake: int): T {.closure.} =
+  var i = 0
+  for x in it():
+    if i >= numToTake:
+      break
+    yield x
+    inc i
+
+# gives wrong reasult (3 times 0)
+for x in infinite.take(3):
+  echo x
+
+# does what we want
+let inf = infinite
+for x in inf.take(3):
+  echo x
+
+# bug #3583
+proc foo(f: (iterator(): int)) =
+  for i in f(): echo i
+
+let fIt = iterator(): int = yield 70
+foo fIt
+
+# bug #5321
+
+proc lineIter*(filename: string): iterator(): string =
+  result = iterator(): string {.closure.} =
+    for line in lines(filename):
+      yield line
+
+proc unused =
+  var count = 0
+  let iter = lineIter("temp10.nim")
+  for line in iter():
+    count += 1
+
+iterator lineIter2*(filename: string): string {.closure.} =
+  var f = open(filename, bufSize=8000)
+  defer: close(f)   # <-- commenting defer "solves" the problem
+  var res = newStringOfCap(80)
+  while f.readLine(res): yield res
+
+proc unusedB =
+  var count = 0
+  for line in lineIter2("temp10.nim"):
+    count += 1
+
+# bug #5519
+import os, algorithm
+
+iterator filesIt(path: string): auto {.closure.} =
+  var files = newSeq[string]()
+  var dirs = newSeq[string]()
+  for k, p in os.walkDir(path):
+    let (_, n, e) = p.splitFile
+    if e != "":
+      continue
+    case k
+    of pcFile, pcLinkToFile:
+      files.add(n)
+    else:
+      dirs.add(n)
+  files.sort(system.cmp)
+  dirs.sort(system.cmp)
+  for f in files:
+    yield f
+
+  for d in dirs:
+    files = newSeq[string]()
+    for k, p in os.walkDir(path / d):
+      let (_, n, e) = p.splitFile
+      if e != "":
+        continue
+      case k
+      of pcFile, pcLinkToFile:
+        files.add(n)
+      else:
+        discard
+    files.sort(system.cmp)
+    let prefix = path.splitPath[1]
+    for f in files:
+      yield prefix / f
+
+# bug #13815
+when not defined(js):
+  var love = iterator: int {.closure.} =
+    yield cast[type(
+      block:
+        var a = 0
+        yield a
+        a)](0)
+
+  for i in love():
+    echo i
+else:
+  echo 0
+
+# bug #18474
+iterator pairs(): (int, int) {.closure.} =
+  for i in 1..3:
+    for j in 1..3:
+      yield (i, j)
+
+for pair in pairs():
+  echo pair
diff --git a/tests/iter/tcountup.nim b/tests/iter/tcountup.nim
new file mode 100644
index 000000000..5f75e653c
--- /dev/null
+++ b/tests/iter/tcountup.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''
+0123456789
+0.0
+'''
+"""
+
+# Test new countup
+
+for i in 0 ..< 10'i64:
+  stdout.write(i)
+
+echo()
+
+# 11099
+
+var
+  x: uint32
+  y: float
+
+for i in 0 ..< x:
+  if i == 1: echo i
+  y += 1
+
+echo y
diff --git a/tests/iter/tgeniteratorinblock.nim b/tests/iter/tgeniteratorinblock.nim
new file mode 100644
index 000000000..2ab903996
--- /dev/null
+++ b/tests/iter/tgeniteratorinblock.nim
@@ -0,0 +1,54 @@
+discard """
+  output: '''30
+60
+90
+150
+180
+210
+240
+60
+180
+240
+[60, 180, 240]
+[60, 180]'''
+"""
+import std/enumerate
+
+template map[T; Y](i: iterable[T], fn: proc(x: T): Y): untyped =
+  iterator internal(): Y  {.gensym.} =
+    for it in i:
+      yield fn(it)
+  internal()
+
+template filter[T](i: iterable[T], fn: proc(x: T): bool): untyped =
+  iterator internal(): T {.gensym.} =
+    for it in i:
+      if fn(it):
+        yield it
+  internal()
+
+template group[T](i: iterable[T], amount: static int): untyped =
+  iterator internal(): array[amount, T] {.gensym.} =
+    var val: array[amount, T]
+    for ind, it in enumerate i:
+      val[ind mod amount] = it
+      if ind mod amount == amount - 1:
+        yield val
+  internal()
+
+var a = [10, 20, 30, 50, 60, 70, 80]
+
+proc mapFn(x: int): int = x * 3
+proc filterFn(x: int): bool = x mod 20 == 0
+
+for x in a.items.map(mapFn):
+  echo x
+
+for y in a.items.map(mapFn).filter(filterFn):
+  echo y
+
+for y in a.items.map(mapFn).filter(filterFn).group(3):
+  echo y
+
+for y in a.items.map(mapFn).filter(filterFn).group(2):
+  echo y
diff --git a/tests/iter/timplicit_auto.nim b/tests/iter/timplicit_auto.nim
new file mode 100644
index 000000000..1b9f06843
--- /dev/null
+++ b/tests/iter/timplicit_auto.nim
@@ -0,0 +1,18 @@
+# bug #1838
+
+type State = enum Empty, Tree, Fire
+
+const
+  disp: array[State, string] = ["  ", "\e[32m/\\\e[m", "\e[07;31m/\\\e[m"]
+
+proc univ(x, y: int): State = Tree
+
+var w, h = 30
+
+iterator fields(a = (0,0), b = (h-1,w-1)): auto =
+  for y in max(a[0], 0) .. min(b[0], h-1):
+    for x in max(a[1], 0) .. min(b[1], w-1):
+      yield (y,x)
+
+for y,x in fields():
+  doAssert disp[univ(x, y)] == disp[Tree]
diff --git a/tests/iter/titer.nim b/tests/iter/titer.nim
new file mode 100644
index 000000000..b03d43f36
--- /dev/null
+++ b/tests/iter/titer.nim
@@ -0,0 +1,147 @@
+discard """
+output: '''
+testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest2!test3?hi
+what's
+your
+name
+hi
+what's
+your
+name
+'''
+"""
+
+# Test the new iterators
+
+iterator xrange(fromm, to: int, step = 1): int =
+  var a = fromm
+  while a <= to:
+    yield a
+    inc(a, step)
+
+iterator interval[T](a, b: T): T =
+  var x = a
+  while x <= b:
+    yield x
+    inc(x)
+
+#
+#iterator lines(filename: string): (line: string) =
+#  var
+#    f: tTextfile
+#    shouldClose = open(f, filename)
+#  if shouldClose:
+#    setSpace(line, 256)
+#    while readTextLine(f, line):
+#      yield line
+#  finally:
+#    if shouldClose: close(f)
+#
+
+for i in xrange(0, 5):
+  for k in xrange(1, 7):
+    write(stdout, "test")
+
+for j in interval(45, 45):
+  write(stdout, "test2!")
+  write(stdout, "test3?")
+
+for x in items(["hi", "what's", "your", "name"]):
+  echo(x)
+
+const
+  stringArray = ["hi", "what's", "your", "name"]
+
+for i in 0..len(stringArray)-1:
+  echo(stringArray[i])
+
+# bug #15360
+
+type Rule[T] = (int, T)
+
+var t: seq[Rule[int]]
+for (c, t) in t:
+  discard
+
+
+
+import std/sugar
+
+# bug #14165
+iterator log_nodups_hamming(): int {.inline.} =
+  let lb3 = 1
+  let lb4 = 123
+  proc mul3(): int = lb3 + lb4
+  yield mul3()
+
+for h in log_nodups_hamming():
+  break
+for h in log_nodups_hamming():
+  break
+for h in log_nodups_hamming():
+  break
+
+# bug #18536
+iterator envPairs*(): int =
+  var foo: seq[int]
+  proc fun() =
+    foo = @[]
+  fun()
+  yield 3
+
+proc main() =
+  for a in envPairs():
+    discard
+  for a in envPairs():
+    discard
+static: main()
+main()
+
+# bug #6269
+iterator makeFn(outer_val: int): proc(a: int): int =
+  for i in 0..1:
+    yield proc(a:int): int =
+      return a + i.int
+
+let v1 = 42
+
+let res = collect:
+  for fn1 in makeFn(v1):
+    let v2 = fn1(v1)
+    for fn2 in makeFn(v2):
+      fn2(v2)
+
+doAssert res == @[42, 43, 43, 44]
+
+block: # bug #21110
+  iterator p(): int =
+    when nimvm:
+      yield 0
+    else:
+      yield 0
+
+  template foo =
+    for k in p():
+      let m = ""
+      proc e() = discard m & ""
+      e()
+  static: foo()
+  foo()
+
+
+# bug #15924
+iterator walk(): (int, int) {.closure.} =
+  yield (10,11)
+
+for (i,j) in walk():
+  doAssert i == 10
+
+proc main123() =
+  let x = false
+  iterator it(): (bool, bool) {.closure.} = # normally {.closure.} here makes #21476 work
+    discard x
+
+  for (_, _) in it():
+    discard
+
+main123()
diff --git a/tests/iter/titer10.nim b/tests/iter/titer10.nim
new file mode 100644
index 000000000..ae36aa519
--- /dev/null
+++ b/tests/iter/titer10.nim
@@ -0,0 +1,51 @@
+discard """
+  output: '''3
+2
+5
+1
+@[@[0, 0], @[0, 1]]
+@[@[0, 0], @[0, 1]]
+@[@[2, 2], @[2, 3]]
+@[@[2, 2], @[2, 3]]'''
+"""
+
+when true:
+  # bug #2604
+
+  import algorithm
+
+  iterator byDistance*[int]( ints: openArray[int], base: int ): int =
+      var sortable = @ints
+
+      sortable.sort do (a, b: int) -> int:
+          result = cmp( abs(base - a), abs(base - b) )
+
+      for val in sortable:
+          yield val
+
+  when true:
+    proc main =
+      for val in byDistance([2, 3, 5, 1], 3):
+          echo val
+    main()
+
+when true:
+  # bug #1527
+
+  import sequtils
+
+  let thread = @[@[0, 0],
+                 @[0, 1],
+                 @[2, 2],
+                 @[2, 3]]
+
+  iterator threadUniqs(seq1: seq[seq[int]]): seq[seq[int]] =
+    for i in 0 ..< seq1.len:
+      block:
+        let i = i
+        yield seq1.filter do (x: seq[int]) -> bool: x[0] == seq1[i][0]
+  proc main2 =
+    for uniqs in thread.threadUniqs:
+      echo uniqs
+
+  main2()
diff --git a/tests/iter/titer11.nim b/tests/iter/titer11.nim
new file mode 100644
index 000000000..153b3c29a
--- /dev/null
+++ b/tests/iter/titer11.nim
@@ -0,0 +1,40 @@
+discard """
+targets: "c js"
+output: '''
+[
+1
+2
+3
+]
+'''
+"""
+
+proc represent(i: int): iterator(): string =
+  result = iterator(): string =
+    yield $i
+
+proc represent(s: seq[int]): iterator(): string =
+  result = iterator(): string =
+    yield "["
+    for i in s:
+      var events = represent(i)
+      for event in events():
+        yield event
+    yield "]"
+
+let s = @[1, 2, 3]
+var output = represent(s)
+
+for item in output():
+  echo item
+
+
+#------------------------------------------------------------------------------
+# Issue #12747
+
+type
+  ABC = ref object
+      arr: array[0x40000, pointer]
+let a = ABC()
+for a in a.arr:
+    assert a == nil
\ No newline at end of file
diff --git a/tests/iter/titer12.nim b/tests/iter/titer12.nim
new file mode 100644
index 000000000..f264a0e82
--- /dev/null
+++ b/tests/iter/titer12.nim
@@ -0,0 +1,83 @@
+discard """
+targets: "c js"
+output: '''
+Selecting 2
+1.0
+Selecting 4
+2.0
+'''
+"""
+
+
+# bug #5522
+import macros, sugar, sequtils
+
+proc tryS(f: () -> void): void =
+  (try: f() except: discard)
+
+template trySTImpl(body: untyped): untyped =
+  tryS do() -> auto:
+    `body`
+
+macro tryST*(body: untyped): untyped =
+  var b = if body.kind == nnkDo: body[^1] else: body
+  result = quote do:
+    trySTImpl((block:
+      `b`
+    ))
+
+iterator testIt(): int {.closure.} =
+  for x in 0..10:
+    yield x
+
+var xs = newSeq[int]()
+proc test = tryST do:
+  for x in testIt():
+    xs.add(x)
+
+test()
+
+doAssert xs == toSeq(0..10)
+
+
+
+# bug #5690
+proc filter[T](it: (iterator : T), f: proc(x: T): bool): (iterator : T) =
+  return iterator (): T {.closure.} =
+    for x in it():
+      if f(x): 
+        yield x
+
+proc len[T](it : iterator : T) : Natural =
+  for i in it():
+    result += 1
+
+proc simpleSeqIterator(s :seq[int]) : iterator : int =
+  iterator it: int {.closure.} =
+    for x in s:
+      yield x
+  result = it
+
+let a = newSeq[int](99)
+
+doAssert len(simpleSeqIterator(a).filter(proc(x : int) : bool = true)) == 99
+
+
+
+# bug #5340
+proc where[A](input: seq[A], filter: (A) -> bool): iterator (): A =
+  result = iterator (): A {.closure.} = 
+    for item in input:
+      if filter(item):
+        yield item
+
+proc select[A,B](input: iterator(): A {.closure.}, selector: (A) -> B): iterator (): B {.closure.} = 
+  result = iterator (): B =
+    for item in input():
+      echo "Selecting " & $item
+      yield selector(item)
+
+let query = @[1,2,3,4].where(x=>x mod 2==0).select((x)=>x/2)
+
+for i in query():
+  echo $i
diff --git a/tests/iter/titer13.nim b/tests/iter/titer13.nim
new file mode 100644
index 000000000..086c40ca4
--- /dev/null
+++ b/tests/iter/titer13.nim
@@ -0,0 +1,83 @@
+discard """
+  output: '''b yields
+c yields
+a returns
+b yields
+b returns
+c yields
+
+
+1
+2
+3
+4
+'''
+"""
+
+block:
+  template tloop(iter: untyped) =
+    for i in iter():
+      echo i
+
+  template twhile(iter: untyped) =
+    let it = iter
+    while not finished(it):
+      echo it()
+
+  iterator a(): auto {.closure.} =
+    if true: return "a returns"
+    yield "a yields"
+
+  iterator b(): auto {.closure.} =
+    yield "b yields"
+    if true: return "b returns"
+
+  iterator c(): auto {.closure.} =
+    yield "c yields"
+    if true: return
+
+  iterator d(): auto {.closure.} =
+    if true: return
+    yield "d yields"
+
+  tloop(a)
+  tloop(b)
+  tloop(c)
+  tloop(d)
+  twhile(a)
+  twhile(b)
+  twhile(c)
+  twhile(d)
+
+block:
+  iterator a: auto =
+    yield 1
+  for x in a():
+    echo x
+
+  let b = iterator: int =
+    yield 2
+  for x in b():
+    echo x
+
+  let c = iterator: auto =
+    yield 3
+  for x in c():
+    echo x
+
+block:
+  iterator myIter2(): auto {.closure.} =
+    yield 4
+  for a in myIter2():
+    echo a
+
+block t5859:
+  proc flatIterator[T](s: openArray[T]): auto {.noSideEffect.}=
+    result = iterator(): auto =
+      when (T is not seq|array):
+        for item in s:
+          yield item
+      else:
+        yield 123456
+  # issue #5859
+  let it = flatIterator(@[@[1,2], @[3,4]])
diff --git a/tests/iter/titer14.nim b/tests/iter/titer14.nim
new file mode 100644
index 000000000..7e483bbae
--- /dev/null
+++ b/tests/iter/titer14.nim
@@ -0,0 +1,7 @@
+proc f() =
+  var s: seq[int]
+  iterator a(): int =
+    for x in s: yield x
+
+  iterator b(): int =
+    for x in a(): yield x
diff --git a/tests/iter/titer2.nim b/tests/iter/titer2.nim
new file mode 100644
index 000000000..975cc786c
--- /dev/null
+++ b/tests/iter/titer2.nim
@@ -0,0 +1,66 @@
+discard """
+  output: '''true
+3
+4
+5
+0
+1
+2
+3
+4'''
+  cmd: "nim $target --gc:none --hints:on --warnings:off $options $file"
+"""
+
+import hashes
+
+type
+  TSlotEnum = enum seEmpty, seFilled, seDeleted
+  TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B]
+  TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]]
+  TTable*[A, B] {.final.} = object
+    data: TKeyValuePairSeq[A, B]
+    counter: int
+
+iterator mycountup(a, b: int): int =
+  var res = a
+  while res <= b:
+    yield res
+    inc(res)
+
+when true:
+  iterator pairs*[A, B](t: TTable[A, B]): tuple[key: A, val: B] =
+    ## iterates over any (key, value) pair in the table `t`.
+    for h in mycountup(0, high(t.data)):
+      var k = t.data[h].key
+      if t.data[h].slot == seFilled: yield (k, t.data[h].val)
+else:
+  iterator pairs*(t: TTable[int, string]): tuple[key: int, val: string] =
+    ## iterates over any (key, value) pair in the table `t`.
+    for h in mycountup(0, high(t.data)):
+      var k = t.data[h].key
+      if t.data[h].slot == seFilled: yield (k, t.data[h].val)
+
+proc initTable*[A, B](initialSize=64): TTable[A, B] =
+  ## creates a new hash table that is empty. `initialSize` needs to be
+  ## a power of two.
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+block Test1:
+  # generic cache does not instantiate the same iterator[types] twice. This
+  # means we have only one instantiation of 'h'. However, this is the same for
+  # a non-generic iterator!
+
+  var t = initTable[int, string]()
+  for k, v in t.pairs: discard
+  for k, v in t.pairs: discard
+
+echo "true"
+
+# bug #1560
+for i in @[3, 4, 5]:
+  echo($i)
+
+# bug #6992
+for i in 0 ..< 5u32:
+  echo i
diff --git a/tests/iter/titer3.nim b/tests/iter/titer3.nim
new file mode 100644
index 000000000..defd56c98
--- /dev/null
+++ b/tests/iter/titer3.nim
@@ -0,0 +1,54 @@
+discard """
+  output: '''1231
+4
+6
+8
+--------
+4
+6
+8
+'''
+"""
+
+iterator count1_3: int =
+  yield 1
+  yield 2
+  yield 3
+
+for x in count1_3():
+  write(stdout, $x)
+
+# yield inside an iterator, but not in a loop:
+iterator iter1(a: openArray[int]): int =
+  yield a[0]
+
+var x = [[1, 2, 3], [4, 5, 6]]
+for y in iter1(x[0]): write(stdout, $y)
+writeLine(stdout, "")
+
+# ensure closure and inline iterators have the same behaviour regarding
+# parameter passing
+
+iterator clo(a: int): int {.closure.} =
+  yield 0+a
+  yield 1+a
+  yield 2+a
+
+iterator inl(a: int): int {.inline.} =
+  yield 0+a
+  yield 1+a
+  yield 2+a
+
+proc main =
+  var y = 4
+  for i in clo(y):
+    echo i
+    inc y
+
+  echo "--------"
+  y = 4
+  for i in inl(y):
+    echo i
+    inc y
+
+main()
diff --git a/tests/iter/titer4.nim b/tests/iter/titer4.nim
new file mode 100644
index 000000000..912883a63
--- /dev/null
+++ b/tests/iter/titer4.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "iterator within for loop context expected"
+  file: "titer4.nim"
+  line: 7
+"""
+# implicit items/pairs, but not if we have 3 for loop vars:
+for x, y, z in {'a'..'z'}: #ERROR_MSG iterator within for loop context expected
+  nil
diff --git a/tests/iter/titer5.nim b/tests/iter/titer5.nim
new file mode 100644
index 000000000..cb691ffdb
--- /dev/null
+++ b/tests/iter/titer5.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "abcxyz"
+"""
+# Test method call syntax for iterators:
+import strutils
+
+const lines = """abc  xyz"""
+
+for x in lines.split():
+  stdout.write(x)
+
+#OUT abcxyz
+stdout.write "\n"
diff --git a/tests/iter/titer6.nim b/tests/iter/titer6.nim
new file mode 100644
index 000000000..69a10d868
--- /dev/null
+++ b/tests/iter/titer6.nim
@@ -0,0 +1,35 @@
+discard """
+  output: "000"
+"""
+# Test iterator with more than 1 yield statement
+
+import strutils
+
+iterator tokenize2(s: string, seps: set[char] = Whitespace): tuple[
+  token: string, isSep: bool] =
+  var i = 0
+  while i < s.len:
+    var j = i
+    if s[j] in seps:
+      while j < s.len and s[j] in seps: inc(j)
+      if j > i:
+        yield (substr(s, i, j-1), true)
+    else:
+      while j < s.len and s[j] notin seps: inc(j)
+      if j > i:
+        yield (substr(s, i, j-1), false)
+    i = j
+
+for word, isSep in tokenize2("ta da", WhiteSpace):
+  var titer2TestVar = 0
+  stdout.write(titer2TestVar)
+
+proc wordWrap2(s: string, maxLineWidth = 80,
+               splitLongWords = true,
+               seps: set[char] = Whitespace,
+               newLine = "\n"): string  =
+  result = ""
+  for word, isSep in tokenize2(s, seps):
+    var w = 0
+
+stdout.write "\n"
diff --git a/tests/iter/titer7.nim b/tests/iter/titer7.nim
new file mode 100644
index 000000000..9cba3038d
--- /dev/null
+++ b/tests/iter/titer7.nim
@@ -0,0 +1,53 @@
+discard """
+  output: '''--- evens
+2
+4
+6
+8
+--- squares
+1
+4
+9
+16
+25
+36
+49
+64
+81
+'''
+"""
+
+iterator `/`[T](sequence: seq[T],
+                filter: proc(e:T):bool {.closure.}) : T =
+    for element in sequence:
+        if (filter(element)):
+            yield element
+
+iterator `>>`[I,O](sequence: seq[I],
+                   map: proc(e:I):O {.closure.}) : O =
+    for element in sequence:
+        yield map(element)
+
+iterator `/>>`[I,O](sequence: seq[I],
+                    filtermap:tuple[
+                        f:proc(e:I):bool {.closure.},
+                        m:proc(e:I):O {.closure.}]) : O =
+    for element in sequence:
+        if (filtermap.f(element)):
+            yield filtermap.m(element)
+
+proc isEven(x:int): bool =
+    (x and 1) == 0
+
+proc square(x:int): int =
+    x * x
+
+let list = @[1,2,3,4,5,6,7,8,9]
+
+echo ("--- evens")
+for item in list / isEven: echo(item)
+echo ("--- squares")
+for item in list >> square: echo(item)
+#echo ("--- squares of evens, only")
+# next line doesn't compile. Generic types are not inferred
+#for item in list />> (isEven, square) : echo(item)
diff --git a/tests/iter/titer8.nim b/tests/iter/titer8.nim
new file mode 100644
index 000000000..7b6d7b6de
--- /dev/null
+++ b/tests/iter/titer8.nim
@@ -0,0 +1,117 @@
+discard """
+  output: '''tada
+1
+2
+3
+ta da1 1
+1 2
+1 3
+2 1
+2 2
+2 3
+3 1
+3 2
+3 3
+0
+1
+2
+a1: A
+a2: A
+a1: B
+a2: B
+a1: C
+a2: C
+a1: D'''
+"""
+# Test first class iterator:
+
+import strutils
+
+iterator tokenize2(s: string, seps: set[char] = Whitespace): tuple[
+  token: string, isSep: bool] {.closure.} =
+  var i = 0
+  while i < s.len:
+    var j = i
+    if s[j] in seps:
+      while j < s.len and s[j] in seps: inc(j)
+      if j > i:
+        yield (substr(s, i, j-1), true)
+    else:
+      while j < s.len and s[j] notin seps: inc(j)
+      if j > i:
+        yield (substr(s, i, j-1), false)
+    i = j
+
+iterator count3(): int {.closure.} =
+  yield 1
+  yield 2
+  yield 3
+
+for word, isSep in tokenize2("ta da", WhiteSpace):
+  if not isSep:
+    stdout.write(word)
+echo ""
+
+proc inProc() =
+  for c in count3():
+    echo c
+
+  for word, isSep in tokenize2("ta da", WhiteSpace):
+    stdout.write(word)
+
+  for c in count3():
+    for d in count3():
+      echo c, " ", d
+
+
+inProc()
+
+iterator count0(): int {.closure.} =
+  # note: doesn't require anything in its closure (except 'state')
+  yield 0
+
+iterator count2(): int {.closure.} =
+  # note: requires 'x' in its closure
+  var x = 1
+  yield x
+  inc x
+  yield x
+
+# a first class iterator has the type 'proc {.closure.}', but maybe
+# it shouldn't:
+proc invoke(iter: iterator(): int {.closure.}) =
+  for x in iter(): echo x
+
+invoke(count0)
+invoke(count2)
+
+
+# simple tasking:
+type
+  TTask = iterator (ticker: int)
+
+iterator a1(ticker: int) {.closure.} =
+  echo "a1: A"
+  yield
+  echo "a1: B"
+  yield
+  echo "a1: C"
+  yield
+  echo "a1: D"
+
+iterator a2(ticker: int) {.closure.} =
+  echo "a2: A"
+  yield
+  echo "a2: B"
+  yield
+  echo "a2: C"
+
+proc runTasks(t: varargs[TTask]) =
+  var ticker = 0
+  while true:
+    let x = t[ticker mod t.len]
+    if finished(x): break
+    x(ticker)
+    inc ticker
+
+runTasks(a1, a2)
diff --git a/tests/iter/titer9.nim b/tests/iter/titer9.nim
new file mode 100644
index 000000000..99874e70a
--- /dev/null
+++ b/tests/iter/titer9.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''5
+14
+0'''
+"""
+
+iterator count[T](x: T, skip: bool): int {.closure.} =
+  if skip: return x+10
+  else: yield x+1
+
+  if skip: return x+10
+  else: yield x+2
+
+proc takeProc[T](x: iterator (x: T, skip: bool): int) =
+  echo x(4, false)
+  echo x(4, true)
+  echo x(4, false)
+
+takeProc(count[int])
+
diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim
new file mode 100644
index 000000000..c82b3902d
--- /dev/null
+++ b/tests/iter/titer_issues.nim
@@ -0,0 +1,411 @@
+discard """
+  target: "c js"
+  output: '''
+0
+1
+2
+3
+4
+1
+start
+false
+0
+1
+2
+end
+@[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 18, 20, 21, 24, 27, 30, 36, 40, 42]
+1002
+0
+1
+2
+7
+9002
+9004
+9006
+9008
+9010
+9012
+9014
+9016
+9018
+@[1, 2]
+@[1, 2, 3]
+1
+nested finally
+outer finally
+nested finally
+outer finally
+nested finally
+outer finally
+nested finally
+outer finally
+In defer
+trying
+exception caught
+finally block
+'''
+"""
+
+
+import sequtils, strutils
+
+
+block t338:
+  proc moo(): iterator (): int =
+    iterator fooGen: int {.closure.} =
+      while true:
+        yield result
+        result.inc
+    return fooGen
+
+  var foo = moo()
+
+  for i in 0 .. 4:
+    echo foo()
+
+
+
+block t8041:
+  iterator xy[T](a: T, b: set[T]): T =
+    if a in b:
+      yield a
+
+  for a in xy(1'i8, {}):
+    for b in xy(a, {}):
+      echo a
+
+
+
+block t3837_chained:
+  iterator t1(): int {.closure.} =
+    yield 1
+
+  iterator t2(): int {.closure.} =
+    for i in t1():
+      yield i
+
+  for i in t2():
+    echo $i
+
+
+  proc iter1(): (iterator: int) =
+    let coll = [0,1,2]
+    result = iterator: int {.closure.} =
+      for i in coll:
+        yield i
+
+  proc iter2(it: (iterator: int)): (iterator: int)  =
+    result = iterator: int {.closure.} =
+      echo finished(it)
+      for i in it():
+        yield i
+
+  echo "start"
+  let myiter1 = iter1()
+  let myiter2 = iter2(myiter1)
+  for i in myiter2():
+    echo i
+  echo "end"
+
+
+  type Iterable[T] = (iterator: T) | Slice[T]
+    ## Everything that can be iterated over, iterators and slices so far.
+
+  proc toIter[T](s: Slice[T]): iterator: T =
+    ## Iterate over a slice.
+    iterator it: T {.closure.} =
+      for x in s.a..s.b:
+        yield x
+    return it
+
+  proc toIter[T](i: iterator: T): iterator: T =
+    ## Nop
+    i
+
+  iterator map[T,S](i: Iterable[T], f: proc(x: T): S): S =
+    let i = toIter(i)
+    for x in i():
+      yield f(x)
+
+  proc filter[T](i: Iterable[T], f: proc(x: T): bool): iterator: T =
+    let i = toIter(i)
+    iterator it: T {.closure.} =
+      for x in i():
+        if f(x):
+          yield x
+    result = it
+
+  iterator filter[T](i: Iterable[T], f: proc(x: T): bool): T =
+    let i = toIter(i)
+    for x in i():
+      if f(x):
+        yield x
+
+  var it = toSeq(filter(2..10, proc(x: int): bool = x mod 2 == 0))
+  doAssert it == @[2, 4, 6, 8, 10]
+  it = toSeq(map(filter(2..10, proc(x: int): bool = x mod 2 == 0), proc(x: int): int = x * 2))
+  doAssert it == @[4, 8, 12, 16, 20]
+
+
+
+block t3221_complex:
+  iterator permutations[T](ys: openArray[T]): seq[T] =
+    var
+      d = 1
+      c = newSeq[int](ys.len)
+      xs = newSeq[T](ys.len)
+    for i, y in ys: xs[i] = y
+    yield xs
+    block outer:
+      while true:
+        while d > 1:
+          dec d
+          c[d] = 0
+        while c[d] >= d:
+          inc d
+          if d >= ys.len: break outer
+        let i = if (d and 1) == 1: c[d] else: 0
+        swap xs[i], xs[d]
+        yield xs
+        inc c[d]
+
+  proc dig_vectors(): void =
+    var v_nums: seq[int]
+    v_nums = newSeq[int](1)
+    for perm in permutations(toSeq(0 .. 1)):
+      v_nums[0] = 1
+
+  dig_vectors()
+
+
+
+block t3499_keepstate:
+  proc slice[T](iter: iterator(): T {.closure.}, sl: auto): seq[T] =
+    var res: seq[int64] = @[]
+    var i = 0
+    for n in iter():
+      if i > sl.b:
+        break
+      if i >= sl.a:
+        res.add(n)
+      inc i
+    res
+
+  iterator harshad(): int64 {.closure.} =
+    for n in 1 ..< int64.high:
+      var sum = 0
+      for ch in string($n):
+        sum += parseInt("" & ch)
+      if n mod sum == 0:
+        yield n
+
+  echo harshad.slice 0 ..< 20
+
+  for n in harshad():
+    if n > 1000:
+      echo n
+      break
+
+  # bug #3499 last snippet fixed
+  # bug #705  last snippet fixed
+
+
+
+block t1725_nested:
+  iterator factory(): int {.closure.} =
+    iterator bar(): int {.closure.} =
+      yield 0
+      yield 1
+      yield 2
+
+    for x in bar(): yield x
+
+  for x in factory():
+    echo x
+
+
+
+block t2023_objiter:
+  type
+    Obj = object
+      iter: iterator (): int8 {.closure.}
+
+  iterator test(): int8 {.closure.} =
+    yield 7
+
+  proc init():Obj=
+    result.iter = test
+
+  var o = init()
+  echo(o.iter())
+
+
+block:
+  # bug #13739
+  iterator myIter(arg: openArray[int]): int =
+    var tmp = 0
+    let len = arg.len
+    while tmp < len:
+      yield arg[tmp] * 2
+      inc tmp
+
+  proc someProc() =
+    var data = [4501,4502,4503,4504,4505,4506,4507,4508,4509]
+    # StmtListExpr should not get special treatment.
+    for x in myIter((discard;data)):
+      echo x
+
+  someProc()
+
+block:
+  # bug #12576
+  iterator ff(sq: varargs[seq[int]]): int =
+    for x in sq:
+      echo x
+
+  for x in ff(@[1, 2], @[1, 2, 3]):
+    echo x
+
+
+# bug #19575
+
+iterator bb() {.closure.} =
+    while true:
+        try: discard
+        except: break
+        finally: break
+
+var a = bb
+
+iterator cc() {.closure.} =
+    while true:
+        try: discard
+        except:
+          if true:
+            break
+        finally:
+          if true:
+            break
+
+var a2 = cc
+
+# bug #16876
+block:
+  iterator a(num: int): int {.closure.} =
+      if num == 1:
+          yield num
+      else:
+          for i in a(num - 1):
+              yield i
+
+  for i in a(5):
+    echo i
+
+block:
+  # bug #19911 (return in nested try)
+
+  # try yield -> try
+  iterator p1: int {.closure.} =
+    try:
+      yield 0
+      try:
+        return
+      finally:
+        echo "nested finally"
+      echo "shouldn't run"
+    finally:
+      echo "outer finally"
+    echo "shouldn't run"
+
+  for _ in p1():
+    discard
+
+  # try -> try yield
+  iterator p2: int {.closure.} =
+    try:
+      try:
+        yield 0
+        return
+      finally:
+        echo "nested finally"
+      echo "shouldn't run"
+    finally:
+      echo "outer finally"
+    echo "shouldn't run"
+
+  for _ in p2():
+    discard
+
+  # try yield -> try yield
+  iterator p3: int {.closure.} =
+    try:
+      yield 0
+      try:
+        yield 0
+        return
+      finally:
+        echo "nested finally"
+      echo "shouldn't run"
+    finally:
+      echo "outer finally"
+    echo "shouldn't run"
+
+  for _ in p3():
+    discard
+
+  # try -> try
+  iterator p4: int {.closure.} =
+    try:
+      try:
+        return
+      finally:
+        echo "nested finally"
+      echo "shouldn't run"
+    finally:
+      echo "outer finally"
+    echo "shouldn't run"
+
+  for _ in p4():
+    discard
+
+# bug #18824
+iterator poc_iterator: int {.closure.}  =
+  block bug18824:
+    try:
+      break bug18824
+    finally:
+      echo "In defer"
+
+for _ in poc_iterator():
+  discard
+
+# bug #20624
+iterator tryFinally() {.closure.} =
+  block route:
+    try:
+      echo "trying"
+      raise
+    except:
+      echo "exception caught"
+      break route
+    finally:
+      echo "finally block"
+
+var x = tryFinally
+x()
+
+block: # bug #24033
+  type Query = ref object
+
+  iterator pairs(query: Query): (int, (string, float32)) =
+    var output: (int, (string, float32)) = (0, ("foo", 3.14))
+    for id in @[0, 1, 2]:
+      output[0] = id
+      yield output
+
+  var collections: seq[(int, string, string)]
+
+  for id, (str, num) in Query():
+    collections.add (id, str, $num)
+
+  doAssert collections[1] == (1, "foo", "3.14")
diff --git a/tests/iter/titer_no_tuple_unpack.nim b/tests/iter/titer_no_tuple_unpack.nim
new file mode 100644
index 000000000..d8df10189
--- /dev/null
+++ b/tests/iter/titer_no_tuple_unpack.nim
@@ -0,0 +1,27 @@
+discard """
+output: '''
+3 4
+4 5
+5 6
+6 7
+7 8
+(x: 3, y: 4)
+(x: 4, y: 5)
+(x: 5, y: 6)
+(x: 6, y: 7)
+(x: 7, y: 8)
+'''
+"""
+
+
+iterator xrange(fromm, to: int, step = 1): tuple[x, y: int] =
+  var a = fromm
+  while a <= to:
+    yield (a, a+1)
+    inc(a, step)
+
+for a, b in xrange(3, 7):
+  echo a, " ", b
+
+for tup in xrange(3, 7):
+  echo tup
diff --git a/tests/iter/titerable.nim b/tests/iter/titerable.nim
new file mode 100644
index 000000000..f503836d3
--- /dev/null
+++ b/tests/iter/titerable.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''2
+4
+6
+4
+8
+12
+'''
+  disabled: "true"
+"""
+
+# Will eventually fix it...
+
+iterator map[T, U](s: iterator:T{.inline.}, f: proc(x: T): U): U =
+  for e in s: yield f(e)
+
+template toSeq(s: untyped): untyped =
+  var res = newSeq[type(s)](0)
+  for e in s: res.add(e)
+  res
+
+var s1 = @[1, 2, 3]
+for x in map(s1.items, proc (a:int): int = a*2):
+  echo x
+
+var s2 = toSeq(map(s1.items, proc (a:int): int = a*4))
+for x in s2:
+  echo x
+
diff --git a/tests/iter/titerautoerr1.nim b/tests/iter/titerautoerr1.nim
new file mode 100644
index 000000000..c7e5642c8
--- /dev/null
+++ b/tests/iter/titerautoerr1.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "type mismatch: got <int literal(1)> but expected 'string'"
+  line: 8
+"""
+
+iterator a(): auto {.closure.} =
+  if true: return "str"
+  yield 1
diff --git a/tests/iter/titerautoerr2.nim b/tests/iter/titerautoerr2.nim
new file mode 100644
index 000000000..eb48a36f9
--- /dev/null
+++ b/tests/iter/titerautoerr2.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "type mismatch: got <string> but expected 'int literal(1)'"
+  line: 8
+"""
+
+iterator b(): auto {.closure.} =
+  yield 1
+  if true: return "str"
diff --git a/tests/iter/titerautoerr3.nim b/tests/iter/titerautoerr3.nim
new file mode 100644
index 000000000..e47b65540
--- /dev/null
+++ b/tests/iter/titerautoerr3.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "cannot infer the return type of 'bar'"
+  line: 6
+"""
+
+iterator bar(): auto =
+  discard
+for t in bar():
+  discard
diff --git a/tests/iter/titerconcat.nim b/tests/iter/titerconcat.nim
new file mode 100644
index 000000000..477ac5e26
--- /dev/null
+++ b/tests/iter/titerconcat.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''1
+2
+3
+4
+20
+21
+22
+23'''
+"""
+
+proc toIter*[T](s: Slice[T]): iterator: T =
+  iterator it: T {.closure.} =
+    for x in s.a..s.b:
+      yield x
+  return it
+
+iterator concat*[T](its: varargs[T, toIter]): auto =
+  for i in its:
+    for x in i():
+      yield x
+
+for i in concat(1..4, 20..23):
+  echo i
diff --git a/tests/iter/titerovl.nim b/tests/iter/titerovl.nim
new file mode 100644
index 000000000..be665b2b7
--- /dev/null
+++ b/tests/iter/titerovl.nim
@@ -0,0 +1,21 @@
+discard """
+  output: '''9
+1
+2
+3
+'''
+"""
+
+# Test the new overloading rules for iterators:
+
+# test that iterator 'p' is preferred:
+proc p(): seq[int] = @[1, 2, 3]
+iterator p(): int = yield 9
+
+for x in p(): echo x
+
+# test that 'q' works in this position:
+proc q(): seq[int] = @[1, 2, 3]
+
+for x in q(): echo x
+
diff --git a/tests/iter/titerslice.nim b/tests/iter/titerslice.nim
new file mode 100644
index 000000000..e5d2e14a3
--- /dev/null
+++ b/tests/iter/titerslice.nim
@@ -0,0 +1,9 @@
+discard """
+  output: '''2
+3
+4'''
+"""
+
+var t1 = @["1", "2", "3", "4"]
+for t in t1[1..3]:
+  echo t
diff --git a/tests/iter/titertypedesc.nim b/tests/iter/titertypedesc.nim
new file mode 100644
index 000000000..a69f703c6
--- /dev/null
+++ b/tests/iter/titertypedesc.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''0
+(id: 0)
+@[]
+[0, 0, 0]'''
+"""
+
+iterator foo*(T: typedesc): T =
+  var x: T
+  yield x
+
+for a in foo(int): echo a
+for b in foo(tuple[id: int]): echo b
+for c in foo(seq[int]): echo c
+
+type Generic[T] = T
+for d in foo(Generic[array[0..2, int]]): echo d
diff --git a/tests/iter/titervaropenarray.nim b/tests/iter/titervaropenarray.nim
new file mode 100644
index 000000000..b2fe71ceb
--- /dev/null
+++ b/tests/iter/titervaropenarray.nim
@@ -0,0 +1,15 @@
+discard """
+  output: "123"
+  targets: "c cpp"
+"""
+# Try to break the transformation pass:
+iterator iterAndZero(a: var openArray[int]): int =
+  for i in 0..len(a)-1:
+    yield a[i]
+    a[i] = 0
+
+var x = [[1, 2, 3], [4, 5, 6]]
+for y in iterAndZero(x[0]): write(stdout, $y)
+#OUT 123
+
+write stdout, "\n"
diff --git a/tests/iter/tmoditer.nim b/tests/iter/tmoditer.nim
new file mode 100644
index 000000000..99e5b642d
--- /dev/null
+++ b/tests/iter/tmoditer.nim
@@ -0,0 +1,88 @@
+discard """
+  output: "XXXXX01234"
+"""
+
+iterator modPairs(a: var array[0..4,string]): tuple[key: int, val: var string] =
+  for i in 0..a.high:
+    yield (key: i, val: a[i])
+
+iterator modItems*[T](a: var array[0..4,T]): var T =
+  for i in 0..a.high:
+    yield a[i]
+
+var
+  arr = ["a", "b", "c", "d", "e"]
+
+for a in modItems(arr):
+  a = "X"
+
+for a in items(arr):
+  stdout.write(a)
+
+for i, a in modPairs(arr):
+  a = $i
+
+for a in items(arr):
+  stdout.write(a)
+
+echo ""
+
+#--------------------------------------------------------------------
+# Lent iterators
+#--------------------------------------------------------------------
+type
+  NonCopyable = object
+    x: int
+
+
+proc `=destroy`(o: var NonCopyable) =
+  discard
+
+proc `=copy`(dst: var NonCopyable, src: NonCopyable) {.error.}
+
+proc `=sink`(dst: var NonCopyable, src: NonCopyable) =
+  dst.x = src.x
+
+iterator lentItems[T](a: openArray[T]): lent T =
+  for i in 0..a.high:
+    yield a[i]
+
+iterator lentPairs[T](a: array[0..1, T]): tuple[key: int, val: lent T] =
+  for i in 0..a.high:
+    yield (key: i, val: a[i])
+
+
+let arr1 = [1, 2, 3]
+let arr2 = @["a", "b", "c"]
+let arr3 = [NonCopyable(x: 1), NonCopyable(x: 2)]
+let arr4 = @[(1, "a"), (2, "b"), (3, "c")]
+
+var accum: string
+for x in lentItems(arr1):
+  accum &= $x
+doAssert(accum == "123")
+
+accum = ""
+for x in lentItems(arr2):
+  accum &= $x
+doAssert(accum == "abc")
+
+accum = ""
+for val in lentItems(arr3):
+  accum &= $val.x
+doAssert(accum == "12")
+
+accum = ""
+for i, val in lentPairs(arr3):
+  accum &= $i & "-" & $val.x & " "
+doAssert(accum == "0-1 1-2 ")
+
+accum = ""
+for i, val in lentItems(arr4):
+  accum &= $i & "-" & $val & " "
+doAssert(accum == "1-a 2-b 3-c ")
+
+accum = ""
+for (i, val) in lentItems(arr4):
+  accum &= $i & "-" & $val & " "
+doAssert(accum == "1-a 2-b 3-c ")
diff --git a/tests/iter/tpermutations.nim b/tests/iter/tpermutations.nim
new file mode 100644
index 000000000..30a66460f
--- /dev/null
+++ b/tests/iter/tpermutations.nim
@@ -0,0 +1,69 @@
+discard """
+output: '''
+@[@[1.0, 2.0], @[3.0, 4.0]]
+perm: 10.0 det: -2.0
+@[@[1.0, 2.0, 3.0, 4.0], @[4.0, 5.0, 6.0, 7.0], @[7.0, 8.0, 9.0, 10.0], @[10.0, 11.0, 12.0, 13.0]]
+perm: 29556.0 det: 0.0
+@[@[0.0, 1.0, 2.0, 3.0, 4.0], @[5.0, 6.0, 7.0, 8.0, 9.0], @[10.0, 11.0, 12.0, 13.0, 14.0], @[15.0, 16.0, 17.0, 18.0, 19.0], @[20.0, 21.0, 22.0, 23.0, 24.0]]
+perm: 6778800.0 det: 0.0
+'''
+"""
+
+
+import sequtils, sugar
+
+iterator permutations*[T](ys: openArray[T]): tuple[perm: seq[T], sign: int] =
+  var
+    d = 1
+    c = newSeq[int](ys.len)
+    xs = newSeq[T](ys.len)
+    sign = 1
+
+  for i, y in ys: xs[i] = y
+  yield (xs, sign)
+
+  block outter:
+    while true:
+      while d > 1:
+        dec d
+        c[d] = 0
+      while c[d] >= d:
+        inc d
+        if d >= ys.len: break outter
+
+      let i = if (d and 1) == 1: c[d] else: 0
+      swap xs[i], xs[d]
+      sign *= -1
+      yield (xs, sign)
+      inc c[d]
+
+proc det(a: seq[seq[float]]): float =
+  let n = toSeq 0..a.high
+  for sigma, sign in n.permutations:
+    result += sign.float * n.map((i: int) => a[i][sigma[i]]).foldl(a * b)
+
+proc perm(a: seq[seq[float]]): float =
+  let n = toSeq 0..a.high
+  for sigma, sign in n.permutations:
+    result += n.map((i: int) => a[i][sigma[i]]).foldl(a * b)
+
+for a in [
+    @[ @[1.0, 2.0]
+     , @[3.0, 4.0]
+    ],
+    @[ @[ 1.0,  2,  3,  4]
+     , @[ 4.0,  5,  6,  7]
+     , @[ 7.0,  8,  9, 10]
+     , @[10.0, 11, 12, 13]
+    ],
+    @[ @[ 0.0,  1,  2,  3,  4]
+     , @[ 5.0,  6,  7,  8,  9]
+     , @[10.0, 11, 12, 13, 14]
+     , @[15.0, 16, 17, 18, 19]
+     , @[20.0, 21, 22, 23, 24]
+    ] ]:
+  echo a
+  echo "perm: ", a.perm, " det: ", a.det
+
+# bug #3499 last snippet fixed
+# bug 705  last snippet fixed
diff --git a/tests/iter/treciter.nim b/tests/iter/treciter.nim
new file mode 100644
index 000000000..11fb58224
--- /dev/null
+++ b/tests/iter/treciter.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "recursion is not supported in iterators: 'myrec'"
+  file: "treciter.nim"
+  line: 9
+"""
+# Test that an error message occurs for a recursive iterator
+
+iterator myrec(n: int): int =
+  for x in myrec(n-1): #ERROR_MSG recursive dependency: 'myrec'
+    yield x
+
+for x in myrec(10): echo x
diff --git a/tests/iter/tscheduler.nim b/tests/iter/tscheduler.nim
new file mode 100644
index 000000000..f4b04f311
--- /dev/null
+++ b/tests/iter/tscheduler.nim
@@ -0,0 +1,77 @@
+discard """
+  output: '''a1 5
+a2 10
+a1 3
+a1 1
+a2 8
+a2 6
+a2 4
+a2 2'''
+  disabled: "true"
+"""
+
+import os, strutils, times, algorithm
+
+
+type TaskFn = iterator (): float
+
+type Task = object
+    coro: TaskFn
+    next_run: float
+
+
+type Scheduler = object
+    tasks: seq[Task]
+
+
+proc newScheduler(): Scheduler =
+    var s = Scheduler()
+    s.tasks = @[]
+    return s
+
+
+proc start(this: var Scheduler, task: TaskFn) =
+    var t = Task()
+    t.coro = task
+    t.next_run = 0.0
+    this.tasks.add(t)
+
+
+proc run(this: var Scheduler) =
+    while this.tasks.len > 0:
+        var dead: seq[int] = @[]
+        for i in this.tasks.low..this.tasks.high:
+            var task = this.tasks[i]
+            if finished(task.coro):
+                dead.add(i)
+                continue
+            if task.next_run <= epochTime():
+                task.next_run = task.coro() + epochTime()
+            this.tasks[i] = task
+        for i in dead:
+            this.tasks.delete(i)
+        if this.tasks.len > 0:
+            sort(this.tasks, proc (t1: Task, t2: Task): int = cmp(t1.next_run, t2.next_run))
+            sleep(int((this.tasks[0].next_run - epochTime()) * 1000))
+
+
+iterator a1(): float {.closure.} =
+    var k = 5
+    while k > 0:
+        echo "a1 $1" % [$k]
+        dec k, 2
+        yield 0.5
+
+
+iterator a2(): float {.closure.} =
+    var k = 10
+    while k > 0:
+        echo "a2 $1" % [$k]
+        dec k, 2
+        yield 1.5
+
+
+var sched = newScheduler()
+sched.start(a1)
+sched.start(a2)
+sched.run()
diff --git a/tests/iter/tshallowcopy_closures.nim b/tests/iter/tshallowcopy_closures.nim
new file mode 100644
index 000000000..06b04a788
--- /dev/null
+++ b/tests/iter/tshallowcopy_closures.nim
@@ -0,0 +1,36 @@
+discard """
+  matrix: "--mm:refc"
+  ccodecheck: "!@('{' \\s* 'NI HEX3Astate;' \\s* '}')"
+  output: '''
+a1 10
+a1 9
+'''
+"""
+
+# bug #1803
+type TaskFn = iterator (): float
+
+iterator a1(): float {.closure.} =
+    var k = 10
+    while k > 0:
+        echo "a1 ", k
+        dec k
+        yield 1.0
+
+
+iterator a2(): float {.closure.} =
+    var k = 15
+    while k > 0:
+        echo "a2 ", k
+        dec k
+        yield 2.0
+
+var
+  x = a1
+  y = a2
+  z: TaskFn
+
+discard x()
+shallowCopy(z, x)
+shallowCopy(z, y)
+discard x()
diff --git a/tests/iter/twrap_walkdir.nim b/tests/iter/twrap_walkdir.nim
new file mode 100644
index 000000000..1d52e9791
--- /dev/null
+++ b/tests/iter/twrap_walkdir.nim
@@ -0,0 +1,17 @@
+discard """
+action: compile
+"""
+
+import os
+
+# bug #3636
+
+proc fooIt(foo: string): iterator(): (string) =
+  iterator temp(): (string) =
+    for f in walkDirRec(foo): # No problem with walkFiles
+      yield f
+  return temp
+
+let it = fooIt(".")
+for x in it():
+  echo x
diff --git a/tests/iter/twrongiter.nim b/tests/iter/twrongiter.nim
new file mode 100644
index 000000000..577b8c4f1
--- /dev/null
+++ b/tests/iter/twrongiter.nim
@@ -0,0 +1,13 @@
+discard """
+errormsg: "type mismatch"
+line: 12
+"""
+
+proc first(it: iterator(): int): seq[int] =
+  return @[]
+
+iterator primes(): int =
+  yield 1
+
+for i in first(primes):
+  break
diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim
new file mode 100644
index 000000000..e51ab7f0d
--- /dev/null
+++ b/tests/iter/tyieldintry.nim
@@ -0,0 +1,529 @@
+discard """
+  matrix: "; --experimental:strictdefs; -d:nimOptIters"
+  targets: "c cpp"
+"""
+
+var closureIterResult = newSeq[int]()
+
+proc checkpoint(arg: int) =
+  closureIterResult.add(arg)
+
+type
+  TestError = object of CatchableError
+  AnotherError = object of CatchableError
+
+proc testClosureIterAux(it: iterator(): int, exceptionExpected: bool, expectedResults: varargs[int]) =
+  closureIterResult.setLen(0)
+
+  var exceptionCaught = false
+
+  try:
+    for i in it():
+      closureIterResult.add(i)
+  except TestError:
+    exceptionCaught = true
+
+  if closureIterResult != @expectedResults or exceptionCaught != exceptionExpected:
+    if closureIterResult != @expectedResults:
+      echo "Expected: ", @expectedResults
+      echo "Actual: ", closureIterResult
+    if exceptionCaught != exceptionExpected:
+      echo "Expected exception: ", exceptionExpected
+      echo "Got exception: ", exceptionCaught
+    doAssert(false)
+
+proc test(it: iterator(): int, expectedResults: varargs[int]) =
+  testClosureIterAux(it, false, expectedResults)
+
+proc testExc(it: iterator(): int, expectedResults: varargs[int]) =
+  testClosureIterAux(it, true, expectedResults)
+
+proc raiseTestError() =
+  raise newException(TestError, "Test exception!")
+
+block:
+  iterator it(): int {.closure.} =
+    var i = 5
+    while i != 0:
+      yield i
+      if i == 3:
+        yield 123
+      dec i
+
+  test(it, 5, 4, 3, 123, 2, 1)
+
+block:
+  iterator it(): int {.closure.} =
+    yield 0
+    try:
+      checkpoint(1)
+      raiseTestError()
+    except TestError:
+      checkpoint(2)
+      yield 3
+      checkpoint(4)
+    finally:
+      checkpoint(5)
+
+    checkpoint(6)
+
+  test(it, 0, 1, 2, 3, 4, 5, 6)
+
+block:
+  iterator it(): int {.closure.} =
+    yield 0
+    try:
+      yield 1
+      checkpoint(2)
+    finally:
+      checkpoint(3)
+      yield 4
+      checkpoint(5)
+      yield 6
+
+  test(it, 0, 1, 2, 3, 4, 5, 6)
+
+block:
+  iterator it(): int {.closure.} =
+    yield 0
+    try:
+      yield 1
+      raiseTestError()
+      yield 2
+    finally:
+      checkpoint(3)
+      yield 4
+      checkpoint(5)
+      yield 6
+
+  testExc(it, 0, 1, 3, 4, 5, 6)
+
+block:
+  iterator it(): int {.closure.} =
+    try:
+      try:
+        raiseTestError()
+      except AnotherError:
+        yield 123
+      finally:
+        checkpoint(3)
+    finally:
+      checkpoint(4)
+
+  testExc(it, 3, 4)
+
+block:
+  iterator it(): int {.closure.} =
+    try:
+      yield 1
+      raiseTestError()
+    except AnotherError:
+      checkpoint(123)
+    finally:
+      checkpoint(2)
+    checkpoint(3)
+
+  testExc(it, 1, 2)
+
+block:
+  iterator it(): int {.closure.} =
+    try:
+      yield 0
+      try:
+        yield 1
+        try:
+          yield 2
+          raiseTestError()
+        except AnotherError:
+          yield 123
+        finally:
+          yield 3
+      except AnotherError:
+        yield 124
+      finally:
+        yield 4
+      checkpoint(1234)
+    except:
+      yield 5
+      checkpoint(6)
+    finally:
+      checkpoint(7)
+      yield 8
+    checkpoint(9)
+
+  test(it, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
+
+block:
+  iterator it(): int {.closure.} =
+    try:
+      yield 0
+      return 2
+    finally:
+      checkpoint(1)
+    checkpoint(123)
+
+  test(it, 0, 1)
+
+block:
+  iterator it(): int {.closure.} =
+    try:
+      try:
+        yield 0
+        raiseTestError()
+      finally:
+        checkpoint(1)
+    except TestError:
+      yield 2
+      return
+    finally:
+      yield 3
+
+    checkpoint(123)
+
+  test(it, 0, 1, 2, 3)
+
+block:
+  iterator it(): int {.closure.} =
+    try:
+      try:
+        yield 0
+        raiseTestError()
+      finally:
+        return # Return in finally should stop exception propagation
+    except AnotherError:
+      yield 2
+      return
+    finally:
+      yield 3
+    checkpoint(123)
+
+  test(it, 0, 3)
+
+block: # Yield in yield
+  iterator it(): int {.closure.} =
+    template foo(): int =
+      yield 1
+      2
+
+    for i in 0 .. 2:
+      checkpoint(0)
+      yield foo()
+
+  test(it, 0, 1, 2, 0, 1, 2, 0, 1, 2)
+
+block:
+  iterator it(): int {.closure.} =
+    let i = if true:
+        yield 0
+        1
+      else:
+        2
+    yield i
+
+  test(it, 0, 1)
+
+block:
+  iterator it(): int {.closure.} =
+    var foo = 123
+    let i = try:
+        yield 0
+        raiseTestError()
+        1
+      except TestError as e:
+        assert(e.msg == "Test exception!")
+        case foo
+        of 1:
+          yield 123
+          2
+        of 123:
+          yield 5
+          6
+        else:
+          7
+    yield i
+
+  test(it, 0, 5, 6)
+
+block:
+  iterator it(): int {.closure.} =
+    proc voidFoo(i1, i2, i3: int) =
+      checkpoint(i1)
+      checkpoint(i2)
+      checkpoint(i3)
+
+    proc foo(i1, i2, i3: int): int =
+      voidFoo(i1, i2, i3)
+      i3
+
+    proc bar(i1: int): int =
+      checkpoint(i1)
+
+    template tryexcept: int =
+      try:
+        yield 1
+        raiseTestError()
+        123
+      except TestError:
+        yield 2
+        checkpoint(3)
+        4
+
+    let e1 = true
+
+    template ifelse1: int =
+      if e1:
+        yield 10
+        11
+      else:
+        12
+
+    template ifelse2: int =
+      if ifelse1() == 12:
+        yield 20
+        21
+      else:
+        yield 22
+        23
+
+    let i = foo(bar(0), tryexcept, ifelse2)
+    discard foo(bar(0), tryexcept, ifelse2)
+    voidFoo(bar(0), tryexcept, ifelse2)
+    yield i
+
+  test(it,
+
+    # let i = foo(bar(0), tryexcept, ifelse2)
+    0, # bar(0)
+    1, 2, 3, # tryexcept
+    10, # ifelse1
+    22, # ifelse22
+    0, 4, 23, # foo
+
+    # discard foo(bar(0), tryexcept, ifelse2)
+    0, # bar(0)
+    1, 2, 3, # tryexcept
+    10, # ifelse1
+    22, # ifelse22
+    0, 4, 23, # foo
+
+    # voidFoo(bar(0), tryexcept, ifelse2)
+    0, # bar(0)
+    1, 2, 3, # tryexcept
+    10, # ifelse1
+    22, # ifelse22
+    0, 4, 23, # foo
+
+    23 # i
+  )
+
+block:
+  iterator it(): int {.closure.} =
+    checkpoint(0)
+    for i in 0 .. 1:
+      try:
+        yield 1
+        raiseTestError()
+      except TestError as e:
+        doAssert(e.msg == "Test exception!")
+        yield 2
+      except AnotherError:
+        yield 123
+      except:
+        yield 1234
+      finally:
+        yield 3
+        checkpoint(4)
+        yield 5
+
+  test(it, 0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
+
+block:
+  iterator it(): int {.closure.} =
+    var i = 5
+    template foo(): bool =
+      yield i
+      true
+
+    while foo():
+      dec i
+      if i == 0:
+        break
+
+  test(it, 5, 4, 3, 2, 1)
+
+block: # Short cirquits
+  iterator it(): int {.closure.} =
+    template trueYield: bool =
+      yield 1
+      true
+
+    template falseYield: bool =
+      yield 0
+      false
+
+    if trueYield or falseYield:
+      discard falseYield and trueYield
+
+    if falseYield and trueYield:
+      checkpoint(123)
+
+  test(it, 1, 0, 0)
+
+block: #7969
+  type
+    SomeObj = object
+      id: int
+
+  iterator it(): int {.closure.} =
+    template yieldAndSomeObj: SomeObj =
+      var s: SomeObj
+      s.id = 2
+      yield 1
+      s
+
+    checkpoint(yieldAndSomeObj().id)
+
+    var i = 5
+    case i
+    of 0:
+      checkpoint(123)
+    of 1, 2, 5:
+      checkpoint(3)
+    else:
+      checkpoint(123)
+
+  test(it, 1, 2, 3)
+
+block: # yield in blockexpr
+  iterator it(): int {.closure.} =
+    yield(block:
+      checkpoint(1)
+      yield 2
+      3
+    )
+
+  test(it, 1, 2, 3)
+
+block: #8851
+  type
+    Foo = ref object of RootObj
+  template someFoo(): Foo =
+    var f: Foo
+    yield 1
+    f
+  iterator it(): int {.closure.} =
+    var o: RootRef
+    o = someFoo()
+
+  test(it, 1)
+
+block: # 8243
+  iterator it(): int {.closure.} =
+    template yieldAndSeq: seq[int] =
+      yield 1
+      @[123, 5, 123]
+
+    checkpoint(yieldAndSeq[1])
+
+  test(it, 1, 5)
+
+block:
+  iterator it(): int {.closure.} =
+    template yieldAndSeq: seq[int] =
+      yield 1
+      @[123, 5, 123]
+
+    template yieldAndNum: int =
+      yield 2
+      1
+
+    checkpoint(yieldAndSeq[yieldAndNum])
+
+  test(it, 1, 2, 5)
+
+block: #9694 - yield in ObjConstr
+  type Foo = object
+    a, b: int
+
+  template yieldAndNum: int =
+    yield 1
+    2
+
+  iterator it(): int {.closure.} =
+    let a = Foo(a: 5, b: yieldAndNum())
+    checkpoint(a.b)
+
+  test(it, 1, 2)
+
+block: #9716
+  iterator it(): int {.closure.} =
+    var a = 0
+    for i in 1 .. 3:
+      var a: int # Make sure the "local" var is reset
+      var b: string # ditto
+      yield 1
+      a += 5
+      b &= "hello"
+      doAssert(a == 5)
+      doAssert(b == "hello")
+  test(it, 1, 1, 1)
+
+block: # nnkChckRange
+  type Foo = distinct uint64
+  template yieldDistinct: Foo =
+    yield 2
+    Foo(0)
+
+  iterator it(): int {.closure.} =
+    yield 1
+    var a: int
+    a = int(yieldDistinct())
+    yield 3
+
+  test(it, 1, 2, 3)
+
+block: #17849 - yield in case subject
+  template yieldInCase: int =
+    yield 2
+    3
+
+  iterator it(): int {.closure.} =
+    yield 1
+    case yieldInCase()
+    of 1: checkpoint(11)
+    of 3: checkpoint(13)
+    else: checkpoint(14)
+    yield 5
+
+  test(it, 1, 2, 13, 5)
+
+block: # void iterator
+  iterator it() {.closure.} =
+    try:
+      yield
+    except:
+      discard
+  var a = it
+
+if defined(nimOptIters): # Locals present in only 1 state should be on the stack
+  proc checkOnStack(a: pointer, shouldBeOnStack: bool) =
+    # Quick and dirty way to check if a points to stack
+    var dummy = 0
+    let dummyAddr = addr dummy
+    let distance = abs(cast[int](dummyAddr) - cast[int](a))
+    const requiredDistance = 300
+    if shouldBeOnStack:
+      doAssert(distance <= requiredDistance, "a is not on stack, but should")
+    else:
+      doAssert(distance > requiredDistance, "a is on stack, but should not")
+
+  iterator it(): int {.closure.} =
+    var a = 1
+    var b = 2
+    var c {.liftLocals.} = 3
+    checkOnStack(addr a, true)
+    checkOnStack(addr b, false)
+    checkOnStack(addr c, false)
+    yield a
+    yield b
+  test(it, 1, 2)