summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authormetagn <metagngn@gmail.com>2023-04-11 10:23:41 +0300
committerGitHub <noreply@github.com>2023-04-11 09:23:41 +0200
commit1bb117cd7a49954832d21e6a1502492770acb77b (patch)
tree299cbbc13c72d8f0e3844a1c9770874a25050a67 /lib
parent420b0c14eb0b82e05873191b277e889f95bc802b (diff)
downloadNim-1bb117cd7a49954832d21e6a1502492770acb77b.tar.gz
`proc` typeclass accounts for `iterator`, call conventions + `nil` fix + document typeclass AST (#21629)
* test fix #16546 #16548 + another issue

* please don't tell me other packages do this

* fix CI + test typeclass callconv pragma

* better logic in parser

* docs and changelog
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/hashes.nim2
-rw-r--r--lib/system.nim51
2 files changed, 22 insertions, 31 deletions
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index 4ae4938c6..56c360138 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -501,7 +501,7 @@ proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash =
     h = h !& ord(c)
   result = !$h
 
-proc hash*[T: tuple | object | proc](x: T): Hash =
+proc hash*[T: tuple | object | proc | iterator {.closure.}](x: T): Hash =
   ## Efficient `hash` overload.
   runnableExamples:
     # for `tuple|object`, `hash` must be defined for each component of `x`.
diff --git a/lib/system.nim b/lib/system.nim
index 3a2487004..dcf09d604 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -62,11 +62,11 @@ proc typeof*(x: untyped; mode = typeOfIter): typedesc {.
     doAssert type(myFoo()) is string
     doAssert typeof(myFoo()) is string
     doAssert typeof(myFoo(), typeOfIter) is string
-    doAssert typeof(myFoo3) is "iterator"
+    doAssert typeof(myFoo3) is iterator
 
     doAssert typeof(myFoo(), typeOfProc) is float
     doAssert typeof(0.0, typeOfProc) is float
-    doAssert typeof(myFoo3, typeOfProc) is "iterator"
+    doAssert typeof(myFoo3, typeOfProc) is iterator
     doAssert not compiles(typeof(myFoo2(), typeOfProc))
       # this would give: Error: attempting to call routine: 'myFoo2'
       # since `typeOfProc` expects a typed expression and `myFoo2()` can
@@ -2188,39 +2188,30 @@ when notJSnotNims:
     include "system/profiler"
   {.pop.}
 
-  proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
+  proc rawProc*[T: proc {.closure.} | iterator {.closure.}](x: T): pointer {.noSideEffect, inline.} =
     ## Retrieves the raw proc pointer of the closure `x`. This is
     ## useful for interfacing closures with C/C++, hash compuations, etc.
-    when T is "closure":
-      #[
-      The conversion from function pointer to `void*` is a tricky topic, but this
-      should work at least for c++ >= c++11, e.g. for `dlsym` support.
-      refs: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57869,
-      https://stackoverflow.com/questions/14125474/casts-between-pointer-to-function-and-pointer-to-object-in-c-and-c
-      ]#
-      {.emit: """
-      `result` = (void*)`x`.ClP_0;
-      """.}
-    else:
-      {.error: "Only closure function and iterator are allowed!".}
-
-  proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} =
+    #[
+    The conversion from function pointer to `void*` is a tricky topic, but this
+    should work at least for c++ >= c++11, e.g. for `dlsym` support.
+    refs: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57869,
+    https://stackoverflow.com/questions/14125474/casts-between-pointer-to-function-and-pointer-to-object-in-c-and-c
+    ]#
+    {.emit: """
+    `result` = (void*)`x`.ClP_0;
+    """.}
+
+  proc rawEnv*[T: proc {.closure.} | iterator {.closure.}](x: T): pointer {.noSideEffect, inline.} =
     ## Retrieves the raw environment pointer of the closure `x`. See also `rawProc`.
-    when T is "closure":
-      {.emit: """
-      `result` = `x`.ClE_0;
-      """.}
-    else:
-      {.error: "Only closure function and iterator are allowed!".}
+    {.emit: """
+    `result` = `x`.ClE_0;
+    """.}
 
-  proc finished*[T: proc](x: T): bool {.noSideEffect, inline, magic: "Finished".} =
+  proc finished*[T: iterator {.closure.}](x: T): bool {.noSideEffect, inline, magic: "Finished".} =
     ## It can be used to determine if a first class iterator has finished.
-    when T is "iterator":
-      {.emit: """
-      `result` = ((NI*) `x`.ClE_0)[1] < 0;
-      """.}
-    else:
-      {.error: "Only closure iterator is allowed!".}
+    {.emit: """
+    `result` = ((NI*) `x`.ClE_0)[1] < 0;
+    """.}
 
 from std/private/digitsutils import addInt
 export addInt