tgettype.nim 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import std/macros
  2. import stdtest/testutils
  3. # getType
  4. block:
  5. type
  6. Model = object of RootObj
  7. User = object of Model
  8. name : string
  9. password : string
  10. macro testUser: string =
  11. result = newLit(User.getType.lispRepr)
  12. macro testGeneric(T: typedesc[Model]): string=
  13. result = newLit(T.getType.lispRepr)
  14. doAssert testUser == """(ObjectTy (Empty) (Sym "Model") (RecList (Sym "name") (Sym "password")))"""
  15. doAssert User.testGeneric == """(BracketExpr (Sym "typeDesc") (Sym "User"))"""
  16. macro assertVoid(e: typed): untyped =
  17. assert(getTypeInst(e).typeKind == ntyVoid)
  18. proc voidProc() = discard
  19. assertVoid voidProc()
  20. block:
  21. # refs #18220; not an actual solution (yet) but at least shows what's currently
  22. # possible
  23. type Callable1[R, T, U] = concept fn
  24. fn(default(T)) is R
  25. fn is U
  26. # note that typetraits.arity doesn't work
  27. macro arity(a: typed): int =
  28. # number of params
  29. # this is not production code!
  30. let a2 = a.getType[1] # this used to crash nim, with: `vmdeps.nim(292, 25) `false``
  31. newLit a2.len - 1
  32. type Callable2[R, T, U] = concept fn
  33. fn(default(T)) is R
  34. fn is U
  35. arity(U) == 2
  36. proc map1[T, R, U](a: T, fn: Callable1[R, T, U]): R =
  37. let fn = U(fn)
  38. # `cast[U](fn)` would also work;
  39. # this is currently needed otherwise, sigmatch errors with:
  40. # Error: attempting to call routine: 'fn'
  41. # found 'fn' [param declared in tgettype.nim(53, 28)]
  42. # this can be fixed in future work
  43. fn(a)
  44. proc map2[T, R, U](a: T, fn: Callable2[R, T, U]): R =
  45. let fn = U(fn)
  46. fn(a)
  47. proc fn1(a: int, a2 = 'x'): string = $(a, a2, "fn1")
  48. proc fn2(a: int, a2 = "zoo"): string = $(a, a2, "fn2")
  49. proc fn3(a: int, a2 = "zoo2"): string = $(a, a2, "fn3")
  50. proc fn4(a: int): string {.inline.} = $(a, "fn4")
  51. proc fn5(a: int): string = $(a, "fn5")
  52. assertAll:
  53. # Callable1
  54. 1.map1(fn1) == """(1, 'x', "fn1")"""
  55. 1.map1(fn2) == """(1, "zoo", "fn2")"""
  56. 1.map1(fn3) == """(1, "zoo", "fn3")"""
  57. # fn3's optional param is not honored, because fn3 and fn2 yield same
  58. # generic instantiation; this is a caveat with this approach
  59. # There are several possible ways to improve things in future work.
  60. 1.map1(fn4) == """(1, "fn4")"""
  61. 1.map1(fn5) == """(1, "fn5")"""
  62. # Callable2; prevents passing procs with optional params to avoid above
  63. # mentioned caveat, but more restrictive
  64. not compiles(1.map2(fn1))
  65. not compiles(1.map2(fn2))
  66. not compiles(1.map2(fn3))
  67. 1.map2(fn4) == """(1, "fn4")"""
  68. 1.map2(fn5) == """(1, "fn5")"""