tconcepts_issues.nim 11 KB

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