parent
fb86271556
commit
ee6d56141c
4 changed files with 93 additions and 14 deletions
|
|
@ -524,15 +524,21 @@ proc hash*[T: tuple | object | proc](x: T): Hash {.inline.} =
|
||||||
proc hash(a: Obj2): Hash = hash((a.x))
|
proc hash(a: Obj2): Hash = hash((a.x))
|
||||||
assert hash(Obj2[float](x: 520, y: "Nim")) == hash(Obj2[float](x: 520, y: "Nim2"))
|
assert hash(Obj2[float](x: 520, y: "Nim")) == hash(Obj2[float](x: 520, y: "Nim2"))
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
# proc and closure examples
|
# proc
|
||||||
proc fn1() = discard
|
proc fn1() = discard
|
||||||
var a = 0
|
|
||||||
proc fn2() = a.inc
|
|
||||||
assert hash(fn1) != hash(fn2)
|
|
||||||
const fn1b = fn1
|
const fn1b = fn1
|
||||||
assert hash(fn1b) == hash(fn1)
|
assert hash(fn1b) == hash(fn1)
|
||||||
|
|
||||||
|
# closure
|
||||||
|
proc outer =
|
||||||
|
var a = 0
|
||||||
|
proc fn2() = a.inc
|
||||||
|
assert fn2 is "closure"
|
||||||
let fn2b = fn2
|
let fn2b = fn2
|
||||||
assert hash(fn2b) == hash(fn2)
|
assert hash(fn2b) == hash(fn2)
|
||||||
|
assert hash(fn2) != hash(fn1)
|
||||||
|
outer()
|
||||||
|
|
||||||
when T is "closure":
|
when T is "closure":
|
||||||
result = hash((rawProc(x), rawEnv(x)))
|
result = hash((rawProc(x), rawEnv(x)))
|
||||||
elif T is (proc):
|
elif T is (proc):
|
||||||
|
|
|
||||||
|
|
@ -2414,17 +2414,22 @@ when notJSnotNims:
|
||||||
|
|
||||||
proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
|
proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
|
||||||
## Retrieves the raw proc pointer of the closure `x`. This is
|
## Retrieves the raw proc pointer of the closure `x`. This is
|
||||||
## useful for interfacing closures with C.
|
## useful for interfacing closures with C/C++, hash compuations, etc.
|
||||||
when T is "closure":
|
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: """
|
{.emit: """
|
||||||
`result` = `x`.ClP_0;
|
`result` = (void*)`x`.ClP_0;
|
||||||
""".}
|
""".}
|
||||||
else:
|
else:
|
||||||
{.error: "Only closure function and iterator are allowed!".}
|
{.error: "Only closure function and iterator are allowed!".}
|
||||||
|
|
||||||
proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} =
|
proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} =
|
||||||
## Retrieves the raw environment pointer of the closure `x`. This is
|
## Retrieves the raw environment pointer of the closure `x`. See also `rawProc`.
|
||||||
## useful for interfacing closures with C.
|
|
||||||
when T is "closure":
|
when T is "closure":
|
||||||
{.emit: """
|
{.emit: """
|
||||||
`result` = `x`.ClE_0;
|
`result` = `x`.ClE_0;
|
||||||
|
|
|
||||||
|
|
@ -184,8 +184,8 @@ proc main() =
|
||||||
# pending fix proposed in https://github.com/nim-lang/Nim/issues/15952#issuecomment-786312417
|
# pending fix proposed in https://github.com/nim-lang/Nim/issues/15952#issuecomment-786312417
|
||||||
discard
|
discard
|
||||||
do:
|
do:
|
||||||
assert a[0].addr.hash != a[1].addr.hash
|
doAssert a[0].addr.hash != a[1].addr.hash
|
||||||
assert cast[pointer](a[0].addr).hash == a[0].addr.hash
|
doAssert cast[pointer](a[0].addr).hash == a[0].addr.hash
|
||||||
|
|
||||||
block: # hash(ref)
|
block: # hash(ref)
|
||||||
type A = ref object
|
type A = ref object
|
||||||
|
|
@ -193,9 +193,31 @@ proc main() =
|
||||||
let a = A(x: 3)
|
let a = A(x: 3)
|
||||||
disableVm: # xxx Error: VM does not support 'cast' from tyRef to tyPointer
|
disableVm: # xxx Error: VM does not support 'cast' from tyRef to tyPointer
|
||||||
let ha = a.hash
|
let ha = a.hash
|
||||||
assert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`.
|
doAssert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`.
|
||||||
a.x = 4
|
a.x = 4
|
||||||
assert ha == a.hash # the hash only depends on the address
|
doAssert ha == a.hash # the hash only depends on the address
|
||||||
|
|
||||||
|
block: # hash(proc)
|
||||||
|
proc fn(a: int): auto = a*2
|
||||||
|
doAssert fn isnot "closure"
|
||||||
|
doAssert fn is (proc)
|
||||||
|
const fn2 = fn
|
||||||
|
let fn3 = fn
|
||||||
|
whenVMorJs: discard
|
||||||
|
do:
|
||||||
|
doAssert hash(fn2) == hash(fn)
|
||||||
|
doAssert hash(fn3) == hash(fn)
|
||||||
|
|
||||||
|
block: # hash(closure)
|
||||||
|
proc outer() =
|
||||||
|
var a = 0
|
||||||
|
proc inner() = a.inc
|
||||||
|
doAssert inner is "closure"
|
||||||
|
let inner2 = inner
|
||||||
|
whenVMorJs: discard
|
||||||
|
do:
|
||||||
|
doAssert hash(inner2) == hash(inner)
|
||||||
|
outer()
|
||||||
|
|
||||||
static: main()
|
static: main()
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
46
tests/stdlib/tsystem.nim
Normal file
46
tests/stdlib/tsystem.nim
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
discard """
|
||||||
|
targets: "c cpp js"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# TODO: in future work move existing `system` tests here, where they belong
|
||||||
|
|
||||||
|
import stdtest/testutils
|
||||||
|
|
||||||
|
template main =
|
||||||
|
block: # closure
|
||||||
|
proc outer() =
|
||||||
|
var a = 0
|
||||||
|
proc inner1 = a.inc
|
||||||
|
proc inner2 = discard
|
||||||
|
doAssert inner1 is "closure"
|
||||||
|
doAssert inner2 isnot "closure"
|
||||||
|
doAssert inner1 is (proc)
|
||||||
|
doAssert inner2 is (proc)
|
||||||
|
let inner1b = inner1
|
||||||
|
doAssert inner1b is "closure"
|
||||||
|
doAssert inner1b == inner1
|
||||||
|
outer()
|
||||||
|
|
||||||
|
block: # rawProc, rawProc, bug #17911
|
||||||
|
proc outer() =
|
||||||
|
var a = 0
|
||||||
|
var b = 0
|
||||||
|
proc inner1() = a.inc
|
||||||
|
proc inner2() = a += 2
|
||||||
|
proc inner3() = b.inc
|
||||||
|
let inner1b = inner1
|
||||||
|
doAssert inner2 != inner1
|
||||||
|
doAssert inner3 != inner1
|
||||||
|
whenVMorJs: discard
|
||||||
|
do:
|
||||||
|
doAssert rawProc(inner1b) == rawProc(inner1)
|
||||||
|
doAssert rawProc(inner2) != rawProc(inner1)
|
||||||
|
doAssert rawProc(inner3) != rawProc(inner1)
|
||||||
|
|
||||||
|
doAssert rawEnv(inner1b) == rawEnv(inner1)
|
||||||
|
doAssert rawEnv(inner2) == rawEnv(inner1) # because both use `a`
|
||||||
|
# doAssert rawEnv(inner3) != rawEnv(inner1) # because `a` vs `b` # this doesn't hold
|
||||||
|
outer()
|
||||||
|
|
||||||
|
static: main()
|
||||||
|
main()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue