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/m1027a.nim1
-rw-r--r--tests/template/m1027b.nim1
-rw-r--r--tests/template/m19277_1.nim2
-rw-r--r--tests/template/m19277_2.nim2
-rw-r--r--tests/template/mdotcall.nim82
-rw-r--r--tests/template/mdotcall2.nim7
-rw-r--r--tests/template/mqualifiedtype1.nim2
-rw-r--r--tests/template/mqualifiedtype2.nim2
-rw-r--r--tests/template/otests.nim4
-rw-r--r--tests/template/sunset.nimf2
-rw-r--r--tests/template/t1027.nim22
-rw-r--r--tests/template/t11705.nim17
-rw-r--r--tests/template/t13426.nim87
-rw-r--r--tests/template/t17433.nim16
-rw-r--r--tests/template/t18113.nim14
-rw-r--r--tests/template/t19149.nim19
-rw-r--r--tests/template/t19277.nim19
-rw-r--r--tests/template/t19700.nim10
-rw-r--r--tests/template/t21231.nim10
-rw-r--r--tests/template/t21532.nim8
-rw-r--r--tests/template/t24112.nim19
-rw-r--r--tests/template/t6217.nim19
-rw-r--r--tests/template/t9534.nim21
-rw-r--r--tests/template/taliassyntax.nim74
-rw-r--r--tests/template/taliassyntaxerrors.nim28
-rw-r--r--tests/template/tcallsitelineinfo.nim17
-rw-r--r--tests/template/tcallsitelineinfo2.nim20
-rw-r--r--tests/template/tdefaultparam.nim56
-rw-r--r--tests/template/tdotcall.nim32
-rw-r--r--tests/template/template_issues.nim8
-rw-r--r--tests/template/template_pragmas.nim2
-rw-r--r--tests/template/template_various.nim61
-rw-r--r--tests/template/tgenericparam.nim93
-rw-r--r--tests/template/tgensymhijack.nim37
-rw-r--r--tests/template/tidentconcatenations.nim31
-rw-r--r--tests/template/tinnerouterproc.nim20
-rw-r--r--tests/template/tmodulealias.nim2
-rw-r--r--tests/template/tnested.nim38
-rw-r--r--tests/template/tobjectdeclfield.nim21
-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.nim11
-rw-r--r--tests/template/tqualifiedident.nim8
-rw-r--r--tests/template/tqualifiedtype.nim25
-rw-r--r--tests/template/tredefinition_override.nim33
-rw-r--r--tests/template/tunderscore1.nim11
-rw-r--r--tests/template/twrongmapit.nim6
-rw-r--r--tests/template/utemplates.nim2
49 files changed, 1314 insertions, 16 deletions
diff --git a/tests/template/m1027a.nim b/tests/template/m1027a.nim
new file mode 100644
index 000000000..fad915a2f
--- /dev/null
+++ b/tests/template/m1027a.nim
@@ -0,0 +1 @@
+const version_str* = "mod a"
diff --git a/tests/template/m1027b.nim b/tests/template/m1027b.nim
new file mode 100644
index 000000000..5ff0b9714
--- /dev/null
+++ b/tests/template/m1027b.nim
@@ -0,0 +1 @@
+const version_str* = "mod b"
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/mdotcall.nim b/tests/template/mdotcall.nim
new file mode 100644
index 000000000..fecd8ee26
--- /dev/null
+++ b/tests/template/mdotcall.nim
@@ -0,0 +1,82 @@
+# issue #20073
+
+type Foo = object
+proc foo(f: Foo) = discard
+
+template works*() =
+  var f: Foo
+  foo(f)
+
+template boom*() =
+  var f: Foo
+  f.foo() # Error: attempting to call undeclared routine: 'foo'
+  f.foo # Error: undeclared field: 'foo' for type a.Foo
+
+# issue #7085
+
+proc bar(a: string): string =
+  return a & "bar"
+
+template baz*(a: string): string =
+  var b = a.bar()
+  b
+
+# issue #7223
+
+import mdotcall2
+
+type
+  Bytes* = seq[byte]
+  
+  BytesRange* = object
+    bytes*: Bytes
+    ibegin*, iend*: int
+
+proc privateProc(r: BytesRange): int = r.ibegin
+
+template rangeBeginAddr*(r: BytesRange): pointer =
+  r.bytes.baseAddr.shift(r.privateProc)
+
+# issue #11733
+
+type ObjA* = object
+
+proc foo2(o: var ObjA) = discard
+proc bar2(o: var ObjA, arg: Natural) = discard
+
+template publicTemplateObjSyntax*(o: var ObjA, arg: Natural, doStuff: untyped) =
+  o.foo2()
+  doStuff
+  o.bar2(arg)
+
+# issue #15246
+import os
+
+template sourceBaseName*(): string =
+  bind splitFile
+  instantiationInfo().filename.splitFile().name
+
+# issue #12683
+
+import unicode
+template toRune(s: string): Rune = s.runeAt(0)
+proc heh*[T](x: Slice[T], chars: string) = discard chars.toRune
+
+# issue #7889
+
+from streams import newStringStream, readData, writeData
+
+template bindmeTemplate*(): untyped =
+  var tst = "sometext"
+  var ss = newStringStream("anothertext")
+  ss.writeData(tst[0].addr, 2)
+  discard ss.readData(tst[0].addr, 2) # <= comment this out to make compilation successful
+
+from macros import quote, newIdentNode
+
+macro bindmeQuote*(): untyped =
+  quote do:
+    var tst = "sometext"
+    var ss = newStringStream("anothertext")
+    ss.writeData(tst[0].addr, 2)
+    discard ss.readData(tst[0].addr, 2) # <= comment this out to make compilation successful
diff --git a/tests/template/mdotcall2.nim b/tests/template/mdotcall2.nim
new file mode 100644
index 000000000..e906ac9d6
--- /dev/null
+++ b/tests/template/mdotcall2.nim
@@ -0,0 +1,7 @@
+# imported by mdotcall
+
+proc baseAddr*[T](x: openarray[T]): pointer =
+  cast[pointer](x)
+
+proc shift*(p: pointer, delta: int): pointer =
+  cast[pointer](cast[int](p) + delta)
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/otests.nim b/tests/template/otests.nim
index 120146343..9cb9d7fcb 100644
--- a/tests/template/otests.nim
+++ b/tests/template/otests.nim
@@ -163,7 +163,7 @@ when true: #embeddingTest
     """
 
     # Expression template
-    proc test_expression(nums: openarray[int] = []): string =
+    proc test_expression(nums: openArray[int] = []): string =
         var i = 2
         tmpli html"""
             $(no_substitution())
@@ -171,7 +171,7 @@ when true: #embeddingTest
             <div id="age">Age: $($nums[i] & "!!")</div>
         """
 
-    proc test_statements(nums: openarray[int] = []): string =
+    proc test_statements(nums: openArray[int] = []): string =
         tmpli html"""
             $(test_expression(nums))
             $if true {
diff --git a/tests/template/sunset.nimf b/tests/template/sunset.nimf
index 465b12a5e..bd57bb8e1 100644
--- a/tests/template/sunset.nimf
+++ b/tests/template/sunset.nimf
@@ -1,6 +1,6 @@
 #? stdtmpl
 #proc sunsetTemplate*(current, ticker, content: string,
-#                     tabs: openarray[array[0..1, string]]): string = 
+#                     tabs: openArray[array[0..1, string]]): string = 
 #  result = ""
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
diff --git a/tests/template/t1027.nim b/tests/template/t1027.nim
new file mode 100644
index 000000000..fe03c4ea9
--- /dev/null
+++ b/tests/template/t1027.nim
@@ -0,0 +1,22 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  errormsg: ""
+  nimout: '''
+t1027.nim(20, 19) Error: ambiguous identifier: 'version_str' -- use one of the following:
+  m1027a.version_str: string
+  m1027b.version_str: string
+'''
+"""
+
+
+
+
+
+
+import m1027a, m1027b
+
+# bug #1027
+template wrap_me(stuff): untyped =
+  echo "Using " & version_str
+
+wrap_me("hey")
diff --git a/tests/template/t11705.nim b/tests/template/t11705.nim
new file mode 100644
index 000000000..65ddc7e6c
--- /dev/null
+++ b/tests/template/t11705.nim
@@ -0,0 +1,17 @@
+type RefObj = ref object
+
+proc `[]`(val: static[int]) = # works with different name/overload or without static arg
+  discard
+
+template noRef*(T: typedesc): typedesc = # works without template indirection
+  typeof(default(T)[])
+
+proc `=destroy`(x: var noRef(RefObj)) =
+  discard
+
+proc foo =
+  var x = new RefObj
+  doAssert $(x[]) == "()"
+
+# bug #11705
+foo()
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/t17433.nim b/tests/template/t17433.nim
new file mode 100644
index 000000000..053d33ff0
--- /dev/null
+++ b/tests/template/t17433.nim
@@ -0,0 +1,16 @@
+# Inside template bodies, ensure return types referencing a param are replaced.
+# This helps guarantee that return parameter analysis happens after argument
+# analysis.
+ 
+# bug #17433
+
+from std/macros import expandMacros
+
+proc bar(a: typedesc): a = default(a)
+doAssert bar(float) == 0.0
+doAssert bar(string) == ""
+
+template main =
+  proc baz(a: typedesc): a = default(a)
+  doAssert baz(float) == 0.0
+main()
diff --git a/tests/template/t18113.nim b/tests/template/t18113.nim
new file mode 100644
index 000000000..a84b3fd0e
--- /dev/null
+++ b/tests/template/t18113.nim
@@ -0,0 +1,14 @@
+# ensure template pragma handling doesn't eagerly attempt to add an implicit
+# 'pushed' pragma to the evaluation of any intermediate AST prior to
+# substitution.
+ 
+# bug #18113
+
+import sequtils
+
+{.push raises: [Defect].}
+
+var a = toSeq([1, 2, 3, 5, 10]).filterIt(it > 5)
+
+doAssert a.len == 1
+doAssert a[0] == 10
diff --git a/tests/template/t19149.nim b/tests/template/t19149.nim
new file mode 100644
index 000000000..631e8fc30
--- /dev/null
+++ b/tests/template/t19149.nim
@@ -0,0 +1,19 @@
+type Foo = tuple[active: bool, index: int]
+
+
+var f: Foo
+
+# template result type during match stage
+# f:var Foo
+# a:Foo
+# tyVar
+# tyTuple
+# after change to proc
+# f:Foo
+# a:Foo
+# tyTuple
+# tyTuple
+
+template cursor(): var Foo = f
+discard cursor()
+
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/t19700.nim b/tests/template/t19700.nim
new file mode 100644
index 000000000..cc2944944
--- /dev/null
+++ b/tests/template/t19700.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "type mismatch: got <Obj, Obj, template (x: untyped, y: untyped): untyped>"
+"""
+
+type Obj = object
+
+proc apply[T, R](a, b: T; f: proc(x, y: T): R): R = f(a, b)
+
+let a, b = Obj()
+discard apply(a, b, `!=`)
diff --git a/tests/template/t21231.nim b/tests/template/t21231.nim
new file mode 100644
index 000000000..51e96cdd6
--- /dev/null
+++ b/tests/template/t21231.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "undeclared identifier: 'x'"
+"""
+
+var x: int
+# bug #21231
+template f(y: untyped) = echo y.x
+for i in 1 .. 10:
+  x = i
+  f(system)
diff --git a/tests/template/t21532.nim b/tests/template/t21532.nim
new file mode 100644
index 000000000..3193b0dc3
--- /dev/null
+++ b/tests/template/t21532.nim
@@ -0,0 +1,8 @@
+
+template elementType(a: untyped): typedesc =
+  typeof(block: (for ai in a: ai))
+
+func fn[T](a: T) =
+  doAssert elementType(a) is int
+
+@[1,2,3].fn
\ No newline at end of file
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/t6217.nim b/tests/template/t6217.nim
new file mode 100644
index 000000000..b27b61881
--- /dev/null
+++ b/tests/template/t6217.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''
+start
+side effect!
+end
+'''
+"""
+
+# bug #6217
+
+template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a
+
+proc f(): int =
+  echo "side effect!"
+  result = 55
+
+echo "start"
+doAssert f() * 2 == 110
+echo "end"
diff --git a/tests/template/t9534.nim b/tests/template/t9534.nim
new file mode 100644
index 000000000..8d66f42a0
--- /dev/null
+++ b/tests/template/t9534.nim
@@ -0,0 +1,21 @@
+discard """
+  targets: "c cpp"
+"""
+
+# bug #9534
+type
+  Object = object
+    data: int
+
+template test() =
+  proc methodName(o: Object): int =
+    var p: pointer
+    doAssert o.data == 521
+    let f {.used.} = cast[proc (o: int): int {.nimcall.}](p)
+    doAssert o.data == 521
+    result = 1314
+
+  var a = Object(data: 521)
+  doAssert methodName(a) == 1314
+
+test()
diff --git a/tests/template/taliassyntax.nim b/tests/template/taliassyntax.nim
new file mode 100644
index 000000000..2d8237d93
--- /dev/null
+++ b/tests/template/taliassyntax.nim
@@ -0,0 +1,74 @@
+type Foo = object
+  bar: int
+
+var foo = Foo(bar: 10)
+template bar: int = foo.bar
+doAssert bar == 10
+bar = 15
+doAssert bar == 15
+var foo2 = Foo(bar: -10)
+doAssert bar == 15
+# works in generics
+proc genericProc[T](x: T): string =
+  $(x, bar)
+doAssert genericProc(true) == "(true, 15)"
+# redefine
+template bar: int {.redefine.} = foo2.bar
+doAssert bar == -10
+
+block: # subscript
+  var bazVal = @[1, 2, 3]
+  template baz: seq[int] = bazVal
+  doAssert baz[1] == 2
+  proc genericProc2[T](x: T): string =
+    result = $(x, baz[1])
+    baz[1] = 7
+  doAssert genericProc2(true) == "(true, 2)"
+  doAssert baz[1] == 7
+  baz[1] = 14
+  doAssert baz[1] == 14
+
+block: # type alias
+  template Int2: untyped = int
+  let x: Int2 = 123
+  proc generic[T](): string =
+    template U: untyped = T
+    var x: U
+    result = $typeof(x)
+    doAssert result == $U
+    doAssert result == $T
+  doAssert generic[int]() == "int"
+  doAssert generic[Int2]() == "int"
+  doAssert generic[string]() == "string"
+  doAssert generic[seq[int]]() == "seq[int]"
+  doAssert generic[seq[Int2]]() == "seq[int]"
+  discard generic[123]()
+  proc genericStatic[X; T: static[X]](): string =
+    template U: untyped = T
+    result = $U
+    doAssert result == $T
+  doAssert genericStatic[int, 123]() == "123"
+  doAssert genericStatic[Int2, 123]() == "123"
+  doAssert genericStatic[(string, bool), ("a", true)]() == "(\"a\", true)"
+
+block: # issue #13515
+  template test: bool = true
+  # compiles:
+  if not test:
+    doAssert false
+  # does not compile:
+  template x =
+    if not test:
+      doAssert false
+  x
+
+import macros
+
+block: # issue #21727
+  template debugAnnotation(s: typed): string =
+    astToStr s
+
+  macro cpsJump(x: int): untyped =
+    result = newLit(debugAnnotation(cpsJump))
+  
+  doAssert cpsJump(13) == "cpsJump"
diff --git a/tests/template/taliassyntaxerrors.nim b/tests/template/taliassyntaxerrors.nim
new file mode 100644
index 000000000..f16acaf91
--- /dev/null
+++ b/tests/template/taliassyntaxerrors.nim
@@ -0,0 +1,28 @@
+discard """
+  cmd: "nim check --hints:off $file"
+"""
+
+block: # with params
+  type Foo = object
+    bar: int
+
+  var foo = Foo(bar: 10)
+  template bar(x: int): int = x + foo.bar
+  let a = bar #[tt.Error
+      ^ invalid type: 'template (x: int): int' for let. Did you mean to call the template with '()'?]#
+  bar = 15 #[tt.Error
+  ^ 'bar' cannot be assigned to]#
+
+block: # generic template
+  type Foo = object
+    bar: int
+
+  var foo = Foo(bar: 10)
+  template bar[T]: T = T(foo.bar)
+  let a = bar #[tt.Error
+      ^ invalid type: 'template (): T' for let. Did you mean to call the template with '()'?; tt.Error
+          ^ 'bar' has unspecified generic parameters]#
+  let b = bar[float]()
+  doAssert b == 10.0
+  bar = 15 #[tt.Error
+  ^ 'bar' cannot be assigned to]#
diff --git a/tests/template/tcallsitelineinfo.nim b/tests/template/tcallsitelineinfo.nim
new file mode 100644
index 000000000..5fed93363
--- /dev/null
+++ b/tests/template/tcallsitelineinfo.nim
@@ -0,0 +1,17 @@
+discard """
+  nimout: '''
+tcallsitelineinfo.nim(17, 4) Warning: abc [User]
+'''
+  exitcode: 1
+  outputsub: '''
+tcallsitelineinfo.nim(17) tcallsitelineinfo
+Error: unhandled exception: def [ValueError]
+'''
+"""
+
+template foo(): untyped {.callsite.} =
+  {.warning: "abc".}
+  raise newException(ValueError, "def")
+  echo "hello"
+
+foo()
diff --git a/tests/template/tcallsitelineinfo2.nim b/tests/template/tcallsitelineinfo2.nim
new file mode 100644
index 000000000..d5f257474
--- /dev/null
+++ b/tests/template/tcallsitelineinfo2.nim
@@ -0,0 +1,20 @@
+discard """
+  nimout: '''
+tcallsitelineinfo2.nim(18, 1) Warning: abc [User]
+tcallsitelineinfo2.nim(19, 12) Warning: def [User]
+'''
+  exitcode: 1
+  outputsub: '''
+tcallsitelineinfo2.nim(20) tcallsitelineinfo2
+Error: unhandled exception: ghi [ValueError]
+'''
+"""
+
+template foo(a: untyped): untyped {.callsite.} =
+  {.warning: "abc".}
+  a
+  echo "hello"
+
+foo: # with `{.line.}:`, the following do not keep their line information:
+  {.warning: "def".}
+  raise newException(ValueError, "ghi")
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/tdotcall.nim b/tests/template/tdotcall.nim
new file mode 100644
index 000000000..dc97fd52e
--- /dev/null
+++ b/tests/template/tdotcall.nim
@@ -0,0 +1,32 @@
+import mdotcall
+
+block: # issue #20073
+  works()
+  boom()
+
+block: # issue #7085
+  doAssert baz("hello") == "hellobar"
+  doAssert baz"hello" == "hellobar"
+  doAssert "hello".baz == "hellobar"
+
+block: # issue #7223
+  var r = BytesRange(bytes: @[1.byte, 2, 3], ibegin: 0, iend: 2)
+  var a = r.rangeBeginAddr
+
+block: # issue #11733
+  var a: ObjA
+  var evaluated = false
+  a.publicTemplateObjSyntax(42): evaluated = true
+  doAssert evaluated
+
+block: # issue #15246
+  doAssert sourceBaseName() == "tdotcall"
+
+block: # issue #12683
+  heh(0..40, "|")
+
+block: # issue #7889
+  if false:
+    bindmeQuote()
+  if false:
+    bindmeTemplate()
diff --git a/tests/template/template_issues.nim b/tests/template/template_issues.nim
index 502c6d1ee..58c40941d 100644
--- a/tests/template/template_issues.nim
+++ b/tests/template/template_issues.nim
@@ -173,7 +173,7 @@ block t2585:
       st
       echo "a ", $fb
 
-  proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2;
+  proc render(rdat: var RenderData; passes: var openArray[RenderPass]; proj: Mat2;
               indexType = 1) =
       for i in 0 ..< len(passes):
           echo "blah ", repr(passes[i])
@@ -296,3 +296,9 @@ block: # bug #12595
     discard {i: ""}
 
   test()
+
+block: # bug #21920
+  template t[T](): T =
+    discard
+
+  t[void]() # Error: expression has no type: discard
diff --git a/tests/template/template_pragmas.nim b/tests/template/template_pragmas.nim
index d6c99080d..da532b010 100644
--- a/tests/template/template_pragmas.nim
+++ b/tests/template/template_pragmas.nim
@@ -3,7 +3,7 @@ proc output_x:string {.compileTime.} = "x"
 template t =
   const x = output_x()
   let
-    bar {.exportC:"bar" & x.} = 100
+    bar {.exportc:"bar" & x.} = 100
 
 static:
   doAssert(compiles (t()))
diff --git a/tests/template/template_various.nim b/tests/template/template_various.nim
index 75226ea2d..2088b1739 100644
--- a/tests/template/template_various.nim
+++ b/tests/template/template_various.nim
@@ -94,7 +94,7 @@ block generic_templates:
 
   var i3: int = t1[int]("xx")
 
-
+from strutils import contains
 
 block tgetast_typeliar:
   proc error(s: string) = quit s
@@ -111,7 +111,9 @@ block tgetast_typeliar:
     var message : NimNode = newLit(condition.repr)
     # echo message
     result = getAst assertOrReturn2(condition, message)
-    echo result.repr
+    # echo result.repr
+    let s = result.repr
+    doAssert """error("Assertion failed:""" in s
 
   proc point(size: int16): tuple[x, y: int16] =
     # returns random point in square area with given `size`
@@ -272,10 +274,10 @@ parse9:
 block gensym1:
   template x: untyped = -1
   template t1() =
-    template x: untyped {.gensym.} = 1
+    template x: untyped {.gensym, redefine.} = 1
     echo x()  # 1
   template t2() =
-    template x: untyped = 1  # defaults to {.inject.}
+    template x: untyped {.redefine.} = 1  # defaults to {.inject.}
     echo x()  # -1  injected x not available during template definition
   t1()
   t2()
@@ -351,3 +353,54 @@ block gensym3:
   echo a ! b ! c ! d
   echo a ! b ! c ! d ! e
   echo x,y,z
+
+block: # issue #2465
+  template t() =
+    template declX(str: string) {.gensym.} =
+      var x {.inject.} : string = str
+
+  t()
+  doAssert not declared(declX)
+  doAssert not compiles(declX("a string"))
+
+  template t2() =
+    template fooGensym() {.gensym.} =
+      echo 42
+
+  t2()
+  doAssert not declared(fooGensym)
+  doAssert not compiles(fooGensym())
+
+
+block identifier_construction_with_overridden_symbol:
+  # could use add, but wanna make sure it's an override no matter what
+  func examplefn = discard
+  func examplefn(x: int) = discard
+
+  # the function our template wants to use
+  func examplefn1 = discard
+
+  template exampletempl(n) =
+    # attempt to build a name using the overridden symbol "examplefn"
+    `examplefn n`()
+
+  exampletempl(1)
+
+import typetraits
+
+block: # issue #4596
+  type
+    T0 = object
+    T1 = object
+
+  template printFuncsT() =
+    proc getV[A](a: typedesc[A]): string =
+      var s {. global .} = name(A)
+      return s
+
+  printFuncsT()
+
+  doAssert getV(T1) == "T1"
+  doAssert getV(T0) == "T0"
+  doAssert getV(T0) == "T0"
+  doAssert getV(T1) == "T1"
diff --git a/tests/template/tgenericparam.nim b/tests/template/tgenericparam.nim
new file mode 100644
index 000000000..becf75d36
--- /dev/null
+++ b/tests/template/tgenericparam.nim
@@ -0,0 +1,93 @@
+block: # basic template generic parameter substitution
+  block: # issue #13527
+    template typeNameTempl[T](a: T): string = $T
+    proc typeNameProc[T](a: T): string = $T
+    doAssert typeNameTempl(1) == typeNameProc(1)
+    doAssert typeNameTempl(true) == typeNameProc(true)
+    doAssert typeNameTempl(1.0) == typeNameProc(1.0)
+    doAssert typeNameTempl(1u8) == typeNameProc(1u8)
+
+    template isDefault[T](a: T): bool = a == default(T)
+    doAssert isDefault(0.0)
+
+  block: # issue #17240
+    func to(c: int, t: typedesc[float]): t = discard
+    template converted[I, T](i: seq[I], t: typedesc[T]): seq[T] =
+      var result = newSeq[T](2)
+      result[0] = i[0].to(T)
+      result
+    doAssert newSeq[int](3).converted(float) == @[0.0, 0.0]
+
+  block: # issue #6340
+    type A[T] = object
+      v: T
+    proc foo(x: int): string = "int"
+    proc foo(x: typedesc[int]): string = "typedesc[int]"
+    template fooT(x: int): string = "int"
+    template fooT(x: typedesc[int]): string = "typedesc[int]"
+    proc foo[T](x: A[T]): (string, string) =
+      (foo(T), fooT(T))
+    template fooT[T](x: A[T]): (string, string) =
+      (foo(T), fooT(T))
+    var x: A[int]
+    doAssert foo(x) == fooT(x)
+
+  block: # issue #20033
+    template run[T](): T = default(T)
+    doAssert run[int]() == 0
+
+import options, tables, typetraits
+
+block: # complex cases of above with imports
+  block: # issue #19576, complex case
+    type RegistryKey = object
+      key, val: string
+    var regKey = @[RegistryKey(key: "abc", val: "def")]
+    template findFirst[T](s: seq[T], pred: proc(x: T): bool): Option[T] =
+      var res = none(T) # important line
+      for x in s:
+        if pred(x):
+          res = some(x)
+          break
+      res
+    proc getval(searchKey: string): Option[string] =
+      let found = regKey.findFirst(proc (rk: RegistryKey): bool = rk.key == searchKey)
+      if found.isNone: none(string)
+      else: some(found.get().val)
+    doAssert getval("strange") == none(string)
+    doAssert getval("abc") == some("def")
+  block: # issue #19076
+    block: # case 1
+      var tested: Table[string,int]
+      template `[]`[V](t:Table[string,V],key:string):untyped =
+        $V
+      doAssert tested["abc"] == "int"
+      template `{}`[V](t:Table[string,V],key:string):untyped =
+        ($V, tables.`[]`(t, key))
+      doAssert (try: tested{"abc"} except KeyError: ("not there", 123)) == ("not there", 123)
+      tables.`[]=`(tested, "abc", 456)
+      doAssert tested["abc"] == "int"
+      doAssert tested{"abc"} == ("int", 456)
+    block: # case 2
+      type Foo[A,T] = object
+        t:T
+      proc init[A,T](f:type Foo,a:typedesc[A],t:T):Foo[A,T] = Foo[A,T](t:t)
+      template fromOption[A](o:Option[A]):auto =
+        when o.isSome:
+          Foo.init(A,35)
+        else:
+          Foo.init(A,"hi")
+      let op = fromOption(some(5))
+  block: # issue #7461
+    template p[T](): untyped = none(T)
+    doAssert p[int]() == none(int)
+  block: # issue #7995
+    var res: string
+    template copyRange[T](dest: seq[T], destOffset: int) =
+      when supportsCopyMem(T):
+        res = "A"
+      else:    
+        res = "B"
+    var a = @[1, 2, 3]
+    copyRange(a, 0)
+    doAssert res == "A"
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/tidentconcatenations.nim b/tests/template/tidentconcatenations.nim
new file mode 100644
index 000000000..ddd2e49cc
--- /dev/null
+++ b/tests/template/tidentconcatenations.nim
@@ -0,0 +1,31 @@
+type
+  Hash*[bits: static[int]] = object
+    data*: array[bits div 8, uint8]
+
+{.emit: """
+
+void sha_256(void* input, int input_len, void* output, int output_len) {}
+void sha_512(void* input, int input_len, void* output, int output_len) {}
+
+void keccak_256(void* input, int input_len, void* output, int output_len) {}
+void keccak_512(void* input, int input_len, void* output, int output_len) {}
+
+""".}
+
+template defineKeccak(bits: untyped) =
+  proc `extKeccak bits`(output: pointer, outSize: csize_t, input: pointer, inputSize: csize_t) {.nodecl, importc: "keccak_" & astToStr(bits).}
+
+template defineSha(bits: static[int]) =
+  proc `extSha bits`(output: pointer, outSize: csize_t, input: pointer, inputSize: csize_t) {.nodecl, importc: "sha_" & astToStr(bits).}
+
+template defineHashProcs(bits) =
+  defineSha(bits)
+  defineKeccak(bits)
+
+defineHashProcs(256)
+defineHashProcs(512)
+
+extSha256(nil, 0, nil, 0)
+extSha512(nil, 0, nil, 0)
+extKeccak256(nil, 0, nil, 0)
+extKeccak512(nil, 0, nil, 0)
diff --git a/tests/template/tinnerouterproc.nim b/tests/template/tinnerouterproc.nim
new file mode 100644
index 000000000..56e0d02df
--- /dev/null
+++ b/tests/template/tinnerouterproc.nim
@@ -0,0 +1,20 @@
+block: # #20002
+  proc bar(x: int): int = 10
+  template foo =
+    proc bar(x: int): int {.gensym.} = x + 2
+    doAssert bar(3) == 5
+    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/tmodulealias.nim b/tests/template/tmodulealias.nim
index 6681379fb..79b5ec9c6 100644
--- a/tests/template/tmodulealias.nim
+++ b/tests/template/tmodulealias.nim
@@ -7,7 +7,7 @@ when defined(windows):
 else:
   import posix
 
-when defined(Windows):
+when defined(windows):
   template orig: expr =
     winlean
 else:
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/tobjectdeclfield.nim b/tests/template/tobjectdeclfield.nim
new file mode 100644
index 000000000..afce2cae8
--- /dev/null
+++ b/tests/template/tobjectdeclfield.nim
@@ -0,0 +1,21 @@
+block: # issue #16005
+  var x = 0
+
+  block:
+    type Foo = object
+      x: float # ok
+
+  template main() =
+    block:
+      type Foo = object
+        x: float # Error: cannot use symbol of kind 'var' as a 'field'
+
+  main()
+
+block: # issue #19552
+  template test =
+    type
+      test2 = ref object
+        reset: int
+
+  test()
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 1444667f4..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
@@ -72,7 +73,7 @@ proc concreteProc(x: int) =
   forStatic i, 0..3:
     echo i
 
-proc genericProc(x: any) =
+proc genericProc(x: auto) =
   forStatic i, 0..3:
     echo i
 
@@ -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/tqualifiedident.nim b/tests/template/tqualifiedident.nim
new file mode 100644
index 000000000..463b14ee7
--- /dev/null
+++ b/tests/template/tqualifiedident.nim
@@ -0,0 +1,8 @@
+block: # issue #19865
+  template f() = discard default(system.int)
+  f()
+
+# issue #21221, same as above
+type M = object
+template r() = discard default(tqualifiedident.M)
+r()
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)
diff --git a/tests/template/tredefinition_override.nim b/tests/template/tredefinition_override.nim
new file mode 100644
index 000000000..7ae232bba
--- /dev/null
+++ b/tests/template/tredefinition_override.nim
@@ -0,0 +1,33 @@
+{.push warningAsError[ImplicitTemplateRedefinition]: on.}
+
+doAssert not (compiles do:
+  template foo(): int = 1
+  template foo(): int = 2)
+doAssert (compiles do:
+  template foo(): int = 1
+  template foo(): int {.redefine.} = 2)
+doAssert not (compiles do:
+  block:
+    template foo() =
+      template bar: string {.gensym.} = "a"
+      template bar: string {.gensym.} = "b"
+    foo())
+doAssert (compiles do:
+  block:
+    template foo() =
+      template bar: string {.gensym.} = "a"
+      template bar: string {.gensym, redefine.} = "b"
+    foo())
+
+block:
+  template foo(): int = 1
+  template foo(): int {.redefine.} = 2
+  doAssert foo() == 2
+block:
+  template foo(): string =
+    template bar: string {.gensym.} = "a"
+    template bar: string {.gensym, redefine.} = "b"
+    bar()
+  doAssert foo() == "b"
+
+{.pop.}
diff --git a/tests/template/tunderscore1.nim b/tests/template/tunderscore1.nim
new file mode 100644
index 000000000..d74e5ba63
--- /dev/null
+++ b/tests/template/tunderscore1.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "the special identifier '_' is ignored in declarations and cannot be used"
+"""
+
+# issue #12094, #13804
+
+template foo =
+  let _ = 1
+  echo _
+
+foo()
diff --git a/tests/template/twrongmapit.nim b/tests/template/twrongmapit.nim
index 5b8663cf9..2d53d03f5 100644
--- a/tests/template/twrongmapit.nim
+++ b/tests/template/twrongmapit.nim
@@ -1,8 +1,6 @@
 discard """
-  output: "####"
+  joinable: false
 """
-# unfortunately our tester doesn't support multiple lines of compiler
-# error messages yet...
 
 # bug #1562
 type Foo* {.pure, final.} = object
@@ -29,4 +27,4 @@ import sequtils
 
 (var i = @[""];i).applyIt(it)
 # now works:
-echo "##", i[0], "##"
+doAssert i[0] == ""
diff --git a/tests/template/utemplates.nim b/tests/template/utemplates.nim
index 7674ba7c0..d70746578 100644
--- a/tests/template/utemplates.nim
+++ b/tests/template/utemplates.nim
@@ -22,7 +22,7 @@ block: # templates can be redefined multiple times
     if not cond: fail(msg)
 
   template assertionFailed(body: untyped) {.dirty.} =
-    template fail(msg: string): typed =
+    template fail(msg: string): typed {.redefine.} =
       body
 
   assertionFailed: