ttypetraits.nim 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  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: # rangeBase
  128. {.push warningAsError[EnumConv]: on.}
  129. proc foo[T: not range](x: T): string =
  130. $T & "(" & $x & ")"
  131. proc foo[T: range](x: T): string =
  132. "ranged(" & $low(T) & ".." & $high(T) & " of " & $rangeBase(T) & ") " & foo(rangeBase(x))
  133. doAssert foo(123) == "int(123)"
  134. type IntRange = range[0..3]
  135. let x: IntRange = 2
  136. doAssert foo(x) == "ranged(0..3 of int) int(2)"
  137. type E = enum a, b, c, d, e, f
  138. type EnumRange = range[c..e]
  139. let y: EnumRange = d
  140. doAssert foo(y) == "ranged(c..e of E) E(d)"
  141. let z: range['a'..'z'] = 'g'
  142. doAssert foo(z) == "ranged(a..z of char) char(g)"
  143. {.pop.}
  144. # works only with #24037:
  145. var toChange: range[0..3] = 1
  146. proc bar[T: int and not range](y: var T) =
  147. inc y
  148. doAssert not compiles(bar(toChange))
  149. bar(rangeBase(toChange))
  150. doAssert toChange == 2
  151. block: # tupleLen
  152. doAssert not compiles(tupleLen(int))
  153. type
  154. MyTupleType = (int,float,string)
  155. static: doAssert MyTupleType.tupleLen == 3
  156. type
  157. MyGenericTuple[T] = (T,int,float)
  158. MyGenericAlias = MyGenericTuple[string]
  159. static: doAssert MyGenericAlias.tupleLen == 3
  160. type
  161. MyGenericTuple2[T,U] = (T,U,string)
  162. MyGenericTuple2Alias[T] = MyGenericTuple2[T,int]
  163. MyGenericTuple2Alias2 = MyGenericTuple2Alias[float]
  164. static: doAssert MyGenericTuple2Alias2.tupleLen == 3
  165. static: doAssert (int, float).tupleLen == 2
  166. static: doAssert (1, ).tupleLen == 1
  167. static: doAssert ().tupleLen == 0
  168. let x = (1,2,)
  169. doAssert x.tupleLen == 2
  170. doAssert ().tupleLen == 0
  171. doAssert (1,).tupleLen == 1
  172. doAssert (int,).tupleLen == 1
  173. doAssert type(x).tupleLen == 2
  174. doAssert type(x).default.tupleLen == 2
  175. type T1 = (int,float)
  176. type T2 = T1
  177. doAssert T2.tupleLen == 2
  178. block genericParams:
  179. type Foo[T1, T2]=object
  180. doAssert genericParams(Foo[float, string]) is (float, string)
  181. type Foo1 = Foo[float, int]
  182. doAssert genericParams(Foo1) is (float, int)
  183. type Foo2 = Foo[float, Foo1]
  184. doAssert genericParams(Foo2) is (float, Foo[float, int])
  185. doAssert genericParams(Foo2) is (float, Foo1)
  186. doAssert genericParams(Foo2).get(1) is Foo1
  187. doAssert (int,).get(0) is int
  188. doAssert (int, float).get(1) is float
  189. type Bar[N: static int, T] = object
  190. type Bar3 = Bar[3, float]
  191. doAssert genericParams(Bar3) is (StaticParam[3], float)
  192. doAssert genericParams(Bar3).get(0) is StaticParam
  193. doAssert genericParams(Bar3).get(0).value == 3
  194. doAssert genericParams(Bar[3, float]).get(0).value == 3
  195. static: doAssert genericParams(Bar[3, float]).get(0).value == 3
  196. type
  197. VectorElementType = SomeNumber | bool
  198. Vec[N: static[int], T: VectorElementType] = object
  199. arr: array[N, T]
  200. Vec4[T: VectorElementType] = Vec[4,T]
  201. Vec4f = Vec4[float32]
  202. MyTupleType = (int,float,string)
  203. MyGenericTuple[T] = (T,int,float)
  204. MyGenericAlias = MyGenericTuple[string]
  205. MyGenericTuple2[T,U] = (T,U,string)
  206. MyGenericTuple2Alias[T] = MyGenericTuple2[T,int]
  207. MyGenericTuple2Alias2 = MyGenericTuple2Alias[float]
  208. doAssert genericParams(MyGenericAlias) is (string,)
  209. doAssert genericHead(MyGenericAlias) is MyGenericTuple
  210. doAssert genericParams(MyGenericTuple2Alias2) is (float,)
  211. doAssert genericParams(MyGenericTuple2[float, int]) is (float, int)
  212. doAssert genericParams(MyGenericAlias) is (string,)
  213. doAssert genericParams(Vec4f) is (float32,)
  214. doAssert genericParams(Vec[4, bool]) is (StaticParam[4], bool)
  215. block:
  216. type Foo[T1, T2]=object
  217. doAssert genericParams(Foo[float, string]) is (float, string)
  218. type Bar[N: static float, T] = object
  219. doAssert genericParams(Bar[1.0, string]) is (StaticParam[1.0], string)
  220. type Bar2 = Bar[2.0, string]
  221. doAssert genericParams(Bar2) is (StaticParam[2.0], string)
  222. type Bar3 = Bar[1.0 + 2.0, string]
  223. doAssert genericParams(Bar3) is (StaticParam[3.0], string)
  224. const F = 5.0
  225. type Bar4 = Bar[F, string]
  226. doAssert genericParams(Bar4) is (StaticParam[5.0], string)
  227. doAssert genericParams(Bar[F, string]) is (StaticParam[5.0], string)
  228. block typeof:
  229. var
  230. a: seq[int]
  231. b: array[42, float]
  232. c: array[char, int]
  233. d: array[1..2, char]
  234. doAssert genericParams(typeof(a)).get(0) is int
  235. doAssert genericParams(typeof(b)) is (range[0..41], float)
  236. doAssert genericParams(typeof(c)) is (char, int)
  237. doAssert genericParams(typeof(d)) is (range[1..2], char)
  238. block nestedContainers:
  239. doAssert genericParams(seq[Foo[string, float]]).get(0) is Foo[string, float]
  240. doAssert genericParams(array[10, Foo[Bar[1, int], Bar[2, float]]]) is (StaticParam[10], Foo[Bar[1, int], Bar[2, float]])
  241. doAssert genericParams(array[1..9, int]) is (range[1..9], int)
  242. ##############################################
  243. # bug 13095
  244. type
  245. CpuStorage[T] {.shallow.} = ref object
  246. when supportsCopyMem(T):
  247. raw_buffer*: ptr UncheckedArray[T] # 8 bytes
  248. memalloc*: pointer # 8 bytes
  249. isMemOwner*: bool # 1 byte
  250. else: # Tensors of strings, other ref types or non-trivial destructors
  251. raw_buffer*: seq[T] # 8 bytes (16 for seq v2 backed by destructors?)
  252. var x = CpuStorage[string]()
  253. static:
  254. doAssert(not string.supportsCopyMem)
  255. doAssert x.T is string # true
  256. doAssert x.raw_buffer is seq
  257. block genericHead:
  258. type Foo[T1,T2] = object
  259. x1: T1
  260. x2: T2
  261. type FooInst = Foo[int, float]
  262. type Foo2 = genericHead(FooInst)
  263. doAssert Foo2 is Foo # issue #13066
  264. block:
  265. type Goo[T] = object
  266. type Moo[U] = object
  267. type Hoo = Goo[Moo[float]]
  268. type Koo = genericHead(Hoo)
  269. doAssert Koo is Goo
  270. doAssert genericParams(Hoo) is (Moo[float],)
  271. doAssert genericParams(Hoo).get(0) is Moo[float]
  272. doAssert genericHead(genericParams(Hoo).get(0)) is Moo
  273. type Foo2Inst = Foo2[int, float]
  274. doAssert FooInst.default == Foo2Inst.default
  275. doAssert FooInst.default.x2 == 0.0
  276. doAssert Foo2Inst is FooInst
  277. doAssert FooInst is Foo2Inst
  278. doAssert compiles(genericHead(FooInst))
  279. doAssert not compiles(genericHead(Foo))
  280. type Bar = object
  281. doAssert not compiles(genericHead(Bar))
  282. when false: # xxx not supported yet
  283. doAssert seq[int].genericHead is seq
  284. when false: # xxx not supported yet, gives: Error: identifier expected
  285. type Hoo[T] = object
  286. doAssert genericHead(Hoo[int])[float] is Hoo[float]
  287. block: # elementType
  288. iterator myiter(n: int): auto =
  289. for i in 0..<n: yield i
  290. iterator myiter3(): int = yield 10
  291. iterator myiter2(n: int): auto {.closure.} =
  292. for i in 0..<n: yield i
  293. doAssert elementType(@[1,2]) is int
  294. doAssert elementType("asdf") is char
  295. doAssert elementType(myiter(3)) is int
  296. doAssert elementType(myiter2(3)) is int
  297. doAssert elementType([1.1]) is float
  298. doAssert compiles elementType([1])
  299. doAssert not compiles elementType(1)
  300. doAssert compiles elementType(myiter3())
  301. doAssert not compiles elementType(myiter3)
  302. # check that it also works for 0-sized seq:
  303. var a: seq[int]
  304. doAssert elementType(a) is int
  305. doAssert elementType(seq[char].default) is char
  306. block: # enum.len
  307. type
  308. Direction = enum
  309. north, east, south, west
  310. Direction2 = Direction
  311. Direction3 = Direction2
  312. TokenType = enum
  313. a = 2, b = 4, c = 89
  314. MyEnum = enum
  315. ##[This is test of enum with a doc comment.
  316. Which is also a multi line one.]##
  317. valueA = (0, "my value A"),
  318. ## The items are also commented. This has both integer and string
  319. ## values.
  320. valueB = "value B",
  321. ## This item has only a string value,
  322. valueC = 2,
  323. ## and this one only an integer.
  324. valueD = (3, "abc")
  325. ## Both, integer and string values again.
  326. OtherEnum {.pure.} = enum
  327. valueX, valueY, valueZ
  328. MyFlag {.size: sizeof(cint).} = enum
  329. A, B, C, D
  330. static:
  331. doAssert Direction.enumLen == 4
  332. doAssert Direction2.enumLen == 4
  333. doAssert Direction3.enumLen == 4
  334. doAssert TokenType.enumLen == 3
  335. doAssert MyEnum.enumLen == 4
  336. doAssert OtherEnum.enumLen == 3
  337. doAssert MyFlag.enumLen == 4
  338. when true: # Odd bug where alias can seep inside of `distinctBase`
  339. import std/unittest
  340. type
  341. AdtChild* = concept t
  342. distinctBase(t)
  343. proc `$`*[T: AdtChild](adtChild: T): string = ""
  344. check 10 is int