summary refs log tree commit diff stats
path: root/tests/concepts/tconcepts_issues.nim
diff options
context:
space:
mode:
Diffstat (limited to 'tests/concepts/tconcepts_issues.nim')
-rw-r--r--tests/concepts/tconcepts_issues.nim556
1 files changed, 556 insertions, 0 deletions
diff --git a/tests/concepts/tconcepts_issues.nim b/tests/concepts/tconcepts_issues.nim
new file mode 100644
index 000000000..c6d0267c5
--- /dev/null
+++ b/tests/concepts/tconcepts_issues.nim
@@ -0,0 +1,556 @@
+discard """
+  output: '''
+20.0 USD
+true
+true
+true
+true
+true
+f
+0
+10
+10
+5
+()
+false
+10
+true
+true
+true
+true
+p has been called.
+p has been called.
+implicit generic
+generic
+false
+true
+-1
+Meow
+10 0.0
+1 2.0
+'''
+joinable: false
+"""
+
+import macros, typetraits, os, posix
+
+
+block t5983:
+  const currencies = ["USD", "EUR"] # in real code 120 currencies
+
+  type USD = distinct float # in real code 120 types generates using macro
+  type EUR = distinct float
+
+  type CurrencyAmount = concept c
+    type t = c.type
+    const name = c.type.name
+    name in currencies
+
+  proc `$`(x: CurrencyAmount): string =
+    $float(x) & " " & x.name
+
+  let amount = 20.USD
+  echo amount
+
+
+block t3414:
+  type
+    View[T] = concept v
+      v.empty is bool
+      v.front is T
+      popFront v
+
+  proc find(view: View; target: View.T): View =
+    result = view
+
+    while not result.empty:
+      if view.front == target:
+        return
+
+      mixin popFront
+      popFront result
+
+  proc popFront[T](s: var seq[T]) = discard
+  proc empty[T](s: seq[T]): bool = false
+
+  var s1 = @[1, 2, 3]
+  let s2 = s1.find(10)
+
+
+block t1128:
+  type
+    TFooContainer[T] = object
+
+    TContainer[T] = concept var c
+      foo(c, T)
+
+  proc foo[T](c: var TFooContainer[T], val: T) =
+    discard
+
+  proc bar(c: var TContainer) =
+    discard
+
+  var fooContainer: TFooContainer[int]
+  echo fooContainer is TFooContainer # true.
+  echo fooContainer is TFooContainer[int] # true.
+  fooContainer.bar()
+
+
+
+block t5642:
+  type DataTable = concept x
+    x is object
+    for f in fields(x):
+      f is seq
+
+  type Students = object
+    id : seq[int]
+    name : seq[string]
+    age: seq[int]
+
+  proc nrow(dt: DataTable) : Natural =
+    var totalLen = 0
+    for f in fields(dt):
+      totalLen += f.len
+    return totalLen
+
+  let
+    stud = Students(id: @[1,2,3], name: @["Vas", "Pas", "NafNaf"], age: @[10,16,32])
+
+  doAssert nrow(stud) == 9
+
+
+
+import t5888lib/ca, t5888lib/opt
+block t5888:
+  type LocalCA = ca.CA
+
+  proc f(c: CA) =
+    echo "f"
+    echo c.x
+
+  var o = new(Opt)
+
+  echo o is CA
+  echo o is LocalCA
+  echo o is ca.CA
+
+  o.f()
+
+
+
+import json
+block t5968:
+  type
+    Enumerable[T] = concept e
+      for it in e:
+        it is T
+
+  proc cmap[T, G](e: Enumerable[T], fn: proc(t: T): G): seq[G] =
+    result = @[]
+    for it in e: result.add(fn(it))
+
+  var x = %["hello", "world"]
+
+  var z = x.cmap(proc(it: JsonNode): string = it.getStr & "!")
+  assert z == @["hello!", "world!"]
+
+
+
+import sugar
+block t6462:
+  type
+    FilterMixin[T] = ref object
+      test: (T) -> bool
+      trans: (T) -> T
+
+    SeqGen[T] = ref object
+      fil: FilterMixin[T]
+
+    WithFilter[T] = concept a
+      a.fil is FilterMixin[T]
+
+  proc test[T](a: WithFilter[T]): (T) -> bool =
+    a.fil.test
+
+  var s = SeqGen[int](fil: FilterMixin[int](test: nil, trans: nil))
+  doAssert s.test() == nil
+
+
+
+block t6770:
+  type GA = concept c
+    c.a is int
+
+  type A = object
+    a: int
+
+  type AA = object
+    case exists: bool
+    of true:
+      a: int
+    else:
+      discard
+
+  proc print(inp: GA) =
+    echo inp.a
+
+  let failing = AA(exists: true, a: 10)
+  let working = A(a:10)
+  print(working)
+  print(failing)
+
+
+
+block t7952:
+  type
+    HasLen = concept iter
+      len(iter) is int
+
+  proc echoLen(x: HasLen) =
+    echo len(x)
+
+  echoLen([1, 2, 3, 4, 5])
+
+
+
+block t8280:
+  type
+    Iterable[T] = concept x
+      for elem in x:
+        elem is T
+
+  proc max[A](iter: Iterable[A]): A =
+    discard
+
+  type
+    MyType = object
+
+  echo max(@[MyType()])
+
+
+
+import math
+block t3452:
+  type
+    Node = concept n
+      `==`(n, n) is bool
+    Graph1 = concept g
+      type N = Node
+      distance(g, N, N) is float
+    Graph2 = concept g
+      distance(g, Node, Node) is float
+    Graph3 = concept g
+      var x: Node
+      distance(g, x, x) is float
+    XY = tuple[x, y: int]
+    MyGraph = object
+      points: seq[XY]
+
+  static:
+    assert XY is Node
+
+  proc distance( g: MyGraph, a, b: XY): float =
+    sqrt( pow(float(a.x - b.x), 2) + pow(float(a.y - b.y), 2) )
+
+  static:
+    assert MyGraph is Graph1
+    assert MyGraph is Graph2
+    assert MyGraph is Graph3
+
+
+
+block t6691:
+  type
+    ConceptA = concept c
+    ConceptB = concept c
+        c.myProc(ConceptA)
+    Obj = object
+
+  proc myProc(obj: Obj, x: ConceptA) = discard
+
+  echo Obj is ConceptB
+
+
+
+block t6782:
+  type
+    Reader = concept c
+      c.read(openArray[byte], int, int) is int
+    Rdr = concept c
+      c.rd(openArray[byte], int, int) is int
+
+  type TestFile = object
+
+  proc read(r: TestFile, dest: openArray[byte], offset: int, limit: int): int =
+      result = 0
+  proc rd(r: TestFile, dest: openArray[byte], offset: int, limit: int): int =
+      result = 0
+
+  doAssert TestFile is Reader
+  doAssert TestFile is Rdr
+
+
+
+block t7114:
+  type
+    MyConcept = concept x
+      x.close() # error, doesn't work
+    MyConceptImplementer = object
+
+  proc close(self: MyConceptImplementer) = discard
+  proc takeConcept(window: MyConcept) =
+    discard
+
+  takeConcept(MyConceptImplementer())
+
+
+
+block t7510:
+  type
+    A[T] = concept a
+        a.x is T
+    B[T] = object
+        x: T
+  proc getx(v: A): v.T = v.x
+  var v = B[int32](x: 10)
+  echo v.getx
+
+
+
+block misc_issues:
+  # https://github.com/nim-lang/Nim/issues/1147
+  type TTest = object
+    vals: seq[int]
+
+  proc add(self: var TTest, val: int) =
+    self.vals.add(val)
+
+  type CAddable = concept x
+    x[].add(int)
+
+  echo((ref TTest) is CAddable) # true
+
+  # https://github.com/nim-lang/Nim/issues/1570
+  type ConcretePointOfFloat = object
+    x, y: float
+
+  type ConcretePoint[Value] = object
+    x, y: Value
+
+  type AbstractPointOfFloat = concept p
+    p.x is float and p.y is float
+
+  let p1 = ConcretePointOfFloat(x: 0, y: 0)
+  let p2 = ConcretePoint[float](x: 0, y: 0)
+
+  echo p1 is AbstractPointOfFloat      # true
+  echo p2 is AbstractPointOfFloat      # true
+  echo p2.x is float and p2.y is float # true
+
+  # https://github.com/nim-lang/Nim/issues/2018
+  type ProtocolFollower = concept c
+    true # not a particularly involved protocol
+
+  type ImplementorA = object
+  type ImplementorB = object
+
+  proc p[A: ProtocolFollower, B: ProtocolFollower](a: A, b: B) =
+    echo "p has been called."
+
+  p(ImplementorA(), ImplementorA())
+  p(ImplementorA(), ImplementorB())
+
+  # https://github.com/nim-lang/Nim/issues/2423
+  proc put[T](c: seq[T], x: T) = echo "generic"
+  proc put(c: seq) = echo "implicit generic"
+
+  type
+    Container[T] = concept c
+      put(c)
+      put(c, T)
+
+  proc c1(x: Container) = echo "implicit generic"
+  c1(@[1])
+
+  proc c2[T](x: Container[T]) = echo "generic"
+  c2(@[1])
+
+  # https://github.com/nim-lang/Nim/issues/2882
+  type
+    Paper = object
+      name: string
+
+    Bendable = concept x
+      bend(x is Bendable)
+
+  proc bend(p: Paper): Paper = Paper(name: "bent-" & p.name)
+
+  var paper = Paper(name: "red")
+  echo paper is Bendable
+
+  type
+    A = concept self
+      size(self) is int
+
+    B = object
+
+  proc size(self: B): int =
+    return -1
+
+  proc size(self: A): int =
+    return 0
+
+  let b = B()
+  echo b is A
+  echo b.size()
+
+  # https://github.com/nim-lang/Nim/issues/7125
+  type
+    Thing = concept x
+      x.hello is string
+    Cat = object
+
+  proc hello(d: Cat): string = "Meow"
+
+  proc sayHello(c: Thing) = echo(c.hello)
+
+  # used to be 'var a: Thing = Cat()' but that's not valid Nim code
+  # anyway and will be an error soon.
+  var a: Cat = Cat()
+  a.sayHello()
+
+
+# bug #16897
+
+type
+  Fp[N: static int, T] = object
+    big: array[N, T]
+
+type
+  QuadraticExt* = concept x
+    ## Quadratic Extension concept (like complex)
+    type BaseField = auto
+    x.c0 is BaseField
+    x.c1 is BaseField
+var address = pointer(nil)
+proc prod(r: var QuadraticExt, b: QuadraticExt) =
+  if address == nil:
+    address = addr b
+    prod(r, b)
+  else:
+    assert address == addr b
+
+type
+  Fp2[N: static int, T] {.byref.} = object
+    c0, c1: Fp[N, T]
+
+# This should be passed by reference,
+# but concepts do not respect the 24 bytes rule
+# or `byref` pragma.
+var r, b: Fp2[6, uint64]
+
+prod(r, b)
+
+
+block: # bug #21263
+  type
+    DateDayFraction = concept # no T, an atom
+      proc date(a: Self): int
+      proc fraction(b: Self): float
+    Date = distinct int
+    DateDayFractionImpl = object
+      date : int
+      fraction : float
+
+  proc date(a: Date): int = a.int
+  proc fraction(a:Date): float = 0.0
+
+  proc date(a: DateDayFractionImpl): int = a.date
+  proc fraction(b: DateDayFractionImpl): float = b.fraction
+
+
+  proc print(a: DateDayFraction) =
+    echo a.date, " ", a.fraction
+
+  print(10.Date) # ok
+  print(DateDayFractionImpl(date: 1, fraction: 2))  # error
+
+import sets
+import deques
+
+type AnyTree[V] = concept t, type T
+  for v in t.leaves(V):
+    v is V
+
+type BreadthOrder[V] = ref object
+  frontier: Deque[V]
+  visited: HashSet[V]
+
+proc expand[V, T](order: ref BreadthOrder[T], tree: AnyTree[V], node: V, transform: (V) -> (T)) =
+  for leaf in tree.leaves(node):
+    if not order.visited.containsOrIncl(transform(leaf)):
+      order.frontier.addLast(transform(leaf))
+
+proc hasNext[V](order: ref BreadthOrder[V]): bool =
+  order.frontier.len > 0
+
+proc init[V](_: typedesc[BreadthOrder]): ref BreadthOrder[V] =
+  result.new()
+  result[] = BreadthOrder[V](frontier: initDeque[V](), visited: initHashSet[V]())
+
+proc popNext[V](order: ref BreadthOrder[V]): V =
+  order.frontier.popFirst()
+
+type LevelNode[V] = tuple
+  depth: uint
+  node: V
+
+proc depthOf*[V](orderType: typedesc[BreadthOrder], tree: AnyTree[V], root, goal: V): uint =
+  if root == goal:
+    return 0
+  var order = init[LevelNode[V]](orderType)
+  order.expand(tree, root, (leaf) => (1.uint, leaf))
+  while order.hasNext():
+    let depthNode: LevelNode[V] = order.popNext()
+    if depthNode.node == goal:
+      return depthNode.depth
+    order.expand(tree, depthNode.node, (leaf) => (depthNode.depth + 1, leaf))
+
+type CappedStringTree = ref object
+  symbols: string
+  cap: Natural
+
+iterator leaves*(t: CappedStringTree, s: string): string =
+  if s.len < t.cap:
+    for c in t.symbols:
+      yield s & c
+
+block: # bug #12852
+  var tree = CappedStringTree(symbols: "^v><", cap: 5)
+
+  doAssert BreadthOrder.depthOf(tree, "", ">>>") == 3
+
+block: #bug #22723
+  type
+    Node  = concept n, type T 
+      for i in n.children:
+        i is T
+      n.parent is T
+
+    Nd = ref object
+      parent: Nd
+      children: seq[Nd]
+
+  proc addChild(parent, child: Node) =
+    parent.children.add(child)
+    child.parent = parent
+
+  proc foo =
+    var
+      a = Nd()
+      b = Nd()
+    a.addChild(b)
+    doAssert a.children.len == 1
+
+  foo()