tconcepts_issues.nim 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. discard """
  2. output: '''
  3. 20.0 USD
  4. true
  5. true
  6. true
  7. true
  8. true
  9. f
  10. 0
  11. 10
  12. 10
  13. 5
  14. ()
  15. false
  16. 10
  17. true
  18. true
  19. true
  20. true
  21. p has been called.
  22. p has been called.
  23. implicit generic
  24. generic
  25. false
  26. true
  27. -1
  28. Meow
  29. 10 0.0
  30. 1 2.0
  31. '''
  32. joinable: false
  33. """
  34. import macros, typetraits, os, posix
  35. block t5983:
  36. const currencies = ["USD", "EUR"] # in real code 120 currencies
  37. type USD = distinct float # in real code 120 types generates using macro
  38. type EUR = distinct float
  39. type CurrencyAmount = concept c
  40. type t = c.type
  41. const name = c.type.name
  42. name in currencies
  43. proc `$`(x: CurrencyAmount): string =
  44. $float(x) & " " & x.name
  45. let amount = 20.USD
  46. echo amount
  47. block t3414:
  48. type
  49. View[T] = concept v
  50. v.empty is bool
  51. v.front is T
  52. popFront v
  53. proc find(view: View; target: View.T): View =
  54. result = view
  55. while not result.empty:
  56. if view.front == target:
  57. return
  58. mixin popFront
  59. popFront result
  60. proc popFront[T](s: var seq[T]) = discard
  61. proc empty[T](s: seq[T]): bool = false
  62. var s1 = @[1, 2, 3]
  63. let s2 = s1.find(10)
  64. block t1128:
  65. type
  66. TFooContainer[T] = object
  67. TContainer[T] = concept var c
  68. foo(c, T)
  69. proc foo[T](c: var TFooContainer[T], val: T) =
  70. discard
  71. proc bar(c: var TContainer) =
  72. discard
  73. var fooContainer: TFooContainer[int]
  74. echo fooContainer is TFooContainer # true.
  75. echo fooContainer is TFooContainer[int] # true.
  76. fooContainer.bar()
  77. block t5642:
  78. type DataTable = concept x
  79. x is object
  80. for f in fields(x):
  81. f is seq
  82. type Students = object
  83. id : seq[int]
  84. name : seq[string]
  85. age: seq[int]
  86. proc nrow(dt: DataTable) : Natural =
  87. var totalLen = 0
  88. for f in fields(dt):
  89. totalLen += f.len
  90. return totalLen
  91. let
  92. stud = Students(id: @[1,2,3], name: @["Vas", "Pas", "NafNaf"], age: @[10,16,32])
  93. doAssert nrow(stud) == 9
  94. import t5888lib/ca, t5888lib/opt
  95. block t5888:
  96. type LocalCA = ca.CA
  97. proc f(c: CA) =
  98. echo "f"
  99. echo c.x
  100. var o = new(Opt)
  101. echo o is CA
  102. echo o is LocalCA
  103. echo o is ca.CA
  104. o.f()
  105. import json
  106. block t5968:
  107. type
  108. Enumerable[T] = concept e
  109. for it in e:
  110. it is T
  111. proc cmap[T, G](e: Enumerable[T], fn: proc(t: T): G): seq[G] =
  112. result = @[]
  113. for it in e: result.add(fn(it))
  114. var x = %["hello", "world"]
  115. var z = x.cmap(proc(it: JsonNode): string = it.getStr & "!")
  116. assert z == @["hello!", "world!"]
  117. import sugar
  118. block t6462:
  119. type
  120. FilterMixin[T] = ref object
  121. test: (T) -> bool
  122. trans: (T) -> T
  123. SeqGen[T] = ref object
  124. fil: FilterMixin[T]
  125. WithFilter[T] = concept a
  126. a.fil is FilterMixin[T]
  127. proc test[T](a: WithFilter[T]): (T) -> bool =
  128. a.fil.test
  129. var s = SeqGen[int](fil: FilterMixin[int](test: nil, trans: nil))
  130. doAssert s.test() == nil
  131. block t6770:
  132. type GA = concept c
  133. c.a is int
  134. type A = object
  135. a: int
  136. type AA = object
  137. case exists: bool
  138. of true:
  139. a: int
  140. else:
  141. discard
  142. proc print(inp: GA) =
  143. echo inp.a
  144. let failing = AA(exists: true, a: 10)
  145. let working = A(a:10)
  146. print(working)
  147. print(failing)
  148. block t7952:
  149. type
  150. HasLen = concept iter
  151. len(iter) is int
  152. proc echoLen(x: HasLen) =
  153. echo len(x)
  154. echoLen([1, 2, 3, 4, 5])
  155. block t8280:
  156. type
  157. Iterable[T] = concept x
  158. for elem in x:
  159. elem is T
  160. proc max[A](iter: Iterable[A]): A =
  161. discard
  162. type
  163. MyType = object
  164. echo max(@[MyType()])
  165. import math
  166. block t3452:
  167. type
  168. Node = concept n
  169. `==`(n, n) is bool
  170. Graph1 = concept g
  171. type N = Node
  172. distance(g, N, N) is float
  173. Graph2 = concept g
  174. distance(g, Node, Node) is float
  175. Graph3 = concept g
  176. var x: Node
  177. distance(g, x, x) is float
  178. XY = tuple[x, y: int]
  179. MyGraph = object
  180. points: seq[XY]
  181. static:
  182. assert XY is Node
  183. proc distance( g: MyGraph, a, b: XY): float =
  184. sqrt( pow(float(a.x - b.x), 2) + pow(float(a.y - b.y), 2) )
  185. static:
  186. assert MyGraph is Graph1
  187. assert MyGraph is Graph2
  188. assert MyGraph is Graph3
  189. block t6691:
  190. type
  191. ConceptA = concept c
  192. ConceptB = concept c
  193. c.myProc(ConceptA)
  194. Obj = object
  195. proc myProc(obj: Obj, x: ConceptA) = discard
  196. echo Obj is ConceptB
  197. block t6782:
  198. type
  199. Reader = concept c
  200. c.read(openArray[byte], int, int) is int
  201. Rdr = concept c
  202. c.rd(openArray[byte], int, int) is int
  203. type TestFile = object
  204. proc read(r: TestFile, dest: openArray[byte], offset: int, limit: int): int =
  205. result = 0
  206. proc rd(r: TestFile, dest: openArray[byte], offset: int, limit: int): int =
  207. result = 0
  208. doAssert TestFile is Reader
  209. doAssert TestFile is Rdr
  210. block t7114:
  211. type
  212. MyConcept = concept x
  213. x.close() # error, doesn't work
  214. MyConceptImplementer = object
  215. proc close(self: MyConceptImplementer) = discard
  216. proc takeConcept(window: MyConcept) =
  217. discard
  218. takeConcept(MyConceptImplementer())
  219. block t7510:
  220. type
  221. A[T] = concept a
  222. a.x is T
  223. B[T] = object
  224. x: T
  225. proc getx(v: A): v.T = v.x
  226. var v = B[int32](x: 10)
  227. echo v.getx
  228. block misc_issues:
  229. # https://github.com/nim-lang/Nim/issues/1147
  230. type TTest = object
  231. vals: seq[int]
  232. proc add(self: var TTest, val: int) =
  233. self.vals.add(val)
  234. type CAddable = concept x
  235. x[].add(int)
  236. echo((ref TTest) is CAddable) # true
  237. # https://github.com/nim-lang/Nim/issues/1570
  238. type ConcretePointOfFloat = object
  239. x, y: float
  240. type ConcretePoint[Value] = object
  241. x, y: Value
  242. type AbstractPointOfFloat = concept p
  243. p.x is float and p.y is float
  244. let p1 = ConcretePointOfFloat(x: 0, y: 0)
  245. let p2 = ConcretePoint[float](x: 0, y: 0)
  246. echo p1 is AbstractPointOfFloat # true
  247. echo p2 is AbstractPointOfFloat # true
  248. echo p2.x is float and p2.y is float # true
  249. # https://github.com/nim-lang/Nim/issues/2018
  250. type ProtocolFollower = concept c
  251. true # not a particularly involved protocol
  252. type ImplementorA = object
  253. type ImplementorB = object
  254. proc p[A: ProtocolFollower, B: ProtocolFollower](a: A, b: B) =
  255. echo "p has been called."
  256. p(ImplementorA(), ImplementorA())
  257. p(ImplementorA(), ImplementorB())
  258. # https://github.com/nim-lang/Nim/issues/2423
  259. proc put[T](c: seq[T], x: T) = echo "generic"
  260. proc put(c: seq) = echo "implicit generic"
  261. type
  262. Container[T] = concept c
  263. put(c)
  264. put(c, T)
  265. proc c1(x: Container) = echo "implicit generic"
  266. c1(@[1])
  267. proc c2[T](x: Container[T]) = echo "generic"
  268. c2(@[1])
  269. # https://github.com/nim-lang/Nim/issues/2882
  270. type
  271. Paper = object
  272. name: string
  273. Bendable = concept x
  274. bend(x is Bendable)
  275. proc bend(p: Paper): Paper = Paper(name: "bent-" & p.name)
  276. var paper = Paper(name: "red")
  277. echo paper is Bendable
  278. type
  279. A = concept self
  280. size(self) is int
  281. B = object
  282. proc size(self: B): int =
  283. return -1
  284. proc size(self: A): int =
  285. return 0
  286. let b = B()
  287. echo b is A
  288. echo b.size()
  289. # https://github.com/nim-lang/Nim/issues/7125
  290. type
  291. Thing = concept x
  292. x.hello is string
  293. Cat = object
  294. proc hello(d: Cat): string = "Meow"
  295. proc sayHello(c: Thing) = echo(c.hello)
  296. # used to be 'var a: Thing = Cat()' but that's not valid Nim code
  297. # anyway and will be an error soon.
  298. var a: Cat = Cat()
  299. a.sayHello()
  300. # bug #16897
  301. type
  302. Fp[N: static int, T] = object
  303. big: array[N, T]
  304. type
  305. QuadraticExt* = concept x
  306. ## Quadratic Extension concept (like complex)
  307. type BaseField = auto
  308. x.c0 is BaseField
  309. x.c1 is BaseField
  310. var address = pointer(nil)
  311. proc prod(r: var QuadraticExt, b: QuadraticExt) =
  312. if address == nil:
  313. address = addr b
  314. prod(r, b)
  315. else:
  316. assert address == addr b
  317. type
  318. Fp2[N: static int, T] {.byref.} = object
  319. c0, c1: Fp[N, T]
  320. # This should be passed by reference,
  321. # but concepts do not respect the 24 bytes rule
  322. # or `byref` pragma.
  323. var r, b: Fp2[6, uint64]
  324. prod(r, b)
  325. block: # bug #21263
  326. type
  327. DateDayFraction = concept # no T, an atom
  328. proc date(a: Self): int
  329. proc fraction(b: Self): float
  330. Date = distinct int
  331. DateDayFractionImpl = object
  332. date : int
  333. fraction : float
  334. proc date(a: Date): int = a.int
  335. proc fraction(a:Date): float = 0.0
  336. proc date(a: DateDayFractionImpl): int = a.date
  337. proc fraction(b: DateDayFractionImpl): float = b.fraction
  338. proc print(a: DateDayFraction) =
  339. echo a.date, " ", a.fraction
  340. print(10.Date) # ok
  341. print(DateDayFractionImpl(date: 1, fraction: 2)) # error
  342. import sets
  343. import deques
  344. type AnyTree[V] = concept t, type T
  345. for v in t.leaves(V):
  346. v is V
  347. type BreadthOrder[V] = ref object
  348. frontier: Deque[V]
  349. visited: HashSet[V]
  350. proc expand[V, T](order: ref BreadthOrder[T], tree: AnyTree[V], node: V, transform: (V) -> (T)) =
  351. for leaf in tree.leaves(node):
  352. if not order.visited.containsOrIncl(transform(leaf)):
  353. order.frontier.addLast(transform(leaf))
  354. proc hasNext[V](order: ref BreadthOrder[V]): bool =
  355. order.frontier.len > 0
  356. proc init[V](_: typedesc[BreadthOrder]): ref BreadthOrder[V] =
  357. result.new()
  358. result[] = BreadthOrder[V](frontier: initDeque[V](), visited: initHashSet[V]())
  359. proc popNext[V](order: ref BreadthOrder[V]): V =
  360. order.frontier.popFirst()
  361. type LevelNode[V] = tuple
  362. depth: uint
  363. node: V
  364. proc depthOf*[V](orderType: typedesc[BreadthOrder], tree: AnyTree[V], root, goal: V): uint =
  365. if root == goal:
  366. return 0
  367. var order = init[LevelNode[V]](orderType)
  368. order.expand(tree, root, (leaf) => (1.uint, leaf))
  369. while order.hasNext():
  370. let depthNode: LevelNode[V] = order.popNext()
  371. if depthNode.node == goal:
  372. return depthNode.depth
  373. order.expand(tree, depthNode.node, (leaf) => (depthNode.depth + 1, leaf))
  374. type CappedStringTree = ref object
  375. symbols: string
  376. cap: Natural
  377. iterator leaves*(t: CappedStringTree, s: string): string =
  378. if s.len < t.cap:
  379. for c in t.symbols:
  380. yield s & c
  381. block: # bug #12852
  382. var tree = CappedStringTree(symbols: "^v><", cap: 5)
  383. doAssert BreadthOrder.depthOf(tree, "", ">>>") == 3
  384. block: #bug #22723
  385. type
  386. Node = concept n, type T
  387. for i in n.children:
  388. i is T
  389. n.parent is T
  390. Nd = ref object
  391. parent: Nd
  392. children: seq[Nd]
  393. proc addChild(parent, child: Node) =
  394. parent.children.add(child)
  395. child.parent = parent
  396. proc foo =
  397. var
  398. a = Nd()
  399. b = Nd()
  400. a.addChild(b)
  401. doAssert a.children.len == 1
  402. foo()