summary refs log tree commit diff stats
path: root/tests/template
diff options
context:
space:
mode:
Diffstat (limited to 'tests/template')
-rw-r--r--tests/template/m19277_1.nim2
-rw-r--r--tests/template/m19277_2.nim2
-rw-r--r--tests/template/mqualifiedtype1.nim2
-rw-r--r--tests/template/mqualifiedtype2.nim2
-rw-r--r--tests/template/t13426.nim87
-rw-r--r--tests/template/t19277.nim19
-rw-r--r--tests/template/t24112.nim19
-rw-r--r--tests/template/tdefaultparam.nim56
-rw-r--r--tests/template/tgensymhijack.nim37
-rw-r--r--tests/template/tinnerouterproc.nim12
-rw-r--r--tests/template/tnested.nim38
-rw-r--r--tests/template/topensym.nim209
-rw-r--r--tests/template/topensymoverride.nim39
-rw-r--r--tests/template/topensymwarning.nim60
-rw-r--r--tests/template/tparams_gensymed.nim9
-rw-r--r--tests/template/tqualifiedtype.nim25
16 files changed, 618 insertions, 0 deletions
diff --git a/tests/template/m19277_1.nim b/tests/template/m19277_1.nim
new file mode 100644
index 000000000..840bd4767
--- /dev/null
+++ b/tests/template/m19277_1.nim
@@ -0,0 +1,2 @@
+template foo*(x: untyped) =
+  echo "got: ", x
diff --git a/tests/template/m19277_2.nim b/tests/template/m19277_2.nim
new file mode 100644
index 000000000..de72dad45
--- /dev/null
+++ b/tests/template/m19277_2.nim
@@ -0,0 +1,2 @@
+proc foo*(a: string) =
+  echo "got string: ", a
diff --git a/tests/template/mqualifiedtype1.nim b/tests/template/mqualifiedtype1.nim
new file mode 100644
index 000000000..46569107f
--- /dev/null
+++ b/tests/template/mqualifiedtype1.nim
@@ -0,0 +1,2 @@
+type A* = object
+  x*: int
diff --git a/tests/template/mqualifiedtype2.nim b/tests/template/mqualifiedtype2.nim
new file mode 100644
index 000000000..6a61c14bd
--- /dev/null
+++ b/tests/template/mqualifiedtype2.nim
@@ -0,0 +1,2 @@
+type A* = object
+  x*: array[1000, byte]
diff --git a/tests/template/t13426.nim b/tests/template/t13426.nim
new file mode 100644
index 000000000..f7f44749c
--- /dev/null
+++ b/tests/template/t13426.nim
@@ -0,0 +1,87 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  errormsg: ""
+  nimout: '''
+t13426.nim(81, 6) template/generic instantiation of `fun` from here
+t13426.nim(80, 24) Error: type mismatch: got <int> but expected 'string'
+t13426.nim(81, 6) template/generic instantiation of `fun` from here
+t13426.nim(80, 17) Error: type mismatch: got <uint, string>
+but expected one of:
+proc `and`(x, y: uint): uint
+  first type mismatch at position: 2
+  required type for y: uint
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: uint64): uint64
+  first type mismatch at position: 2
+  required type for y: uint64
+  but expression 'high(@[1])' is of type: string
+10 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them
+
+expression: 1'u and high(@[1])
+t13426.nim(81, 6) template/generic instantiation of `fun` from here
+t13426.nim(80, 17) Error: expression '' has no type (or is ambiguous)
+t13426.nim(87, 6) template/generic instantiation of `fun` from here
+t13426.nim(86, 22) Error: type mismatch: got <int> but expected 'string'
+t13426.nim(87, 6) template/generic instantiation of `fun` from here
+t13426.nim(86, 15) Error: type mismatch: got <int literal(1), string>
+but expected one of:
+proc `and`(x, y: int): int
+  first type mismatch at position: 2
+  required type for y: int
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: int16): int16
+  first type mismatch at position: 2
+  required type for y: int16
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: int32): int32
+  first type mismatch at position: 2
+  required type for y: int32
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: int64): int64
+  first type mismatch at position: 2
+  required type for y: int64
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: int8): int8
+  first type mismatch at position: 2
+  required type for y: int8
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: uint): uint
+  first type mismatch at position: 2
+  required type for y: uint
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: uint16): uint16
+  first type mismatch at position: 2
+  required type for y: uint16
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: uint32): uint32
+  first type mismatch at position: 2
+  required type for y: uint32
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: uint64): uint64
+  first type mismatch at position: 2
+  required type for y: uint64
+  but expression 'high(@[1])' is of type: string
+proc `and`(x, y: uint8): uint8
+  first type mismatch at position: 2
+  required type for y: uint8
+  but expression 'high(@[1])' is of type: string
+2 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them
+
+expression: 1 and high(@[1])
+t13426.nim(87, 6) template/generic instantiation of `fun` from here
+t13426.nim(86, 15) Error: expression '' has no type (or is ambiguous)
+'''
+"""
+
+# bug # #13426
+block:
+  template bar(t): string = high(t)
+  proc fun[A](key: A) =
+    var h = 1'u and bar(@[1])
+  fun(0)
+
+block:
+  template bar(t): string = high(t)
+  proc fun[A](key: A) =
+    var h = 1 and bar(@[1])
+  fun(0)
diff --git a/tests/template/t19277.nim b/tests/template/t19277.nim
new file mode 100644
index 000000000..16435a09c
--- /dev/null
+++ b/tests/template/t19277.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''
+got: 0
+'''
+"""
+
+# issue #19277
+
+import m19277_1, m19277_2
+
+template injector(val: untyped): untyped =
+  template subtemplate: untyped = val
+  subtemplate()
+
+template methodCall(val: untyped): untyped = val
+
+{.push raises: [Defect].}
+
+foo(injector(0).methodCall())
diff --git a/tests/template/t24112.nim b/tests/template/t24112.nim
new file mode 100644
index 000000000..175fc7d5e
--- /dev/null
+++ b/tests/template/t24112.nim
@@ -0,0 +1,19 @@
+discard """
+  matrix: "--skipParentCfg --filenames:legacyRelProj --hints:off"
+  action: reject
+"""
+
+# issue #24112, needs --experimental:openSym disabled
+
+block: # simplified
+  type
+    SomeObj = ref object # Doesn't error if you make SomeObj be non-ref
+  template foo = yield SomeObj()
+  when compiles(foo): discard
+
+import std/asyncdispatch
+block:
+  proc someProc(): Future[void] {.async.} = discard
+  proc foo() =
+    await someProc() #[tt.Error
+                  ^ Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead]#
diff --git a/tests/template/tdefaultparam.nim b/tests/template/tdefaultparam.nim
new file mode 100644
index 000000000..7ea0b2b25
--- /dev/null
+++ b/tests/template/tdefaultparam.nim
@@ -0,0 +1,56 @@
+block:
+  template foo(a: untyped, b: untyped = a(0)): untyped =
+    let x = a(0)
+    let y = b
+    (x, y)
+  proc bar(x: int): int = x + 1
+  doAssert foo(bar, b = bar(0)) == (1, 1)
+  doAssert foo(bar) == (1, 1)
+
+block: # issue #23506
+  var a: string
+  template foo(x: int; y = x) =
+    a = $($x, $y)
+  foo(1)
+  doAssert a == "(\"1\", \"1\")"
+
+block: # untyped params with default value
+  macro foo(x: typed): untyped =
+    result = x
+  template test(body: untyped, alt: untyped = (;), maxTries = 3): untyped {.foo.} =
+    body
+    alt
+  var s = "a"
+  test:
+    s.add "b"
+  do:
+    s.add "c"
+  doAssert s == "abc"
+  template test2(body: untyped, alt: untyped = s.add("e"), maxTries = 3): untyped =
+    body
+    alt
+  test2:
+    s.add "d"
+  doAssert s == "abcde"
+  template test3(body: untyped = willNotCompile) =
+    discard
+  test3()
+
+block: # typed params with `void` default value
+  macro foo(x: typed): untyped =
+    result = x
+  template test(body: untyped, alt: typed = (;), maxTries = 3): untyped {.foo.} =
+    body
+    alt
+  var s = "a"
+  test:
+    s.add "b"
+  do:
+    s.add "c"
+  doAssert s == "abc"
+  template test2(body: untyped, alt: typed = s.add("e"), maxTries = 3): untyped =
+    body
+    alt
+  test2:
+    s.add "d"
+  doAssert s == "abcde"
diff --git a/tests/template/tgensymhijack.nim b/tests/template/tgensymhijack.nim
new file mode 100644
index 000000000..72ff3d495
--- /dev/null
+++ b/tests/template/tgensymhijack.nim
@@ -0,0 +1,37 @@
+# issue #23326
+
+type Result*[E] = object
+  e*: E
+
+proc error*[E](v: Result[E]): E = discard
+
+template valueOr*[E](self: Result[E], def: untyped): int =
+  when E isnot void:
+    when false:
+      # Comment line below to make it work
+      template error(): E {.used, gensym.} = s.e
+      discard
+    else:
+      template error(): E {.used, inject.} =
+        self.e
+
+      def
+  else:
+    def
+
+
+block:
+  let rErr = Result[string](e: "a")
+  let rErrV = rErr.valueOr:
+    ord(error[0])
+
+block:
+  template foo(x: static bool): untyped =
+    when x:
+      let a = 123
+    else:
+      template a: untyped {.gensym.} = 456
+    a
+  
+  doAssert foo(false) == 456
+  doAssert foo(true) == 123
diff --git a/tests/template/tinnerouterproc.nim b/tests/template/tinnerouterproc.nim
index 1f15fb13e..56e0d02df 100644
--- a/tests/template/tinnerouterproc.nim
+++ b/tests/template/tinnerouterproc.nim
@@ -6,3 +6,15 @@ block: # #20002
     discard 3.bar # evaluates to 10 but only check if it compiles for now
   block:
     foo()
+
+block: # issue #23813
+  template r(body: untyped) =
+    proc x() {.gensym.} =
+      body
+  template g() =
+    r:
+      let y = 0
+    r:
+      proc y() = discard
+      y()
+  g()
diff --git a/tests/template/tnested.nim b/tests/template/tnested.nim
new file mode 100644
index 000000000..81e416a76
--- /dev/null
+++ b/tests/template/tnested.nim
@@ -0,0 +1,38 @@
+block: # issue #22775
+  proc h(c: int) = discard
+  template k(v: int) =
+    template p() = v.h()
+    p()
+  let a = @[0]
+  k(0 and not a[0])
+
+block: # issue #22775 case 2
+  proc h(c: int, q: int) = discard
+  template k(v: int) =
+    template p() = h(v, v)
+    p()
+  let a = [0]
+  k(0 and not a[0])
+
+block: # issue #22775 minimal cases
+  proc h(c: int) = discard
+  template k(v: int) =
+    template p() = h(v)
+    p()
+  let a = [0]
+  k(not a[0])
+  block:
+    k(-a[0])
+  block:
+    proc f(x: int): int = x
+    k(f a[0])
+
+block: # bracket assignment case of above tests
+  proc h(c: int) = discard
+  template k(v: int) =
+    template p() = h(v)
+    p()
+  var a = [0]
+  k(not (block:
+    a[0] = 1
+    1))
diff --git a/tests/template/topensym.nim b/tests/template/topensym.nim
new file mode 100644
index 000000000..2f930407b
--- /dev/null
+++ b/tests/template/topensym.nim
@@ -0,0 +1,209 @@
+{.experimental: "openSym".}
+
+block: # issue #24002
+  type Result[T, E] = object
+  func value[T, E](self: Result[T, E]): T {.inline.} =
+    discard
+  func value[T: not void, E](self: var Result[T, E]): var T {.inline.} =
+    discard
+  template unrecognizedFieldWarning =
+    doAssert value == 123
+    let x = value
+    doAssert value == x
+  proc readValue(value: var int) =
+    unrecognizedFieldWarning()
+  var foo: int = 123
+  readValue(foo)
+
+block: # issue #22605 for templates, normal call syntax
+  const error = "bad"
+
+  template valueOr(self: int, def: untyped): untyped =
+    case false
+    of true: ""
+    of false:
+      template error: untyped {.used, inject.} = "good"
+      def
+
+  template g(T: type): string =
+    var res = "ok"
+    let x = valueOr 123:
+      res = $error
+      "dummy"
+    res
+
+  doAssert g(int) == "good"
+
+  template g2(T: type): string =
+    bind error # use the bad version on purpose
+    var res = "ok"
+    let x = valueOr 123:
+      res = $error
+      "dummy"
+    res
+
+  doAssert g2(int) == "bad"
+
+block: # issue #22605 for templates, method call syntax
+  const error = "bad"
+
+  template valueOr(self: int, def: untyped): untyped =
+    case false
+    of true: ""
+    of false:
+      template error: untyped {.used, inject.} = "good"
+      def
+
+  template g(T: type): string =
+    var res = "ok"
+    let x = 123.valueOr:
+      res = $error
+      "dummy"
+    res
+
+  doAssert g(int) == "good"
+
+  template g2(T: type): string =
+    bind error # use the bad version on purpose
+    var res = "ok"
+    let x = 123.valueOr:
+      res = $error
+      "dummy"
+    res
+
+  doAssert g2(int) == "bad"
+
+block: # issue #22605 for templates, original complex example
+  type Xxx = enum
+    error
+    value
+
+  type
+    Result[T, E] = object
+      when T is void:
+        when E is void:
+          oResultPrivate*: bool
+        else:
+          case oResultPrivate*: bool
+          of false:
+            eResultPrivate*: E
+          of true:
+            discard
+      else:
+        when E is void:
+          case oResultPrivate*: bool
+          of false:
+            discard
+          of true:
+            vResultPrivate*: T
+        else:
+          case oResultPrivate*: bool
+          of false:
+            eResultPrivate*: E
+          of true:
+            vResultPrivate*: T
+
+  template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped =
+    let s = (self) # TODO avoid copy
+    case s.oResultPrivate
+    of true:
+      s.vResultPrivate
+    of false:
+      when E isnot void:
+        template error: untyped {.used, inject.} = s.eResultPrivate
+      def
+
+  proc f(): Result[int, cstring] =
+    Result[int, cstring](oResultPrivate: false, eResultPrivate: "f")
+
+  template g(T: type): string =
+    var res = "ok"
+    let x = f().valueOr:
+      res = $error
+      123
+    res
+
+  doAssert g(int) == "f"
+
+  template g2(T: type): string =
+    bind error # use the bad version on purpose
+    var res = "ok"
+    let x = f().valueOr:
+      res = $error
+      123
+    res
+
+  doAssert g2(int) == "error"
+
+block: # issue #23865 for templates
+  type Xxx = enum
+    error
+    value
+
+  type
+    Result[T, E] = object
+      when T is void:
+        when E is void:
+          oResultPrivate: bool
+        else:
+          case oResultPrivate: bool
+          of false:
+            eResultPrivate: E
+          of true:
+            discard
+      else:
+        when E is void:
+          case oResultPrivate: bool
+          of false:
+            discard
+          of true:
+            vResultPrivate: T
+        else:
+          case oResultPrivate: bool
+          of false:
+            eResultPrivate: E
+          of true:
+            vResultPrivate: T
+
+  func error[T, E](self: Result[T, E]): E =
+    ## Fetch error of result if set, or raise Defect
+    case self.oResultPrivate
+    of true:
+      when T isnot void:
+        raiseResultDefect("Trying to access error when value is set", self.vResultPrivate)
+      else:
+        raiseResultDefect("Trying to access error when value is set")
+    of false:
+      when E isnot void:
+        self.eResultPrivate
+
+  template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped =
+    let s = (self) # TODO avoid copy
+    case s.oResultPrivate
+    of true:
+      s.vResultPrivate
+    of false:
+      when E isnot void:
+        template error: untyped {.used, inject.} = s.eResultPrivate
+      def
+  proc f(): Result[int, cstring] =
+    Result[int, cstring](oResultPrivate: false, eResultPrivate: "f")
+  template g(T: type): string =
+    var res = "ok"
+    let x = f().valueOr:
+      res = $error
+      123
+    res
+  doAssert g(int) == "f"
+
+import std/sequtils
+
+block: # issue #15314
+  var it: string
+  var nums = @[1,2,3]
+
+  template doubleNums() =
+    nums.applyIt(it * 2)
+
+  doubleNums()
+  doAssert nums == @[2, 4, 6]
diff --git a/tests/template/topensymoverride.nim b/tests/template/topensymoverride.nim
new file mode 100644
index 000000000..3d4bb59f1
--- /dev/null
+++ b/tests/template/topensymoverride.nim
@@ -0,0 +1,39 @@
+discard """
+  matrix: "--skipParentCfg --filenames:legacyRelProj"
+"""
+
+const value = "captured"
+template fooOld(x: int, body: untyped): untyped =
+  let value {.inject.} = "injected"
+  body
+template foo(x: int, body: untyped): untyped =
+  let value {.inject.} = "injected"
+  {.push experimental: "genericsOpenSym".}
+  body
+  {.pop.}
+
+proc old[T](): string =
+  fooOld(123):
+    return value
+doAssert old[int]() == "captured"
+
+template oldTempl(): string =
+  block:
+    var res: string
+    fooOld(123):
+      res = value
+    res
+doAssert oldTempl() == "captured"
+
+proc bar[T](): string =
+  foo(123):
+    return value
+doAssert bar[int]() == "injected"
+
+template barTempl(): string =
+  block:
+    var res: string
+    foo(123):
+      res = value
+    res
+doAssert barTempl() == "injected"
diff --git a/tests/template/topensymwarning.nim b/tests/template/topensymwarning.nim
new file mode 100644
index 000000000..0bbe0a9fb
--- /dev/null
+++ b/tests/template/topensymwarning.nim
@@ -0,0 +1,60 @@
+discard """
+  matrix: "--skipParentCfg --filenames:legacyRelProj"
+"""
+
+type Xxx = enum
+  error
+  value
+
+type
+  Result[T, E] = object
+    when T is void:
+      when E is void:
+        oResultPrivate*: bool
+      else:
+        case oResultPrivate*: bool
+        of false:
+          eResultPrivate*: E
+        of true:
+          discard
+    else:
+      when E is void:
+        case oResultPrivate*: bool
+        of false:
+          discard
+        of true:
+          vResultPrivate*: T
+      else:
+        case oResultPrivate*: bool
+        of false:
+          eResultPrivate*: E
+        of true:
+          vResultPrivate*: T
+
+template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped =
+  let s = (self) # TODO avoid copy
+  case s.oResultPrivate
+  of true:
+    s.vResultPrivate
+  of false:
+    when E isnot void:
+      template error: untyped {.used, inject.} = s.eResultPrivate
+    def
+
+proc f(): Result[int, cstring] =
+  Result[int, cstring](oResultPrivate: false, eResultPrivate: "f")
+
+template g(T: type): string =
+  var res = "ok"
+  let x = f().valueOr:
+    {.push warningAsError[IgnoredSymbolInjection]: on.}
+    # test spurious error
+    discard true
+    let _ = f
+    {.pop.}
+    res = $error #[tt.Warning
+           ^ a new symbol 'error' has been injected during template or generic instantiation, however 'error' [enumField declared in topensymwarning.nim(6, 3)] captured at the proc declaration will be used instead; either enable --experimental:openSym to use the injected symbol, or `bind` this captured symbol explicitly [IgnoredSymbolInjection]]#
+    123
+  res
+
+discard g(int)
diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim
index b68d7e253..b559c2d9e 100644
--- a/tests/template/tparams_gensymed.nim
+++ b/tests/template/tparams_gensymed.nim
@@ -16,6 +16,7 @@ wth
 (total: 6)
 S1
 5
+abc
 '''
 """
 # bug #1915
@@ -394,3 +395,11 @@ proc chunkedReadLoop2 =
   test2
 
 test1(); test2()
+
+block: # bug #22846
+  template foo2(x: proc (y: string)) =
+    let f = x
+    f("abc")
+
+  foo2(proc (y: string) = echo y)
+
diff --git a/tests/template/tqualifiedtype.nim b/tests/template/tqualifiedtype.nim
new file mode 100644
index 000000000..6497af6ee
--- /dev/null
+++ b/tests/template/tqualifiedtype.nim
@@ -0,0 +1,25 @@
+# issue #19866
+
+# Switch module import order to switch which of last two
+# doAsserts fails
+import mqualifiedtype1
+import mqualifiedtype2
+
+# this isn't officially supported but needed to point out the issue:
+template f(moduleName: untyped): int = sizeof(`moduleName`.A)
+template g(someType:   untyped): int = sizeof(someType)
+
+# These are legitimately true.
+doAssert sizeof(mqualifiedtype1.A) != sizeof(mqualifiedtype2.A)
+doAssert g(mqualifiedtype1.A) != g(mqualifiedtype2.A)
+
+# Which means that this should not be true, but is in Nim 1.6
+doAssert f(`mqualifiedtype1`) != f(`mqualifiedtype2`)
+doAssert f(mqualifiedtype1) != f(mqualifiedtype2)
+
+# These should be true, but depending on import order, exactly one
+# fails in Nim 1.2, 1.6 and devel.
+doAssert f(`mqualifiedtype1`) == g(mqualifiedtype1.A)
+doAssert f(`mqualifiedtype2`) == g(mqualifiedtype2.A)
+doAssert f(mqualifiedtype1) == g(mqualifiedtype1.A)
+doAssert f(mqualifiedtype2) == g(mqualifiedtype2.A)