summary refs log tree commit diff stats
path: root/tests/specialops
diff options
context:
space:
mode:
Diffstat (limited to 'tests/specialops')
-rw-r--r--tests/specialops/tcallops.nim49
-rw-r--r--tests/specialops/tcallprecedence.nim44
-rw-r--r--tests/specialops/tdotops.nim97
-rw-r--r--tests/specialops/terrmsgs.nim76
-rw-r--r--tests/specialops/tnewseq.nim22
-rw-r--r--tests/specialops/tsetter.nim10
6 files changed, 298 insertions, 0 deletions
diff --git a/tests/specialops/tcallops.nim b/tests/specialops/tcallops.nim
new file mode 100644
index 000000000..c541a0c1d
--- /dev/null
+++ b/tests/specialops/tcallops.nim
@@ -0,0 +1,49 @@
+import macros
+
+{.experimental: "callOperator".}
+
+type Foo[T: proc] = object
+  callback: T
+
+macro `()`(foo: Foo, args: varargs[untyped]): untyped =
+  result = newCall(newDotExpr(foo, ident"callback"))
+  for a in args:
+    result.add(a)
+
+var f1Calls = 0
+var f = Foo[proc()](callback: proc() = inc f1Calls)
+doAssert f1Calls == 0
+f()
+doAssert f1Calls == 1
+var f2Calls = 0
+f.callback = proc() = inc f2Calls
+doAssert f2Calls == 0
+f()
+doAssert f2Calls == 1
+
+let g = Foo[proc (x: int): int](callback: proc (x: int): int = x * 2 + 1)
+doAssert g(15) == 31
+
+proc `()`(args: varargs[string]): string =
+  result = "("
+  for a in args: result.add(a)
+  result.add(')')
+
+let a = "1"
+let b = "2"
+let c = "3"
+
+doAssert a(b) == "(12)"
+doAssert a.b(c) == `()`(b, a, c)
+doAssert (a.b)(c) == `()`(a.b, c)
+doAssert `()`(a.b, c) == `()`(`()`(b, a), c)
+
+block: # bug #1072
+  var x: int
+
+  proc foo(some:int):int = some
+  proc `()`(l,r:string): string = discard
+
+  block:
+    var foo = 42
+    doAssert x.foo == 0
diff --git a/tests/specialops/tcallprecedence.nim b/tests/specialops/tcallprecedence.nim
new file mode 100644
index 000000000..6116f83d5
--- /dev/null
+++ b/tests/specialops/tcallprecedence.nim
@@ -0,0 +1,44 @@
+import macros
+
+{.experimental: "dotOperators".}
+{.experimental: "callOperator".}
+
+block:
+  template `.()`(foo: int, args: varargs[untyped]): untyped {.used.} =
+    ".()"
+
+  template `()`(foo: int, args: varargs[untyped]): untyped =
+    "()"
+
+  let a = (b: 1)
+  let c = 3
+
+  doAssert a.b(c) == "()"
+  doAssert not compiles(a(c))
+  doAssert (a.b)(c) == "()"
+
+macro `()`(args: varargs[typed]): untyped =
+  result = newLit("() " & args.treeRepr)
+
+macro `.`(args: varargs[typed]): untyped =
+  result = newLit(". " & args.treeRepr)
+
+block:
+  let a = 1
+  let b = 2
+  doAssert a.b == `()`(b, a)
+
+block:
+  let a = 1
+  proc b(): int {.used.} = 2
+  doAssert a.b == `.`(a, b)
+
+block:
+  let a = 1
+  proc b(x: int): int = x + 1
+  let c = 3
+
+  doAssert a.b(c) == `.`(a, b, c)
+  doAssert a(b) == `()`(a, b)
+  doAssert (a.b)(c) == `()`(a.b, c)
+  doAssert a.b == b(a)
diff --git a/tests/specialops/tdotops.nim b/tests/specialops/tdotops.nim
new file mode 100644
index 000000000..ca5eee665
--- /dev/null
+++ b/tests/specialops/tdotops.nim
@@ -0,0 +1,97 @@
+discard """
+  output: '''
+
+10
+assigning z = 20
+reading field y
+20
+call to y
+dot call
+no params call to a
+100
+no params call to b
+100
+one param call to c with 10
+100
+0 4
+'''
+"""
+
+block:
+  type Foo = object
+  var a: Foo
+  template `.`(a: Foo, b: untyped): untyped = astToStr(b)
+  template callme(a, f): untyped = a.f
+  doAssert callme(a, f2) == "f2" # not `f`
+  doAssert a.callme(f3) == "f3"
+
+type
+  T1 = object
+    x*: int
+
+  TD = distinct T1
+
+  T2 = object
+    x: int
+
+template `.`*(v: T1, f: untyped): int =
+  echo "reading field ", astToStr(f)
+  v.x
+
+template `.=`(t: var T1, f: untyped, v: int) =
+  echo "assigning ", astToStr(f), " = ", v
+  t.x = v
+
+template `.()`(x: T1, f: untyped, args: varargs[typed]): string =
+  echo "call to ", astToStr(f)
+  "dot call"
+
+echo ""
+
+var t = T1(x: 10)
+
+echo t.x
+t.z = 20
+echo t.y
+echo t.y()
+
+var d = TD(t)
+assert(not compiles(d.y))
+
+template `.`(v: T2, f: untyped): int =
+  echo "no params call to ", astToStr(f)
+  v.x
+
+template `.`*(v: T2, f: untyped, a: int): int =
+  echo "one param call to ", astToStr(f), " with ", a
+  v.x
+
+var tt = T2(x: 100)
+
+echo tt.a
+echo tt.b()
+echo tt.c(10)
+
+assert(not compiles(tt.d("x")))
+assert(not compiles(tt.d(1, 2)))
+
+# test simple usage that delegates fields:
+type
+  Other = object
+    a: int
+    b: string
+  MyObject = object
+    nested: Other
+    x, y: int
+
+template `.`(x: MyObject; field: untyped): untyped =
+  x.nested.field
+
+template `.=`(x: MyObject; field, value: untyped) =
+  x.nested.field = value
+
+var m: MyObject
+
+m.a = 4
+m.b = "foo"
+echo m.x, " ", m.a
diff --git a/tests/specialops/terrmsgs.nim b/tests/specialops/terrmsgs.nim
new file mode 100644
index 000000000..081bca451
--- /dev/null
+++ b/tests/specialops/terrmsgs.nim
@@ -0,0 +1,76 @@
+discard """
+action: reject
+cmd: '''nim check $options $file'''
+matrix: "; -d:testWithout; --mm:refc"
+"""
+
+when not defined(testWithout): # test for same errors before and after
+  {.experimental: "dotOperators".}
+  {.experimental: "callOperator".}
+
+# issue #13063
+
+block:
+  type Foo = object
+  type Bar = object
+    x1: int
+  var b: Bar
+  block:
+    template `.`(a: Foo, b: untyped): untyped = 123
+    echo b.x #[tt.Error
+          ^ undeclared field: 'x' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]#
+  block:
+    template `.()`(a: Foo, b: untyped): untyped = 123
+    echo b.x() #[tt.Error
+          ^ attempting to call undeclared routine: 'x']#
+  block:
+    template `.=`(a: Foo, b: untyped, c: untyped) = b = c
+    b.x = 123 #[tt.Error
+        ^ undeclared field: 'x=' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]#
+    # yeah it says x= but does it matter in practice
+  block:
+    template `()`(a: Foo, b: untyped, c: untyped) = echo "something"
+
+    # completely undeclared::
+    xyz(123) #[tt.Error
+    ^ undeclared identifier: 'xyz']#
+
+    # already declared routine:
+    min(123) #[tt.Error
+       ^ type mismatch: got <int literal(123)>]#
+
+    # non-routine type shows `()` overloads:
+    b(123) #[tt.Error
+     ^ attempting to call routine: 'b']#
+
+    echo b.x #[tt.Error
+          ^ undeclared field: 'x' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]#
+    echo b.x() #[tt.Error
+          ^ attempting to call undeclared routine: 'x']#
+
+# issue #7777
+
+import macros
+
+block:
+  type TestType = object
+    private_field: string
+
+  when false:
+    template getField(obj, field: untyped): untyped = obj.field
+
+  macro `.`(obj: TestType, field: untyped): untyped =
+    let private = newIdentNode("private_" & $field)
+    result = quote do:
+      `obj`.getField(`private`) #[tt.Error
+           ^ attempting to call undeclared routine: 'getField']#
+
+  var tt: TestType
+  discard tt.field
+
+block: # related to issue #6981
+  proc `()`(a:string, b:string):string = a & b
+  proc mewSeq[T](a,b:int)=discard
+  proc mewSeq[T](c:int)= discard
+  mewSeq[int]() #[tt.Error
+             ^ type mismatch: got <>]#
diff --git a/tests/specialops/tnewseq.nim b/tests/specialops/tnewseq.nim
new file mode 100644
index 000000000..970a5a8c2
--- /dev/null
+++ b/tests/specialops/tnewseq.nim
@@ -0,0 +1,22 @@
+# issue #6981
+
+import std/assertions
+
+{.experimental: "callOperator".}
+
+block: # issue #6981
+  proc `()`(a:string, b:string):string = a & b
+
+  var s = newSeq[int](3)
+
+  doAssert s == @[0, 0, 0]
+
+block: # generalized example from #6981
+  proc mewSeq[T](a: int)=discard
+  proc mewSeq[T]()= discard
+  mewSeq[int]()
+
+block: # issue #9831
+  type Foo = object
+  proc `()`(foo: Foo) = discard
+  let x = newSeq[int]()
diff --git a/tests/specialops/tsetter.nim b/tests/specialops/tsetter.nim
new file mode 100644
index 000000000..6175cbec4
--- /dev/null
+++ b/tests/specialops/tsetter.nim
@@ -0,0 +1,10 @@
+block: # ensure RHS of setter statement is treated as call operand
+  proc `b=`(a: var int, c: proc (x: int): int) =
+    a = c(a)
+
+  proc foo(x: int): int = x + 1
+  proc foo(x: float): float = x - 1
+
+  var a = 123
+  a.b = foo
+  doAssert a == 124