ttypetraits.nim 12 KB

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