summary refs log tree commit diff stats
path: root/tests/closure
diff options
context:
space:
mode:
Diffstat (limited to 'tests/closure')
-rw-r--r--tests/closure/t11042.nim55
-rw-r--r--tests/closure/t15594.nim10
-rw-r--r--tests/closure/t1641.nim20
-rw-r--r--tests/closure/t19095.nim35
-rw-r--r--tests/closure/t20152.nim20
-rw-r--r--tests/closure/t8550.nim13
-rw-r--r--tests/closure/t9334.nim19
-rw-r--r--tests/closure/tboehmdeepcopy.nim18
-rw-r--r--tests/closure/tcapture.nim34
-rw-r--r--tests/closure/tclosure.nim504
-rw-r--r--tests/closure/tclosure_issues.nim82
-rw-r--r--tests/closure/texplicit_dummy_closure.nim25
-rw-r--r--tests/closure/tinfer_closure_for_nestedproc.nim42
-rw-r--r--tests/closure/tinvalidclosure.nim12
-rw-r--r--tests/closure/tinvalidclosure2.nim14
-rw-r--r--tests/closure/tinvalidclosure3.nim12
-rw-r--r--tests/closure/tinvalidclosure4.nim9
-rw-r--r--tests/closure/tinvalidclosure5.nim10
-rw-r--r--tests/closure/tmacrobust1512.nim123
-rw-r--r--tests/closure/tnested.nim215
-rw-r--r--tests/closure/tstmtlist.nim9
-rw-r--r--tests/closure/ttimeinfo.nim22
-rw-r--r--tests/closure/uclosures.nim23
23 files changed, 1326 insertions, 0 deletions
diff --git a/tests/closure/t11042.nim b/tests/closure/t11042.nim
new file mode 100644
index 000000000..6a3928316
--- /dev/null
+++ b/tests/closure/t11042.nim
@@ -0,0 +1,55 @@
+discard """
+  output:'''
+foo: 1
+foo: 2
+bar: 1
+bar: 2
+foo: 1
+foo: 2
+bar: 1
+bar: 2
+bar: 3
+bar: 4
+bar: 5
+bar: 6
+bar: 7
+bar: 8
+bar: 9
+'''
+"""
+
+# bug #11042
+block:
+  iterator foo: int =
+    for x in 1..2:
+      echo "foo: ", x
+      for y in 1..2:
+        discard
+
+  for x in foo(): discard
+
+  let bar = iterator: int =
+    for x in 1..2:
+      echo "bar: ", x
+      for y in 1..2:
+        discard
+
+  for x in bar(): discard
+
+
+block:
+  iterator foo: int =
+    for x in 1..2:
+      echo "foo: ", x
+      for y in 1..2:
+        discard
+
+  for x in foo(): discard
+
+  let bar = iterator: int =
+    for x in 1..9:
+      echo "bar: ", x
+      for y in 1..2:
+        discard
+
+  for x in bar(): discard
\ No newline at end of file
diff --git a/tests/closure/t15594.nim b/tests/closure/t15594.nim
new file mode 100644
index 000000000..aacd9ed84
--- /dev/null
+++ b/tests/closure/t15594.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "The variable name cannot be `result`!"
+"""
+
+import sugar
+
+proc begin(): int =
+  capture result:
+    echo 1+1
+  result
diff --git a/tests/closure/t1641.nim b/tests/closure/t1641.nim
new file mode 100644
index 000000000..a3e4da367
--- /dev/null
+++ b/tests/closure/t1641.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''foo 0
+bar 0
+baz'''
+"""
+
+# bug #1641
+proc baz() =
+  echo "baz"
+
+proc bar(x: int, p: proc()) =
+  echo "bar ", x
+  p()
+
+proc foo(x: int, p: proc(x: int)) =
+  echo "foo ", x
+  p(x)
+
+let x = 0
+x.foo do(x: int): x.bar do(): baz()
diff --git a/tests/closure/t19095.nim b/tests/closure/t19095.nim
new file mode 100644
index 000000000..880456e02
--- /dev/null
+++ b/tests/closure/t19095.nim
@@ -0,0 +1,35 @@
+discard """
+  action: compile
+"""
+
+block:
+  func inCheck() =
+    discard
+
+  iterator iter(): int =
+    yield 0
+    yield 0
+
+  func search() =
+    let inCheck = 0
+
+    for i in iter():
+
+      proc hello() =
+        inCheck()
+
+  search()
+block:
+  iterator iter(): int =
+    yield 0
+    yield 0
+
+  func search() =
+    let lmrMoveCounter = 0
+
+    for i in iter():
+
+      proc hello() =
+        discard lmrMoveCounter
+
+  search()
diff --git a/tests/closure/t20152.nim b/tests/closure/t20152.nim
new file mode 100644
index 000000000..484ea0741
--- /dev/null
+++ b/tests/closure/t20152.nim
@@ -0,0 +1,20 @@
+discard """

+  action: compile

+"""

+

+proc foo() =

+  iterator it():int {.closure.} =

+    yield 1

+  proc useIter() {.nimcall.} =

+    var iii = it # <-- illegal capture

+    doAssert iii() == 1

+  useIter()

+foo()

+

+proc foo2() =

+  proc bar() = # Local function, but not a closure, because no captures

+    echo "hi"

+  proc baz() {.nimcall.} = # Calls local function

+    bar()

+  baz()

+foo2()

diff --git a/tests/closure/t8550.nim b/tests/closure/t8550.nim
new file mode 100644
index 000000000..a07f45cdc
--- /dev/null
+++ b/tests/closure/t8550.nim
@@ -0,0 +1,13 @@
+discard """
+  targets: "c js"
+  output: "@[\"42\"]"
+"""
+
+proc chk_fail(): seq[string] =
+  iterator x(): int {.closure.} = yield 42
+  proc f(cl: iterator(): int {.closure.}): seq[string] =
+    result = @[]
+    for i in cl(): result.add($i)
+  result = f(x)
+
+echo(chk_fail())
diff --git a/tests/closure/t9334.nim b/tests/closure/t9334.nim
new file mode 100644
index 000000000..36a9a7d77
--- /dev/null
+++ b/tests/closure/t9334.nim
@@ -0,0 +1,19 @@
+discard """
+  cmd: "nim $target --hints:off $options -r $file"
+  nimout: '''@[1]
+@[1, 1]
+'''
+  nimoutFull: true
+"""
+proc p(s: var seq[int]): auto =
+  let sptr = addr s
+  return proc() = sptr[].add 1
+
+proc f =
+  var data = @[1]
+  p(data)()
+  echo repr data
+
+static:
+  f() # prints [1]
+f() # prints [1, 1]
diff --git a/tests/closure/tboehmdeepcopy.nim b/tests/closure/tboehmdeepcopy.nim
new file mode 100644
index 000000000..7c937ca10
--- /dev/null
+++ b/tests/closure/tboehmdeepcopy.nim
@@ -0,0 +1,18 @@
+discard """
+  cmd: "nim c --gc:boehm $options $file"
+  output: '''meep'''
+  disabled: "windows"
+"""
+
+proc callit(it: proc ()) =
+  it()
+
+proc main =
+  var outer = "meep"
+  proc x =
+    echo outer
+  var y: proc()
+  deepCopy(y, x)
+  callit(y)
+
+main()
diff --git a/tests/closure/tcapture.nim b/tests/closure/tcapture.nim
new file mode 100644
index 000000000..dafc44739
--- /dev/null
+++ b/tests/closure/tcapture.nim
@@ -0,0 +1,34 @@
+discard """
+  output: '''
+to be, or not to be
+(v: 1)
+(w: -1)
+(v: 1)
+(w: -1)
+'''
+  joinable: false
+"""
+
+import sequtils, sugar
+
+let m = @[proc (s: string): string = "to " & s, proc (s: string): string = "not to " & s]
+var l = m.mapIt(capture([it], proc (s: string): string = it(s)))
+let r = l.mapIt(it("be"))
+echo r[0] & ", or " & r[1]
+
+type
+  O = object
+    v: int
+  U = object
+    w: int
+var o = O(v: 1)
+var u = U(w: -1)
+var execute: proc()
+capture o, u:
+  execute = proc() =
+    echo o
+    echo u
+execute()
+o.v = -1
+u.w = 1
+execute()
diff --git a/tests/closure/tclosure.nim b/tests/closure/tclosure.nim
new file mode 100644
index 000000000..401a71d40
--- /dev/null
+++ b/tests/closure/tclosure.nim
@@ -0,0 +1,504 @@
+discard """
+  targets: "c"
+  output: '''
+1 3 6 11 20 foo
+foo88
+23 24foo 88
+18
+18
+99
+99
+99
+99 99
+99 99
+12 99 99
+12 99 99
+success
+@[1, 2, 5]
+click at 10,20
+lost focus 1
+lost focus 2
+registered handler for UserEvent 1
+registered handler for UserEvent 2
+registered handler for UserEvent 3
+registered handler for UserEvent 4
+asdas
+processClient end
+false
+baro0
+foo88
+23 24foo 88
+foo88
+23 24foo 88
+11
+@[1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1]
+'''
+joinable: false
+"""
+
+
+block tclosure:
+  proc map(n: var openArray[int], fn: proc (x: int): int {.closure}) =
+    for i in 0..n.len-1: n[i] = fn(n[i])
+
+  proc each(n: openArray[int], fn: proc(x: int) {.closure.}) =
+    for i in 0..n.len-1:
+      fn(n[i])
+
+  var myData: array[0..4, int] = [0, 1, 2, 3, 4]
+
+  proc testA() =
+    var p = 0
+    map(myData, proc (x: int): int =
+                  result = x + 1 shl (proc (y: int): int =
+                    return y + p
+                  )(0)
+                  inc(p))
+
+  testA()
+
+  myData.each do (x: int):
+    write(stdout, x)
+    write(stdout, " ")
+
+  #OUT 2 4 6 8 10
+
+  # bug #5015
+
+  type Mutator = proc(matched: string): string {.noSideEffect, gcsafe.}
+
+  proc putMutated(
+      MutatorCount: static[int],
+      mTable: static[array[MutatorCount, Mutator]], input: string) =
+    for i in 0..<MutatorCount: echo mTable[i](input)
+
+  proc mutator0(matched: string): string =
+      "foo"
+
+  const
+    mTable = [Mutator(mutator0)]
+
+  putMutated(1, mTable, "foo")
+
+
+
+block tclosure0:
+  when true:
+    # test simple closure within dummy 'main':
+    proc dummy =
+      proc main2(param: int) =
+        var fooB = 23
+        proc outer(outerParam: string) =
+          var outerVar = 88
+          echo outerParam, outerVar
+          proc inner() =
+            block Test:
+              echo fooB, " ", param, outerParam, " ", outerVar
+          inner()
+        outer("foo")
+      main2(24)
+
+    dummy()
+
+  when true:
+    proc outer2(x:int) : proc(y:int):int =   # curry-ed application
+        return proc(y:int):int = x*y
+
+    var fn = outer2(6)  # the closure
+    echo fn(3)   # it works
+
+    var rawP = fn.rawProc()
+    var rawE = fn.rawEnv()
+
+    # A type to cast the function pointer into a nimcall
+    type TimesClosure = proc(a: int, x: pointer): int {.nimcall.}
+
+    # Call the function with its closure
+    echo cast[TimesClosure](rawP)(3, rawE)
+
+  when true:
+    proc outer =
+      var x, y: int = 99
+      proc innerA = echo x
+      proc innerB =
+        echo y
+        innerA()
+
+      innerA()
+      innerB()
+
+    outer()
+
+  when true:
+    proc indirectDep =
+      var x, y: int = 99
+      proc innerA = echo x, " ", y
+      proc innerB =
+        innerA()
+
+      innerA()
+      innerB()
+
+    indirectDep()
+
+  when true:
+    proc needlessIndirection =
+      var x, y: int = 99
+      proc indirection =
+        var z = 12
+        proc innerA = echo z, " ", x, " ", y
+        proc innerB =
+          innerA()
+
+        innerA()
+        innerB()
+      indirection()
+
+    needlessIndirection()
+
+
+
+
+
+
+block tclosure3:
+  proc main =
+    const n = 30
+    for iterations in 0..10_000:
+      var s: seq[proc(): string {.closure.}] = @[]
+      for i in 0 .. n-1:
+        (proc () =
+          let ii = i
+          s.add(proc(): string = return $(ii*ii)))()
+      for i in 0 .. n-1:
+        let val = s[i]()
+        if val != $(i*i): echo "bug  ", val
+
+      if getOccupiedMem() > 5000_000: quit("still a leak!")
+    echo "success"
+
+  main()
+
+
+
+import json, tables, sequtils
+block tclosure4:
+  proc run(json_params: OrderedTable) =
+    let json_elems = json_params["files"].elems
+    # These fail compilation.
+    var files = map(json_elems, proc (x: JsonNode): string = x.str)
+
+  let text = """{"files": ["a", "b", "c"]}"""
+  run((text.parseJson).fields)
+
+
+
+import sugar
+block inference3304:
+  type
+    List[T] = ref object
+      val: T
+
+  proc foo[T](l: List[T]): seq[int] =
+    @[1,2,3,5].filter(x => x != l.val)
+
+  echo(foo(List[int](val: 3)))
+
+
+
+block tcodegenerr1923:
+  type
+    Foo[M] = proc() : M
+
+  proc bar[M](f : Foo[M]) =
+    discard f()
+
+  proc baz() : int = 42
+
+  bar(baz)
+
+
+
+block doNotation:
+  type
+    Button = object
+    Event = object
+      x, y: int
+
+  proc onClick(x: Button, handler: proc(x: Event)) =
+    handler(Event(x: 10, y: 20))
+
+  proc onFocusLost(x: Button, handler: proc()) =
+    handler()
+
+  proc onUserEvent(x: Button, eventName: string, handler: proc) =
+    echo "registered handler for ", eventName
+
+  var b = Button()
+
+  b.onClick do (e: Event):
+    echo "click at ", e.x, ",", e.y
+
+  b.onFocusLost do ():
+    echo "lost focus 1"
+
+  b.onFocusLost do ():
+    echo "lost focus 2"
+
+  b.onUserEvent("UserEvent 1") do ():
+    discard
+
+  onUserEvent(b, "UserEvent 2") do ():
+    discard
+
+  b.onUserEvent("UserEvent 3") do ():
+    discard
+
+  b.onUserEvent("UserEvent 4", () => echo "event 4")
+
+
+
+import tables
+block fib50:
+  proc memoize(f: proc (a: int64): int64): proc (a: int64): int64 =
+      var previous = initTable[int64, int64]()
+      return proc(i: int64): int64 =
+          if not previous.hasKey i:
+              previous[i] = f(i)
+          return previous[i]
+
+  var fib: proc(a: int64): int64
+
+  fib = memoize(proc (i: int64): int64 =
+      if i == 0 or i == 1:
+          return 1
+      return fib(i-1) + fib(i-2)
+  )
+
+  doAssert fib(50) == 20365011074
+
+
+
+block tflatmap:
+  # bug #3995
+  type
+    RNG = tuple[]
+    Rand[A] = (RNG) -> (A, RNG)
+
+  proc nextInt(r: RNG): (int, RNG) =
+    (1, ())
+
+  proc flatMap[A,B](f: Rand[A], g: A -> Rand[B]): Rand[B] =
+    (rng: RNG) => (
+      let (a, rng2) = f(rng);
+      let g1 = g(a);
+      g1(rng2)
+    )
+
+  proc map[A,B](s: Rand[A], f: A -> B): Rand[B] =
+    let g: A -> Rand[B] = (a: A) => ((rng: RNG) => (f(a), rng))
+    flatMap(s, g)
+
+  discard nextInt.map(i => i - i mod 2)
+
+
+
+block tforum:
+  type
+    PAsyncHttpServer = ref object
+      value: string
+    PFutureBase = ref object
+      callback: proc () {.closure.}
+      value: string
+      failed: bool
+
+  proc accept(server: PAsyncHttpServer): PFutureBase =
+    new(result)
+    result.callback = proc () =
+      discard
+    server.value = "hahaha"
+
+  proc processClient(): PFutureBase =
+    new(result)
+
+  proc serve(server: PAsyncHttpServer): PFutureBase =
+    iterator serveIter(): PFutureBase {.closure.} =
+      echo server.value
+      while true:
+        var acceptAddrFut = server.accept()
+        yield acceptAddrFut
+        var fut = acceptAddrFut.value
+
+        var f = processClient()
+        f.callback =
+          proc () =
+            echo("processClient end")
+            echo(f.failed)
+        yield f
+    var x = serveIter
+    for i in 0 .. 1:
+      result = x()
+      result.callback()
+
+  discard serve(PAsyncHttpServer(value: "asdas"))
+
+
+
+block futclosure2138:
+  proc any[T](list: varargs[T], pred: (T) -> bool): bool =
+    for item in list:
+        if pred(item):
+            result = true
+            break
+
+  proc contains(s: string, words: varargs[string]): bool =
+    any(words, (word) => s.contains(word))
+
+
+
+block tinterf:
+  type
+    ITest = tuple[
+      setter: proc(v: int) {.closure.},
+      getter1: proc(): int {.closure.},
+      getter2: proc(): int {.closure.}]
+
+  proc getInterf(): ITest =
+    var shared1, shared2: int
+
+    return (setter: proc (x: int) =
+              shared1 = x
+              shared2 = x + 10,
+            getter1: proc (): int = result = shared1,
+            getter2: proc (): int = return shared2)
+
+  var i = getInterf()
+  i.setter(56)
+
+  doAssert i.getter1() == 56
+  doAssert i.getter2() == 66
+
+
+
+block tjester:
+  type
+    Future[T] = ref object
+      data: T
+      callback: proc () {.closure.}
+
+  proc cbOuter(response: string) {.discardable.} =
+    iterator cbIter(): Future[int] {.closure.} =
+      for i in 0..7:
+        proc foo(): int =
+          iterator fooIter(): Future[int] {.closure.} =
+            echo response, i
+            yield Future[int](data: 17)
+          var iterVar = fooIter
+          iterVar().data
+        yield Future[int](data: foo())
+
+    var iterVar2 = cbIter
+    proc cb2() {.closure.} =
+      try:
+        if not finished(iterVar2):
+          let next = iterVar2()
+          if next != nil:
+            next.callback = cb2
+      except:
+        echo "WTF"
+    cb2()
+
+  cbOuter "baro"
+
+
+
+block tnamedparamanonproc:
+  type
+    PButton = ref object
+    TButtonClicked = proc(button: PButton) {.nimcall.}
+
+  proc newButton(onClick: TButtonClicked) =
+    discard
+
+  proc main() =
+    newButton(onClick = proc(b: PButton) =
+      var requestomat = 12
+      )
+
+  main()
+
+
+
+block tnestedclosure:
+  proc main(param: int) =
+    var foo = 23
+    proc outer(outerParam: string) =
+      var outerVar = 88
+      echo outerParam, outerVar
+      proc inner() =
+        block Test:
+          echo foo, " ", param, outerParam, " ", outerVar
+      inner()
+    outer("foo")
+
+  # test simple closure within dummy 'main':
+  proc dummy =
+    proc main2(param: int) =
+      var fooB = 23
+      proc outer(outerParam: string) =
+        var outerVar = 88
+        echo outerParam, outerVar
+        proc inner() =
+          block Test:
+            echo fooB, " ", param, outerParam, " ", outerVar
+        inner()
+      outer("foo")
+    main2(24)
+
+  dummy()
+
+  main(24)
+
+  # Jester + async triggered this bug:
+  proc cbOuter() =
+    var response = "hohoho"
+    block:
+      proc cbIter() =
+        block:
+          proc fooIter() =
+            doAssert response == "hohoho"
+          fooIter()
+      cbIter()
+  cbOuter()
+
+
+
+block tnestedproc:
+  proc p(x, y: int): int =
+    result = x + y
+
+  echo p((proc (): int =
+            var x = 7
+            return x)(),
+         (proc (): int = return 4)())
+
+
+
+block tnoclosure:
+  proc pascal(n: int) =
+    var row = @[1]
+    for r in 1..n:
+      row = zip(row & @[0], @[0] & row).mapIt(it[0] + it[1])
+    echo row
+  pascal(10)
+
+block: # bug #22297
+  iterator f: int {.closure.} =
+    try:
+      yield 12
+    finally:
+      return 14
+
+  let s = f
+  doAssert s() == 12
+  doAssert s() == 14
diff --git a/tests/closure/tclosure_issues.nim b/tests/closure/tclosure_issues.nim
new file mode 100644
index 000000000..b1a2d7c6b
--- /dev/null
+++ b/tests/closure/tclosure_issues.nim
@@ -0,0 +1,82 @@
+discard """
+  output: '''true
+(999, 0)
+ok 0
+ok 1
+ok 2
+'''
+"""
+
+
+block tissue600:
+  for i in 1..1:
+    var reported = false
+    proc report() =
+      reported = true
+
+
+
+import sequtils
+block tissue1502def:
+  let xs: seq[tuple[key: string, val: seq[string]]] = @[("foo", @["bar"])]
+
+  let maps = xs.map(
+    proc(x: auto): tuple[typ: string, maps: seq[string]] =
+      (x.key, x.val.map(proc(x: string): string = x)))
+
+
+
+block tissue1642:
+  var i = 0
+  proc p() = inc(i)
+
+
+
+block tissue1846:
+  type
+    TBinOp[T] = proc (x,y: T): bool
+    THeap[T] = object
+      cmp: TBinOp[T]
+
+  proc less[T](x,y: T): bool =
+    x < y
+
+  proc initHeap[T](cmp: TBinOp[T]): THeap[T] =
+    result.cmp = cmp
+
+  var h = initHeap[int](less[int])
+  echo h.cmp(2,3)
+
+
+
+block tissue1911:
+  proc foo(x: int) : auto =
+
+    proc helper() : int = x
+    proc bar() : int = helper()
+    proc baz() : int = helper()
+
+    return (bar, baz)
+
+# bug #11523
+proc foo(): proc =
+  let a = 999
+  return proc(): (int, int) =
+    return (a, 0)
+
+echo foo()()
+
+
+block tissue7104:
+  proc sp(cb: proc())=
+      cb()
+
+  sp do ():
+      var i = 0
+      echo "ok ", i
+      sp do ():
+          inc i
+          echo "ok ", i
+          sp do ():
+              inc i
+              echo "ok ", i
diff --git a/tests/closure/texplicit_dummy_closure.nim b/tests/closure/texplicit_dummy_closure.nim
new file mode 100644
index 000000000..02b9ac7c7
--- /dev/null
+++ b/tests/closure/texplicit_dummy_closure.nim
@@ -0,0 +1,25 @@
+discard """
+  disabled: true
+"""
+
+# This is a regression of the new lambda lifting; detected by Aporia
+import asyncio, sockets
+import os
+
+type
+  Window = object
+    oneInstSock*: AsyncSocket
+    IODispatcher*: Dispatcher
+
+var
+  win: Window
+
+proc initSocket() =
+  win.oneInstSock = asyncSocket()
+  #win.oneInstSock.handleAccept =
+  proc test(s: AsyncSocket) =
+    var client: AsyncSocket
+    proc dummy(c: AsyncSocket) {.closure.} =
+      discard
+    client.handleRead = dummy
+  test(win.oneInstSock)
diff --git a/tests/closure/tinfer_closure_for_nestedproc.nim b/tests/closure/tinfer_closure_for_nestedproc.nim
new file mode 100644
index 000000000..6450d1492
--- /dev/null
+++ b/tests/closure/tinfer_closure_for_nestedproc.nim
@@ -0,0 +1,42 @@
+discard """
+  action: compile
+"""
+
+# bug #9441
+import asyncdispatch, asyncfutures, strtabs
+
+type
+  Request = object
+  Context = object
+    position: int
+    accept: bool
+    headers: StringTableRef
+  Handler = proc (r: ref Request, c: Context): Future[Context]
+
+proc respond(req: Request): Future[void] = discard
+
+proc handle*(h: Handler): auto = # (proc (req: Request): Future[void]) =
+  proc server(req: Request): Future[void] {.async.} =
+    let emptyCtx = Context(
+      position: 0,
+      accept: true,
+      headers: newStringTable()
+    )
+    var reqHeap = new(Request)
+    reqHeap[] = req
+    var
+      f: Future[Context]
+      ctx: Context
+    try:
+      f = h(reqHeap, emptyCtx)
+      ctx = await f
+    except:
+      discard
+    if f.failed:
+      await req.respond()
+    else:
+      if not ctx.accept:
+        await req.respond()
+  return server
+
+waitFor handle(nil)(Request())
diff --git a/tests/closure/tinvalidclosure.nim b/tests/closure/tinvalidclosure.nim
new file mode 100644
index 000000000..37d0f68a2
--- /dev/null
+++ b/tests/closure/tinvalidclosure.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "type mismatch: got <proc (x: int){.nimcall, gcsafe.}>"
+  line: 12
+"""
+
+proc ugh[T](x: T) {.nimcall.} =
+  echo "ugha"
+
+
+proc takeCdecl(p: proc (x: int) {.cdecl.}) = discard
+
+takeCDecl(ugh[int])
diff --git a/tests/closure/tinvalidclosure2.nim b/tests/closure/tinvalidclosure2.nim
new file mode 100644
index 000000000..2d58f0215
--- /dev/null
+++ b/tests/closure/tinvalidclosure2.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "illegal capture 'A'"
+  line: 10
+"""
+
+proc outer() =
+  var A: int
+
+  proc ugh[T](x: T) {.cdecl.} =
+    echo "ugha", A, x
+
+  ugh[int](12)
+
+outer()
diff --git a/tests/closure/tinvalidclosure3.nim b/tests/closure/tinvalidclosure3.nim
new file mode 100644
index 000000000..0cbdaf39e
--- /dev/null
+++ b/tests/closure/tinvalidclosure3.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "illegal capture 'x'"
+  line: 9
+"""
+
+proc outer(arg: string) =
+  var x = 0
+  proc inner {.inline.} =
+    echo "inner", x
+  inner()
+
+outer("abc")
diff --git a/tests/closure/tinvalidclosure4.nim b/tests/closure/tinvalidclosure4.nim
new file mode 100644
index 000000000..7985a2488
--- /dev/null
+++ b/tests/closure/tinvalidclosure4.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "illegal capture 'v'"
+  line: 7
+"""
+
+proc outer(v: int) =
+  proc b {.nimcall.} = echo v
+  b()
+outer(5)
diff --git a/tests/closure/tinvalidclosure5.nim b/tests/closure/tinvalidclosure5.nim
new file mode 100644
index 000000000..3b5f46a40
--- /dev/null
+++ b/tests/closure/tinvalidclosure5.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "type mismatch: got <proc (){.closure, gcsafe.}> but expected 'A = proc (){.nimcall.}'"
+  line: 9
+"""
+
+type A = proc() {.nimcall.}
+proc main =
+  let b = 1
+  let a: A = proc() = echo b
+
diff --git a/tests/closure/tmacrobust1512.nim b/tests/closure/tmacrobust1512.nim
new file mode 100644
index 000000000..0f44c5e1a
--- /dev/null
+++ b/tests/closure/tmacrobust1512.nim
@@ -0,0 +1,123 @@
+discard """
+output: ""
+"""
+
+import macros, strutils
+
+# https://github.com/nim-lang/Nim/issues/1512
+
+proc macrobust0(input: string): string =
+  var output = ""
+  proc p1(a:string) =
+    output.add(a)
+
+  proc p2(a:string) = p1(a)
+  proc p3(a:string) = p2(a)
+  proc p4(a:string) = p3(a)
+  proc p5(a:string) = p4(a)
+  proc p6(a:string) = p5(a)
+  proc p7(a:string) = p6(a)
+  proc p8(a:string) = p7(a)
+  proc p9(a:string) = p8(a)
+  proc p10(a:string) = p9(a)
+  proc p11(a:string) = p10(a)
+  proc p12(a:string) = p11(a)
+  proc p13(a:string) = p12(a)
+  proc p14(a:string) = p13(a)
+  proc p15(a:string) = p14(a)
+  proc p16(a:string) = p15(a)
+  proc p17(a:string) = p16(a)
+  proc p18(a:string) = p17(a)
+  proc p19(a:string) = p18(a)
+  proc p20(a:string) = p19(a)
+
+  for a in input.split():
+    p20(a)
+    p19(a)
+    p18(a)
+    p17(a)
+    p16(a)
+    p15(a)
+    p14(a)
+    p13(a)
+    p12(a)
+    p11(a)
+    p10(a)
+    p9(a)
+    p8(a)
+    p7(a)
+    p6(a)
+    p5(a)
+    p4(a)
+    p3(a)
+    p2(a)
+    p1(a)
+
+  result = output
+
+macro macrobust(input: static[string]): untyped =
+  var output = ""
+  proc p1(a:string) =
+    output.add(a)
+
+  proc p2(a:string) = p1(a)
+  proc p3(a:string) = p2(a)
+  proc p4(a:string) = p3(a)
+  proc p5(a:string) = p4(a)
+  proc p6(a:string) = p5(a)
+  proc p7(a:string) = p6(a)
+  proc p8(a:string) = p7(a)
+  proc p9(a:string) = p8(a)
+  proc p10(a:string) = p9(a)
+  proc p11(a:string) = p10(a)
+  proc p12(a:string) = p11(a)
+  proc p13(a:string) = p12(a)
+  proc p14(a:string) = p13(a)
+  proc p15(a:string) = p14(a)
+  proc p16(a:string) = p15(a)
+  proc p17(a:string) = p16(a)
+  proc p18(a:string) = p17(a)
+  proc p19(a:string) = p18(a)
+  proc p20(a:string) = p19(a)
+
+  for a in input.split():
+    p20(a)
+    p19(a)
+    p18(a)
+    p17(a)
+    p16(a)
+    p15(a)
+    p14(a)
+    p13(a)
+    p12(a)
+    p11(a)
+    p10(a)
+    p9(a)
+    p8(a)
+    p7(a)
+    p6(a)
+    p5(a)
+    p4(a)
+    p3(a)
+    p2(a)
+    p1(a)
+
+  result = newLit(output)
+
+const input = """
+  fdsasadfsdfa sadfsdafsdaf
+  dsfsdafdsfadsfa fsdaasdfasdf
+  fsdafsadfsad asdfasdfasdf
+  fdsasdfasdfa sadfsadfsadf
+  sadfasdfsdaf sadfsdafsdaf dsfasdaf
+  sadfsdafsadf fdsasdafsadf fdsasadfsdaf
+  sdfasadfsdafdfsa sadfsadfsdaf
+  sdafsdaffsda sdfasadfsadf
+  fsdasdafsdfa sdfasdfafsda
+  sdfasdafsadf sdfasdafsdaf sdfasdafsdaf
+"""
+
+let str1 = macrobust(input)
+let str2 = macrobust0(input)
+
+doAssert str1 == str2
diff --git a/tests/closure/tnested.nim b/tests/closure/tnested.nim
new file mode 100644
index 000000000..ec5af9b13
--- /dev/null
+++ b/tests/closure/tnested.nim
@@ -0,0 +1,215 @@
+discard """
+targets: "c js"
+output: '''
+foo88
+23 24foo 88
+foo88
+23 24foo 88
+11
+int: 108
+0
+11
+1
+11
+2
+11
+3
+11
+4
+11
+5
+11
+6
+11
+7
+11
+8
+11
+9
+11
+11
+py
+py
+py
+py
+px
+6
+proc (){.closure, noSideEffect, gcsafe.}
+'''
+"""
+
+
+block tnestedclosure:
+  proc main(param: int) =
+    var foo = 23
+    proc outer(outerParam: string) =
+      var outerVar = 88
+      echo outerParam, outerVar
+      proc inner() =
+        block Test:
+          echo foo, " ", param, outerParam, " ", outerVar
+      inner()
+    outer("foo")
+
+  # test simple closure within dummy 'main':
+  proc dummy =
+    proc main2(param: int) =
+      var fooB = 23
+      proc outer(outerParam: string) =
+        var outerVar = 88
+        echo outerParam, outerVar
+        proc inner() =
+          block Test:
+            echo fooB, " ", param, outerParam, " ", outerVar
+        inner()
+      outer("foo")
+    main2(24)
+
+  dummy()
+
+  main(24)
+
+  # Jester + async triggered this bug:
+  proc cbOuter() =
+    var response = "hohoho"
+    block:
+      proc cbIter() =
+        block:
+          proc fooIter() =
+            doAssert response == "hohoho"
+          fooIter()
+      cbIter()
+  cbOuter()
+
+
+block tnestedproc:
+  proc p(x, y: int): int =
+    result = x + y
+
+  echo p((proc (): int =
+            var x = 7
+            return x)(),
+         (proc (): int = return 4)())
+
+
+block deeplynested:
+  # bug #4070
+  proc id(f: (proc())): auto =
+    return f
+
+  proc foo(myinteger: int): (iterator(): int) =
+    return iterator(): int {.closure.} =
+            proc bar() =
+              proc kk() =
+                echo "int: ", myinteger
+              kk()
+            id(bar)()
+
+  discard foo(108)()
+
+
+block tclosure2:
+  when true:
+    proc ax =
+      for xxxx in 0..9:
+        var i = 0
+        proc bx =
+          if i > 10:
+            echo xxxx
+            return
+          i += 1
+          #for j in 0 .. 0: echo i
+          bx()
+
+        bx()
+        echo i
+
+    ax()
+
+  when true:
+    proc accumulator(start: int): (proc(): int {.closure.}) =
+      var x = start-1
+      #let dummy = proc =
+      #  discard start
+
+      result = proc (): int =
+        #var x = 9
+        for i in 0 .. 0: x = x + 1
+
+        return x
+
+    var a = accumulator(3)
+    let b = accumulator(4)
+    echo a() + b() + a()
+
+
+    proc outer =
+
+      proc py() =
+        # no closure here:
+        for i in 0..3: echo "py"
+
+      py()
+
+    outer()
+
+
+  when true:
+    proc outer2 =
+      var errorValue = 3
+      proc fac[T](n: T): T =
+        if n < 0: result = errorValue
+        elif n <= 1: result = 1
+        else: result = n * fac(n-1)
+
+      proc px() {.closure.} =
+        echo "px"
+
+      proc py() {.closure.} =
+        echo "py"
+
+      let
+        mapping = {
+          "abc": px,
+          "xyz": py
+        }
+      mapping[0][1]()
+
+      echo fac(3)
+
+
+    outer2()
+
+# bug #5688
+
+import typetraits
+
+block:
+  proc myDiscard[T](a: T) = discard
+
+  proc foo() =
+    let a = 5
+    let f = (proc() =
+              myDiscard (proc() = echo a)
+            )
+    echo name(typeof(f))
+
+  foo()
+
+
+block:
+  iterator foo: int {.closure.} =
+    yield 1
+    yield 2
+    yield 3
+
+  proc pork =
+    let call = foo
+    for i in call():
+      discard i
+
+    let call2 = foo
+    while not finished(call2):
+      discard call2()
+
+  pork()
diff --git a/tests/closure/tstmtlist.nim b/tests/closure/tstmtlist.nim
new file mode 100644
index 000000000..6a1390617
--- /dev/null
+++ b/tests/closure/tstmtlist.nim
@@ -0,0 +1,9 @@
+discard """
+  action: compile
+"""
+
+proc foo(x: proc()) = x()
+foo: echo "a" #[tt.Warning
+     ^ statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead [StmtListLambda]]#
+foo do: echo "b" #[tt.Warning
+        ^ statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead [StmtListLambda]]#
diff --git a/tests/closure/ttimeinfo.nim b/tests/closure/ttimeinfo.nim
new file mode 100644
index 000000000..24d535cbf
--- /dev/null
+++ b/tests/closure/ttimeinfo.nim
@@ -0,0 +1,22 @@
+discard """
+output: '''
+@[2000-01-01T00:00:00Z, 2001-01-01T00:00:00Z, 2002-01-01T00:00:00Z, 2003-01-01T00:00:00Z, 2004-01-01T00:00:00Z, 2005-01-01T00:00:00Z, 2006-01-01T00:00:00Z, 2007-01-01T00:00:00Z, 2008-01-01T00:00:00Z, 2009-01-01T00:00:00Z, 2010-01-01T00:00:00Z, 2011-01-01T00:00:00Z, 2012-01-01T00:00:00Z, 2013-01-01T00:00:00Z, 2014-01-01T00:00:00Z, 2015-01-01T00:00:00Z]
+@[2000-01-01T00:00:00Z, 2001-01-01T00:00:00Z, 2002-01-01T00:00:00Z, 2003-01-01T00:00:00Z, 2004-01-01T00:00:00Z, 2005-01-01T00:00:00Z, 2006-01-01T00:00:00Z, 2007-01-01T00:00:00Z, 2008-01-01T00:00:00Z, 2009-01-01T00:00:00Z, 2010-01-01T00:00:00Z, 2011-01-01T00:00:00Z, 2012-01-01T00:00:00Z, 2013-01-01T00:00:00Z, 2014-01-01T00:00:00Z, 2015-01-01T00:00:00Z]
+'''
+"""
+
+# bug #2073
+
+import sequtils
+import times
+
+# 1
+proc f(n: int): DateTime =
+  initDateTime(1, mJan, n, 0, 0, 0, utc())
+
+echo toSeq(2000 || 2015).map(f)
+
+# 2
+echo toSeq(2000 || 2015).map(proc (n: int): DateTime =
+  initDateTime(1, mJan, n, 0, 0, 0, utc())
+)
diff --git a/tests/closure/uclosures.nim b/tests/closure/uclosures.nim
new file mode 100644
index 000000000..f259cfeb9
--- /dev/null
+++ b/tests/closure/uclosures.nim
@@ -0,0 +1,23 @@
+# This test is included from within tunittests
+import unittest
+
+test "loop variables are captured by ref":
+  var funcs: seq[proc (): int {.closure.}] = @[]
+
+  for i in 0..10:
+    let ii = i
+    funcs.add do -> int: return ii * ii
+
+  check funcs[0]() == 100
+  check funcs[3]() == 100
+
+test "loop variables in closureScope are captured by copy":
+  var funcs: seq[proc (): int {.closure.}] = @[]
+
+  for i in 0..10:
+    closureScope:
+      let ii = i
+      funcs.add do -> int: return ii * ii
+
+  check funcs[0]() == 0
+  check funcs[3]() == 9