ttypetraits.nim 13 KB

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