ttypetraits.nim 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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. block:
  83. # simplified from https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458
  84. macro uintImpl(bits: static[int]): untyped =
  85. if bits >= 128:
  86. let inner = getAST(uintImpl(bits div 2))
  87. result = newTree(nnkBracketExpr, ident("UintImpl"), inner)
  88. else:
  89. result = ident("uint64")
  90. type
  91. BaseUint = UintImpl or SomeUnsignedInt
  92. UintImpl[Baseuint] = object
  93. Uint[bits: static[int]] = distinct uintImpl(bits)
  94. doAssert Uint[128].distinctBase is UintImpl[uint64]
  95. block:
  96. type
  97. AA = distinct seq[int]
  98. BB = distinct string
  99. CC = distinct int
  100. AAA = AA
  101. static:
  102. var a2: AAA
  103. var b2: BB
  104. var c2: CC
  105. doAssert(a2 is distinct)
  106. doAssert(b2 is distinct)
  107. doAssert(c2 is distinct)
  108. doAssert($distinctBase(typeof(a2)) == "seq[int]")
  109. doAssert($distinctBase(typeof(b2)) == "string")
  110. doAssert($distinctBase(typeof(c2)) == "int")
  111. block: # tupleLen
  112. doAssert not compiles(tupleLen(int))
  113. type
  114. MyTupleType = (int,float,string)
  115. static: doAssert MyTupleType.tupleLen == 3
  116. type
  117. MyGenericTuple[T] = (T,int,float)
  118. MyGenericAlias = MyGenericTuple[string]
  119. static: doAssert MyGenericAlias.tupleLen == 3
  120. type
  121. MyGenericTuple2[T,U] = (T,U,string)
  122. MyGenericTuple2Alias[T] = MyGenericTuple2[T,int]
  123. MyGenericTuple2Alias2 = MyGenericTuple2Alias[float]
  124. static: doAssert MyGenericTuple2Alias2.tupleLen == 3
  125. static: doAssert (int, float).tupleLen == 2
  126. static: doAssert (1, ).tupleLen == 1
  127. static: doAssert ().tupleLen == 0
  128. let x = (1,2,)
  129. doAssert x.tupleLen == 2
  130. doAssert ().tupleLen == 0
  131. doAssert (1,).tupleLen == 1
  132. doAssert (int,).tupleLen == 1
  133. doAssert type(x).tupleLen == 2
  134. doAssert type(x).default.tupleLen == 2
  135. type T1 = (int,float)
  136. type T2 = T1
  137. doAssert T2.tupleLen == 2
  138. block genericParams:
  139. type Foo[T1, T2]=object
  140. doAssert genericParams(Foo[float, string]) is (float, string)
  141. type Foo1 = Foo[float, int]
  142. doAssert genericParams(Foo1) is (float, int)
  143. type Foo2 = Foo[float, Foo1]
  144. doAssert genericParams(Foo2) is (float, Foo[float, int])
  145. doAssert genericParams(Foo2) is (float, Foo1)
  146. doAssert genericParams(Foo2).get(1) is Foo1
  147. doAssert (int,).get(0) is int
  148. doAssert (int, float).get(1) is float
  149. type Bar[N: static int, T] = object
  150. type Bar3 = Bar[3, float]
  151. doAssert genericParams(Bar3) is (StaticParam[3], float)
  152. doAssert genericParams(Bar3).get(0) is StaticParam
  153. doAssert genericParams(Bar3).get(0).value == 3
  154. doAssert genericParams(Bar[3, float]).get(0).value == 3
  155. static: doAssert genericParams(Bar[3, float]).get(0).value == 3
  156. type
  157. VectorElementType = SomeNumber | bool
  158. Vec[N: static[int], T: VectorElementType] = object
  159. arr: array[N, T]
  160. Vec4[T: VectorElementType] = Vec[4,T]
  161. Vec4f = Vec4[float32]
  162. MyTupleType = (int,float,string)
  163. MyGenericTuple[T] = (T,int,float)
  164. MyGenericAlias = MyGenericTuple[string]
  165. MyGenericTuple2[T,U] = (T,U,string)
  166. MyGenericTuple2Alias[T] = MyGenericTuple2[T,int]
  167. MyGenericTuple2Alias2 = MyGenericTuple2Alias[float]
  168. doAssert genericParams(MyGenericAlias) is (string,)
  169. doAssert genericHead(MyGenericAlias) is MyGenericTuple
  170. doAssert genericParams(MyGenericTuple2Alias2) is (float,)
  171. doAssert genericParams(MyGenericTuple2[float, int]) is (float, int)
  172. doAssert genericParams(MyGenericAlias) is (string,)
  173. doAssert genericParams(Vec4f) is (float32,)
  174. doAssert genericParams(Vec[4, bool]) is (StaticParam[4], bool)
  175. block:
  176. type Foo[T1, T2]=object
  177. doAssert genericParams(Foo[float, string]) is (float, string)
  178. type Bar[N: static float, T] = object
  179. doAssert genericParams(Bar[1.0, string]) is (StaticParam[1.0], string)
  180. type Bar2 = Bar[2.0, string]
  181. doAssert genericParams(Bar2) is (StaticParam[2.0], string)
  182. type Bar3 = Bar[1.0 + 2.0, string]
  183. doAssert genericParams(Bar3) is (StaticParam[3.0], string)
  184. const F = 5.0
  185. type Bar4 = Bar[F, string]
  186. doAssert genericParams(Bar4) is (StaticParam[5.0], string)
  187. doAssert genericParams(Bar[F, string]) is (StaticParam[5.0], string)
  188. block typeof:
  189. var
  190. a: seq[int]
  191. b: array[42, float]
  192. c: array[char, int]
  193. d: array[1..2, char]
  194. doAssert genericParams(typeof(a)).get(0) is int
  195. doAssert genericParams(typeof(b)) is (range[0..41], float)
  196. doAssert genericParams(typeof(c)) is (char, int)
  197. doAssert genericParams(typeof(d)) is (range[1..2], char)
  198. block nestedContainers:
  199. doAssert genericParams(seq[Foo[string, float]]).get(0) is Foo[string, float]
  200. doAssert genericParams(array[10, Foo[Bar[1, int], Bar[2, float]]]) is (StaticParam[10], Foo[Bar[1, int], Bar[2, float]])
  201. doAssert genericParams(array[1..9, int]) is (range[1..9], int)
  202. ##############################################
  203. # bug 13095
  204. type
  205. CpuStorage[T] {.shallow.} = ref object
  206. when supportsCopyMem(T):
  207. raw_buffer*: ptr UncheckedArray[T] # 8 bytes
  208. memalloc*: pointer # 8 bytes
  209. isMemOwner*: bool # 1 byte
  210. else: # Tensors of strings, other ref types or non-trivial destructors
  211. raw_buffer*: seq[T] # 8 bytes (16 for seq v2 backed by destructors?)
  212. var x = CpuStorage[string]()
  213. static:
  214. doAssert(not string.supportsCopyMem)
  215. doAssert x.T is string # true
  216. doAssert x.raw_buffer is seq
  217. block genericHead:
  218. type Foo[T1,T2] = object
  219. x1: T1
  220. x2: T2
  221. type FooInst = Foo[int, float]
  222. type Foo2 = genericHead(FooInst)
  223. doAssert Foo2 is Foo # issue #13066
  224. block:
  225. type Goo[T] = object
  226. type Moo[U] = object
  227. type Hoo = Goo[Moo[float]]
  228. type Koo = genericHead(Hoo)
  229. doAssert Koo is Goo
  230. doAssert genericParams(Hoo) is (Moo[float],)
  231. doAssert genericParams(Hoo).get(0) is Moo[float]
  232. doAssert genericHead(genericParams(Hoo).get(0)) is Moo
  233. type Foo2Inst = Foo2[int, float]
  234. doAssert FooInst.default == Foo2Inst.default
  235. doAssert FooInst.default.x2 == 0.0
  236. doAssert Foo2Inst is FooInst
  237. doAssert FooInst is Foo2Inst
  238. doAssert compiles(genericHead(FooInst))
  239. doAssert not compiles(genericHead(Foo))
  240. type Bar = object
  241. doAssert not compiles(genericHead(Bar))
  242. # doAssert seq[int].genericHead is seq
  243. block: # elementType
  244. iterator myiter(n: int): auto =
  245. for i in 0..<n: yield i
  246. iterator myiter3(): int = yield 10
  247. iterator myiter2(n: int): auto {.closure.} =
  248. for i in 0..<n: yield i
  249. doAssert elementType(@[1,2]) is int
  250. doAssert elementType("asdf") is char
  251. doAssert elementType(myiter(3)) is int
  252. doAssert elementType(myiter2(3)) is int
  253. doAssert elementType([1.1]) is float
  254. doAssert compiles elementType([1])
  255. doAssert not compiles elementType(1)
  256. doAssert compiles elementType(myiter3())
  257. doAssert not compiles elementType(myiter3)
  258. # check that it also works for 0-sized seq:
  259. var a: seq[int]
  260. doAssert elementType(a) is int
  261. doAssert elementType(seq[char].default) is char
  262. block: # enum.len
  263. type
  264. Direction = enum
  265. north, east, south, west
  266. Direction2 = Direction
  267. Direction3 = Direction2
  268. TokenType = enum
  269. a = 2, b = 4, c = 89
  270. MyEnum = enum
  271. ##[This is test of enum with a doc comment.
  272. Which is also a multi line one.]##
  273. valueA = (0, "my value A"),
  274. ## The items are also commented. This has both integer and string
  275. ## values.
  276. valueB = "value B",
  277. ## This item has only a string value,
  278. valueC = 2,
  279. ## and this one only an integer.
  280. valueD = (3, "abc")
  281. ## Both, integer and string values again.
  282. OtherEnum {.pure.} = enum
  283. valueX, valueY, valueZ
  284. MyFlag {.size: sizeof(cint).} = enum
  285. A, B, C, D
  286. static:
  287. doAssert Direction.enumLen == 4
  288. doAssert Direction2.enumLen == 4
  289. doAssert Direction3.enumLen == 4
  290. doAssert TokenType.enumLen == 3
  291. doAssert MyEnum.enumLen == 4
  292. doAssert OtherEnum.enumLen == 3
  293. doAssert MyFlag.enumLen == 4