ttypetraits.nim 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. import typetraits
  2. import macros
  3. block: # isNamedTuple
  4. type Foo1 = (a:1,).type
  5. type Foo2 = (Field0:1,).type
  6. type Foo3 = ().type
  7. type Foo4 = object
  8. type Foo5[T] = tuple[x:int, y: T]
  9. type Foo6[T] = (T,)
  10. doAssert (a:1,).type.isNamedTuple
  11. doAssert Foo1.isNamedTuple
  12. doAssert Foo2.isNamedTuple
  13. doAssert isNamedTuple(tuple[key: int])
  14. doAssert not Foo3.isNamedTuple
  15. doAssert not Foo4.isNamedTuple
  16. doAssert not (1,).type.isNamedTuple
  17. doAssert isNamedTuple(Foo5[int8])
  18. doAssert not isNamedTuple(Foo5)
  19. doAssert not isNamedTuple(Foo6[int8])
  20. proc typeToString*(t: typedesc, prefer = "preferTypeName"): string {.magic: "TypeTrait".}
  21. ## Returns the name of the given type, with more flexibility than `name`,
  22. ## and avoiding the potential clash with a variable named `name`.
  23. ## prefer = "preferResolved" will resolve type aliases recursively.
  24. # Move to typetraits.nim once api stabilized.
  25. block: # name, `$`
  26. static:
  27. doAssert $type(42) == "int"
  28. doAssert int.name == "int"
  29. const a1 = name(int)
  30. const a2 = $(int)
  31. const a3 = $int
  32. doAssert a1 == "int"
  33. doAssert a2 == "int"
  34. doAssert a3 == "int"
  35. proc fun[T: typedesc](t: T) =
  36. const a1 = name(t)
  37. const a2 = $(t)
  38. const a3 = $t
  39. doAssert a1 == "int"
  40. doAssert a2 == "int"
  41. doAssert a3 == "int"
  42. fun(int)
  43. doAssert $(int,) == "(int,)"
  44. doAssert $(1,) == "(1,)" # just for comparison to make sure it has same structure
  45. doAssert $tuple[] == "tuple[]"
  46. doAssert $(int,) == "(int,)"
  47. doAssert $(int, float) == "(int, float)"
  48. doAssert $((int), tuple[], tuple[a: uint], tuple[a: uint, b: float], (int,), (int, float)) ==
  49. "(int, tuple[], tuple[a: uint], tuple[a: uint, b: float], (int,), (int, float))"
  50. block: # typeToString
  51. type MyInt = int
  52. type
  53. C[T0, T1] = object
  54. type C2=C # alias => will resolve as C
  55. type C2b=C # alias => will resolve as C (recursively)
  56. type C3[U,V] = C[V,U]
  57. type C4[X] = C[X,X]
  58. template name2(T): string = typeToString(T, "preferResolved")
  59. doAssert MyInt.name2 == "int"
  60. doAssert C3[MyInt, C2b].name2 == "C3[int, C]"
  61. # C3 doesn't get resolved to C, not an alias (nor does C4)
  62. doAssert C2b[MyInt, C4[cstring]].name2 == "C[int, C4[cstring]]"
  63. doAssert C4[MyInt].name2 == "C4[int]"
  64. when BiggestFloat is float and cint is int:
  65. doAssert C2b[cint, BiggestFloat].name2 == "C3[int, C3[float, int32]]"
  66. template name3(T): string = typeToString(T, "preferMixed")
  67. doAssert MyInt.name3 == "MyInt{int}"
  68. doAssert (tuple[a: MyInt, b: float]).name3 == "tuple[a: MyInt{int}, b: float]"
  69. doAssert (tuple[a: C2b[MyInt, C4[cstring]], b: cint, c: float]).name3 ==
  70. "tuple[a: C[MyInt{int}, C4[cstring]], b: cint{int32}, c: float]"
  71. macro fn(): string =
  72. # not 100% sure whether this should even compile; if some PR breaks this test,
  73. # this could be revisited, maybe.
  74. newLit $($getType(untyped), $getType(typed))
  75. doAssert fn() == """("untyped", "typed")"""
  76. block distinctBase:
  77. block:
  78. type
  79. Foo[T] = distinct seq[T]
  80. var a: Foo[int]
  81. doAssert a.type.distinctBase is seq[int]
  82. doAssert seq[int].distinctBase is seq[int]
  83. doAssert "abc".distinctBase == "abc"
  84. block:
  85. # simplified from https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458
  86. macro uintImpl(bits: static[int]): untyped =
  87. if bits >= 128:
  88. let inner = getAST(uintImpl(bits div 2))
  89. result = newTree(nnkBracketExpr, ident("UintImpl"), inner)
  90. else:
  91. result = ident("uint64")
  92. type
  93. BaseUint = UintImpl or SomeUnsignedInt
  94. UintImpl[Baseuint] = object
  95. Uint[bits: static[int]] = distinct uintImpl(bits)
  96. doAssert Uint[128].distinctBase is UintImpl[uint64]
  97. block:
  98. type
  99. AA = distinct seq[int]
  100. BB = distinct string
  101. CC = distinct int
  102. AAA = AA
  103. static:
  104. var a2: AAA
  105. var b2: BB
  106. var c2: CC
  107. doAssert(a2 is distinct)
  108. doAssert(b2 is distinct)
  109. doAssert(c2 is distinct)
  110. doAssert($distinctBase(typeof(a2)) == "seq[int]")
  111. doAssert($distinctBase(typeof(b2)) == "string")
  112. doAssert($distinctBase(typeof(c2)) == "int")
  113. block: # tupleLen
  114. doAssert not compiles(tupleLen(int))
  115. type
  116. MyTupleType = (int,float,string)
  117. static: doAssert MyTupleType.tupleLen == 3
  118. type
  119. MyGenericTuple[T] = (T,int,float)
  120. MyGenericAlias = MyGenericTuple[string]
  121. static: doAssert MyGenericAlias.tupleLen == 3
  122. type
  123. MyGenericTuple2[T,U] = (T,U,string)
  124. MyGenericTuple2Alias[T] = MyGenericTuple2[T,int]
  125. MyGenericTuple2Alias2 = MyGenericTuple2Alias[float]
  126. static: doAssert MyGenericTuple2Alias2.tupleLen == 3
  127. static: doAssert (int, float).tupleLen == 2
  128. static: doAssert (1, ).tupleLen == 1
  129. static: doAssert ().tupleLen == 0
  130. let x = (1,2,)
  131. doAssert x.tupleLen == 2
  132. doAssert ().tupleLen == 0
  133. doAssert (1,).tupleLen == 1
  134. doAssert (int,).tupleLen == 1
  135. doAssert type(x).tupleLen == 2
  136. doAssert type(x).default.tupleLen == 2
  137. type T1 = (int,float)
  138. type T2 = T1
  139. doAssert T2.tupleLen == 2
  140. block genericParams:
  141. type Foo[T1, T2]=object
  142. doAssert genericParams(Foo[float, string]) is (float, string)
  143. type Foo1 = Foo[float, int]
  144. doAssert genericParams(Foo1) is (float, int)
  145. type Foo2 = Foo[float, Foo1]
  146. doAssert genericParams(Foo2) is (float, Foo[float, int])
  147. doAssert genericParams(Foo2) is (float, Foo1)
  148. doAssert genericParams(Foo2).get(1) is Foo1
  149. doAssert (int,).get(0) is int
  150. doAssert (int, float).get(1) is float
  151. type Bar[N: static int, T] = object
  152. type Bar3 = Bar[3, float]
  153. doAssert genericParams(Bar3) is (StaticParam[3], float)
  154. doAssert genericParams(Bar3).get(0) is StaticParam
  155. doAssert genericParams(Bar3).get(0).value == 3
  156. doAssert genericParams(Bar[3, float]).get(0).value == 3
  157. static: doAssert genericParams(Bar[3, float]).get(0).value == 3
  158. type
  159. VectorElementType = SomeNumber | bool
  160. Vec[N: static[int], T: VectorElementType] = object
  161. arr: array[N, T]
  162. Vec4[T: VectorElementType] = Vec[4,T]
  163. Vec4f = Vec4[float32]
  164. MyTupleType = (int,float,string)
  165. MyGenericTuple[T] = (T,int,float)
  166. MyGenericAlias = MyGenericTuple[string]
  167. MyGenericTuple2[T,U] = (T,U,string)
  168. MyGenericTuple2Alias[T] = MyGenericTuple2[T,int]
  169. MyGenericTuple2Alias2 = MyGenericTuple2Alias[float]
  170. doAssert genericParams(MyGenericAlias) is (string,)
  171. doAssert genericHead(MyGenericAlias) is MyGenericTuple
  172. doAssert genericParams(MyGenericTuple2Alias2) is (float,)
  173. doAssert genericParams(MyGenericTuple2[float, int]) is (float, int)
  174. doAssert genericParams(MyGenericAlias) is (string,)
  175. doAssert genericParams(Vec4f) is (float32,)
  176. doAssert genericParams(Vec[4, bool]) is (StaticParam[4], bool)
  177. block:
  178. type Foo[T1, T2]=object
  179. doAssert genericParams(Foo[float, string]) is (float, string)
  180. type Bar[N: static float, T] = object
  181. doAssert genericParams(Bar[1.0, string]) is (StaticParam[1.0], string)
  182. type Bar2 = Bar[2.0, string]
  183. doAssert genericParams(Bar2) is (StaticParam[2.0], string)
  184. type Bar3 = Bar[1.0 + 2.0, string]
  185. doAssert genericParams(Bar3) is (StaticParam[3.0], string)
  186. const F = 5.0
  187. type Bar4 = Bar[F, string]
  188. doAssert genericParams(Bar4) is (StaticParam[5.0], string)
  189. doAssert genericParams(Bar[F, string]) is (StaticParam[5.0], string)
  190. block typeof:
  191. var
  192. a: seq[int]
  193. b: array[42, float]
  194. c: array[char, int]
  195. d: array[1..2, char]
  196. doAssert genericParams(typeof(a)).get(0) is int
  197. doAssert genericParams(typeof(b)) is (range[0..41], float)
  198. doAssert genericParams(typeof(c)) is (char, int)
  199. doAssert genericParams(typeof(d)) is (range[1..2], char)
  200. block nestedContainers:
  201. doAssert genericParams(seq[Foo[string, float]]).get(0) is Foo[string, float]
  202. doAssert genericParams(array[10, Foo[Bar[1, int], Bar[2, float]]]) is (StaticParam[10], Foo[Bar[1, int], Bar[2, float]])
  203. doAssert genericParams(array[1..9, int]) is (range[1..9], int)
  204. ##############################################
  205. # bug 13095
  206. type
  207. CpuStorage[T] {.shallow.} = ref object
  208. when supportsCopyMem(T):
  209. raw_buffer*: ptr UncheckedArray[T] # 8 bytes
  210. memalloc*: pointer # 8 bytes
  211. isMemOwner*: bool # 1 byte
  212. else: # Tensors of strings, other ref types or non-trivial destructors
  213. raw_buffer*: seq[T] # 8 bytes (16 for seq v2 backed by destructors?)
  214. var x = CpuStorage[string]()
  215. static:
  216. doAssert(not string.supportsCopyMem)
  217. doAssert x.T is string # true
  218. doAssert x.raw_buffer is seq
  219. block genericHead:
  220. type Foo[T1,T2] = object
  221. x1: T1
  222. x2: T2
  223. type FooInst = Foo[int, float]
  224. type Foo2 = genericHead(FooInst)
  225. doAssert Foo2 is Foo # issue #13066
  226. block:
  227. type Goo[T] = object
  228. type Moo[U] = object
  229. type Hoo = Goo[Moo[float]]
  230. type Koo = genericHead(Hoo)
  231. doAssert Koo is Goo
  232. doAssert genericParams(Hoo) is (Moo[float],)
  233. doAssert genericParams(Hoo).get(0) is Moo[float]
  234. doAssert genericHead(genericParams(Hoo).get(0)) is Moo
  235. type Foo2Inst = Foo2[int, float]
  236. doAssert FooInst.default == Foo2Inst.default
  237. doAssert FooInst.default.x2 == 0.0
  238. doAssert Foo2Inst is FooInst
  239. doAssert FooInst is Foo2Inst
  240. doAssert compiles(genericHead(FooInst))
  241. doAssert not compiles(genericHead(Foo))
  242. type Bar = object
  243. doAssert not compiles(genericHead(Bar))
  244. when false: # xxx not supported yet
  245. doAssert seq[int].genericHead is seq
  246. when false: # xxx not supported yet, gives: Error: identifier expected
  247. type Hoo[T] = object
  248. doAssert genericHead(Hoo[int])[float] is Hoo[float]
  249. block: # elementType
  250. iterator myiter(n: int): auto =
  251. for i in 0..<n: yield i
  252. iterator myiter3(): int = yield 10
  253. iterator myiter2(n: int): auto {.closure.} =
  254. for i in 0..<n: yield i
  255. doAssert elementType(@[1,2]) is int
  256. doAssert elementType("asdf") is char
  257. doAssert elementType(myiter(3)) is int
  258. doAssert elementType(myiter2(3)) is int
  259. doAssert elementType([1.1]) is float
  260. doAssert compiles elementType([1])
  261. doAssert not compiles elementType(1)
  262. doAssert compiles elementType(myiter3())
  263. doAssert not compiles elementType(myiter3)
  264. # check that it also works for 0-sized seq:
  265. var a: seq[int]
  266. doAssert elementType(a) is int
  267. doAssert elementType(seq[char].default) is char
  268. block: # enum.len
  269. type
  270. Direction = enum
  271. north, east, south, west
  272. Direction2 = Direction
  273. Direction3 = Direction2
  274. TokenType = enum
  275. a = 2, b = 4, c = 89
  276. MyEnum = enum
  277. ##[This is test of enum with a doc comment.
  278. Which is also a multi line one.]##
  279. valueA = (0, "my value A"),
  280. ## The items are also commented. This has both integer and string
  281. ## values.
  282. valueB = "value B",
  283. ## This item has only a string value,
  284. valueC = 2,
  285. ## and this one only an integer.
  286. valueD = (3, "abc")
  287. ## Both, integer and string values again.
  288. OtherEnum {.pure.} = enum
  289. valueX, valueY, valueZ
  290. MyFlag {.size: sizeof(cint).} = enum
  291. A, B, C, D
  292. static:
  293. doAssert Direction.enumLen == 4
  294. doAssert Direction2.enumLen == 4
  295. doAssert Direction3.enumLen == 4
  296. doAssert TokenType.enumLen == 3
  297. doAssert MyEnum.enumLen == 4
  298. doAssert OtherEnum.enumLen == 3
  299. doAssert MyFlag.enumLen == 4