summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorflywind <xzsflywind@gmail.com>2021-03-29 20:22:29 +0800
committerGitHub <noreply@github.com>2021-03-29 14:22:29 +0200
commit81e54c1d30b7651851b9de56d76b9af81e192504 (patch)
treeb617b6cc0b2cf9de12a71e41385bd355bd3efab6
parent04520c0ce4ed38a3fbae37731a4979480144c77b (diff)
downloadNim-81e54c1d30b7651851b9de56d76b9af81e192504.tar.gz
Add `hasClosure` to `std/typetraits` (#17501)
* fix nim js cmp fails at CT

* Add `hasClosure` to `std/effecttraits`

* type

* Update changelog.md

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>

* Update lib/std/effecttraits.nim

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
-rw-r--r--changelog.md2
-rw-r--r--compiler/vmops.nim4
-rw-r--r--lib/pure/typetraits.nim11
-rw-r--r--tests/stdlib/ttypetraits.nim92
4 files changed, 109 insertions, 0 deletions
diff --git a/changelog.md b/changelog.md
index d3335c2a3..be130f780 100644
--- a/changelog.md
+++ b/changelog.md
@@ -246,6 +246,8 @@
 
 - Added dollar `$` and `len` for `jsre.RegExp`.
 
+- Added `hasClosure` to `std/typetraits`.
+
 
 ## Language changes
 
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index 5748b41b3..04356fc76 100644
--- a/compiler/vmops.nim
+++ b/compiler/vmops.nim
@@ -316,3 +316,7 @@ proc registerAdditionalOps*(c: PCtx) =
     let fn = getNode(a, 0)
     setResult(a, (fn.typ != nil and tfNoSideEffect in fn.typ.flags) or
                  (fn.kind == nkSym and fn.sym.kind == skFunc))
+
+  registerCallback c, "stdlib.typetraits.hasClosureImpl", proc (a: VmArgs) =
+    let fn = getNode(a, 0)
+    setResult(a, fn.kind == nkClosure or (fn.typ != nil and fn.typ.callConv == ccClosure))
diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim
index 6827e23b1..2527dc26e 100644
--- a/lib/pure/typetraits.nim
+++ b/lib/pure/typetraits.nim
@@ -263,3 +263,14 @@ since (1, 1):
 
     type T2 = T
     genericParamsImpl(T2)
+
+
+proc hasClosureImpl(n: NimNode): bool = discard "see compiler/vmops.nim"
+
+proc hasClosure*(fn: NimNode): bool {.since: (1, 5, 1).} =
+  ## Return true if the func/proc/etc `fn` has `closure`.
+  ## `fn` has to be a resolved symbol of kind `nnkSym`. This
+  ## implies that the macro that calls this proc should accept `typed`
+  ## arguments and not `untyped` arguments.
+  expectKind fn, nnkSym
+  result = hasClosureImpl(fn)
diff --git a/tests/stdlib/ttypetraits.nim b/tests/stdlib/ttypetraits.nim
new file mode 100644
index 000000000..de8259ab0
--- /dev/null
+++ b/tests/stdlib/ttypetraits.nim
@@ -0,0 +1,92 @@
+discard """
+  targets: "c cpp js"
+"""
+
+import std/typetraits
+
+
+
+macro testClosure(fn: typed, flag: static bool) =
+  if flag:
+    doAssert hasClosure(fn)
+  else:
+    doAssert not hasClosure(fn)
+
+block:
+  proc h1() =
+    echo 1
+
+  testClosure(h1, false)
+
+  proc h2() {.nimcall.} =
+    echo 2
+
+  testClosure(h2, false)
+
+
+block:
+  proc fn(): auto =
+    proc hello() {.nimcall.} =
+      echo 3
+    hello
+
+  let name = fn()
+  testClosure(name, false)
+
+block:
+  proc fn(): auto =
+    proc hello() =
+      echo 3
+    hello
+
+  let name = fn()
+  testClosure(name, false)
+
+block:
+  proc fn(): auto =
+    var x = 0
+    proc hello() =
+      echo 3
+      inc x
+    hello
+
+  let name = fn()
+  testClosure(name, true)
+
+block:
+  proc fn(): auto =
+    var x = 0
+    proc hello() {.closure.} =
+      echo 3
+      inc x
+    hello
+
+  let name = fn()
+  testClosure(name, true)
+
+block:
+  proc fn(): auto =
+    var x = 0
+    proc hello() {.closure.} =
+      echo 3
+      inc x
+    hello
+
+  let name = fn()
+  testClosure(name, true)
+
+  let name2 = name
+  testClosure(name2, true)
+
+block:
+  iterator hello(): int =
+    yield 1
+
+  testClosure(hello, false)
+
+when not defined(js):
+  block:
+    iterator hello(): int {.closure.}=
+      yield 1
+
+    testClosure(hello, true)