summary refs log tree commit diff stats
path: root/tests/macros
diff options
context:
space:
mode:
Diffstat (limited to 'tests/macros')
-rw-r--r--tests/macros/m18235.nim42
-rw-r--r--tests/macros/mparsefile.nim4
-rw-r--r--tests/macros/t14227.nim23
-rw-r--r--tests/macros/t14329.nim4
-rw-r--r--tests/macros/t14511.nim54
-rw-r--r--tests/macros/t14847.nim20
-rw-r--r--tests/macros/t15691.nim22
-rw-r--r--tests/macros/t15751.nim11
-rw-r--r--tests/macros/t16758.nim38
-rw-r--r--tests/macros/t17836.nim15
-rw-r--r--tests/macros/t18203.nim15
-rw-r--r--tests/macros/t18235.nim18
-rw-r--r--tests/macros/t19766_20114.nim16
-rw-r--r--tests/macros/t20067.nim28
-rw-r--r--tests/macros/t20435.nim30
-rw-r--r--tests/macros/t21593.nim13
-rw-r--r--tests/macros/t23032_1.nim19
-rw-r--r--tests/macros/t23032_2.nim20
-rw-r--r--tests/macros/t23547.nim23
-rw-r--r--tests/macros/t23784.nim157
-rw-r--r--tests/macros/t7875.nim22
-rw-r--r--tests/macros/tastrepr.nim17
-rw-r--r--tests/macros/tcasestmtmacro.nim33
-rw-r--r--tests/macros/tclosuremacro.nim15
-rw-r--r--tests/macros/tdumpast.nim153
-rw-r--r--tests/macros/tfail_parse.nim15
-rw-r--r--tests/macros/tforloop_macro1.nim2
-rw-r--r--tests/macros/tgetimpl.nim46
-rw-r--r--tests/macros/tgetraiseslist.nim29
-rw-r--r--tests/macros/tgettype.nim100
-rw-r--r--tests/macros/tgettypeinst.nim4
-rw-r--r--tests/macros/tgettypeinst7737.nim61
-rw-r--r--tests/macros/tmacro2.nim8
-rw-r--r--tests/macros/tmacrogetimpl.nim31
-rw-r--r--tests/macros/tmacros1.nim19
-rw-r--r--tests/macros/tmacros_issues.nim277
-rw-r--r--tests/macros/tmacros_various.nim189
-rw-r--r--tests/macros/tmacrostmt.nim2
-rw-r--r--tests/macros/tmacrotypes.nim8
-rw-r--r--tests/macros/tmemit.nim3
-rw-r--r--tests/macros/tparsefile.nim11
-rw-r--r--tests/macros/tprocgettype.nim28
-rw-r--r--tests/macros/tprochelpers.nim22
-rw-r--r--tests/macros/tstaticparamsmacro.nim4
-rw-r--r--tests/macros/tstructuredlogging.nim6
-rw-r--r--tests/macros/ttemplatesymbols.nim2
-rw-r--r--tests/macros/ttryparseexpr.nim4
-rw-r--r--tests/macros/ttypenodes.nim16
-rw-r--r--tests/macros/tvtable.nim2
49 files changed, 1628 insertions, 73 deletions
diff --git a/tests/macros/m18235.nim b/tests/macros/m18235.nim
new file mode 100644
index 000000000..6bb4547e0
--- /dev/null
+++ b/tests/macros/m18235.nim
@@ -0,0 +1,42 @@
+import macros
+
+# Necessary code to update the AST on a symbol across module boundaries when
+# processed by a type macro. Used by a test of a corresponding name of this
+# file.
+
+macro eexport(n: typed): untyped =
+  result = copyNimTree(n)
+  # turn exported nnkSym -> nnkPostfix(*, nnkIdent), forcing re-sem
+  result[0] = nnkPostfix.newTree(ident"*").add:
+    n.name.strVal.ident
+
+macro unexport(n: typed): untyped =
+  result = copyNimTree(n)
+  # turn nnkSym -> nnkIdent, forcing re-sem and dropping any exported-ness
+  # that might be present
+  result[0] = n.name.strVal.ident
+
+proc foo*() {.unexport.} = discard
+proc bar() {.eexport.} = discard
+
+proc foooof*() {.unexport, eexport, unexport.} = discard
+proc barrab() {.eexport, unexport, eexport.} = discard
+
+macro eexportMulti(n: typed): untyped =
+  # use the call version of `eexport` macro for one or more decls
+  result = copyNimTree(n)
+  for i in 0..<result.len:
+    result[i] = newCall(ident"eexport", result[i])
+
+macro unexportMulti(n: typed): untyped =
+  # use the call version of `unexport` macro for one or more decls
+  result = copyNimTree(n)
+  for i in 0..<result.len:
+    result[i] = newCall(ident"unexport", result[i])
+
+unexportMulti:
+  proc oof*() = discard
+
+eexportMulti:
+  proc rab() = discard
+  proc baz*() = discard
\ No newline at end of file
diff --git a/tests/macros/mparsefile.nim b/tests/macros/mparsefile.nim
new file mode 100644
index 000000000..8ac99d568
--- /dev/null
+++ b/tests/macros/mparsefile.nim
@@ -0,0 +1,4 @@
+let a = 1
+let b = 2
+let c =
+let d = 4
diff --git a/tests/macros/t14227.nim b/tests/macros/t14227.nim
new file mode 100644
index 000000000..4206e2c06
--- /dev/null
+++ b/tests/macros/t14227.nim
@@ -0,0 +1,23 @@
+discard """
+  action: "compile"
+"""
+import sugar
+
+
+block:
+  let y = @[@[1, 2], @[2, 4, 6]]
+  let x = collect(newSeq):
+    for i in y:
+      if i.len > 2:
+        for j in i:
+          j
+  echo(x)
+
+block:
+  let y = @[@[1, 2], @[2, 4, 6]]
+  let x = collect(newSeq):
+    for i in y:
+      for j in i:
+        if i.len > 2:
+          j
+  echo(x)
diff --git a/tests/macros/t14329.nim b/tests/macros/t14329.nim
new file mode 100644
index 000000000..b5606424a
--- /dev/null
+++ b/tests/macros/t14329.nim
@@ -0,0 +1,4 @@
+import macros
+
+macro myMacro(n) =
+  let x = if true: newLit"test" else: error "error", n
diff --git a/tests/macros/t14511.nim b/tests/macros/t14511.nim
new file mode 100644
index 000000000..f3b1e2894
--- /dev/null
+++ b/tests/macros/t14511.nim
@@ -0,0 +1,54 @@
+discard """
+  output: "true\n(y: XInt, a: 5)\n(y: XString, b: \"abc\")"
+"""
+
+import macros
+
+block TEST_1:
+  # https://github.com/nim-lang/Nim/issues/14511
+
+  template myPragma() {.pragma.}
+
+  type
+    XType = enum
+      XInt,
+      XString,
+      XUnused
+    X = object
+      case y {.myPragma.}: XType
+        of XInt, XUnused:
+          a: int
+        else: # <-- Else case caused the "Error: index 1 not in 0 .. 0" error
+          b: string
+
+  var x: X = X(y: XInt, a: 5)
+  echo x.y.hasCustomPragma(myPragma)
+  echo x
+  echo X(y: XString, b: "abc")
+
+
+block TEST_2:
+  template myDevice(val: string) {.pragma.}
+  template myKey(val: string) {.pragma.}
+  template myMouse(val: string) {.pragma.}
+
+  type
+    Device {.pure.} = enum Keyboard, Mouse
+    Key = enum Key1, Key2
+    Mouse = enum Mouse1, Mouse2
+
+  type
+    Obj = object of RootObj
+      case device {.myDevice: "MyDevicePragmaStr".}: Device
+      of Device.Keyboard:
+        key {.myKey: "MyKeyPragmaStr".}: Key
+      else: # <-- Else case caused the "Error: index 1 not in 0 .. 0" error
+        mouse {.myMouse: "MyMousePragmaStr".}: Mouse
+
+  var obj: Obj
+  assert obj.device.hasCustomPragma(myDevice) == true
+  assert obj.key.hasCustomPragma(myKey) == true
+  assert obj.mouse.hasCustomPragma(myMouse) == true
+  assert obj.device.getCustomPragmaVal(myDevice) == "MyDevicePragmaStr"
+  assert obj.key.getCustomPragmaVal(myKey) == "MyKeyPragmaStr"
+  assert obj.mouse.getCustomPragmaVal(myMouse) == "MyMousePragmaStr"
\ No newline at end of file
diff --git a/tests/macros/t14847.nim b/tests/macros/t14847.nim
new file mode 100644
index 000000000..0e6d0dd2d
--- /dev/null
+++ b/tests/macros/t14847.nim
@@ -0,0 +1,20 @@
+discard """
+  output: "98"
+"""
+import macros
+
+#bug #14847
+proc hello*(b: string) =
+  echo b
+
+macro dispatch(pro: typed, params: untyped): untyped =
+  var impl = pro.getImpl
+  let id = ident(pro.strVal & "_coverage")
+  impl[0] = id
+  let call = newCall(id, params)
+
+  result = newStmtList()
+  result.add(impl)
+  result.add(call)
+
+dispatch(hello, "98")
diff --git a/tests/macros/t15691.nim b/tests/macros/t15691.nim
new file mode 100644
index 000000000..c1e8a8648
--- /dev/null
+++ b/tests/macros/t15691.nim
@@ -0,0 +1,22 @@
+discard """
+  action: compile
+"""
+
+import std/macros
+
+macro simplifiedExpandMacros(body: typed): untyped =
+  result = body
+
+simplifiedExpandMacros:
+  proc testProc() = discard
+
+simplifiedExpandMacros:
+  template testTemplate(): untyped = discard
+
+# Error: illformed AST: macro testMacro(): untyped =
+simplifiedExpandMacros:
+  macro testMacro(): untyped = discard
+
+# Error: illformed AST: converter testConverter(x: int): float =
+simplifiedExpandMacros:
+  converter testConverter(x: int): float = discard
diff --git a/tests/macros/t15751.nim b/tests/macros/t15751.nim
new file mode 100644
index 000000000..fcabb2f9e
--- /dev/null
+++ b/tests/macros/t15751.nim
@@ -0,0 +1,11 @@
+discard """
+  cmd: "nim c --hints:off $file"
+  nimout: "out"
+"""
+
+# bug #15751
+macro print(n: untyped): untyped =
+  echo n.repr
+
+print:
+  out
diff --git a/tests/macros/t16758.nim b/tests/macros/t16758.nim
new file mode 100644
index 000000000..66b6d42c5
--- /dev/null
+++ b/tests/macros/t16758.nim
@@ -0,0 +1,38 @@
+discard """

+errormsg: "'blk.p(a)' has nil child at index 1"

+action: reject

+"""

+import macros

+

+type BlockLiteral[T] = object

+  p: T

+

+proc p[T](a:int) = echo 1

+proc p[T](a:string) = echo "a"

+

+iterator arguments(formalParams: NimNode): NimNode =

+  var iParam = 0

+  for i in 1 ..< formalParams.len:

+    let pp = formalParams[i]

+    for j in 0 .. pp.len - 3:

+      yield pp[j]

+      inc iParam

+

+macro implementInvoke(T: typedesc): untyped =

+  let t = getTypeImpl(T)[1]

+

+  let call = newCall(newDotExpr(ident"blk", ident"p"))

+  let params = copyNimTree(t[0])

+  result = newProc(ident"invoke", body = call)

+  # result[2] = newTree(nnkGenericParams,T)

+  for n in arguments(params):

+    call.add(n)

+  

+  params.insert(1, newIdentDefs(ident"blk", newTree(nnkBracketExpr, bindSym"BlockLiteral", T)))

+  result.params = params

+

+proc getInvoke(T: typedesc) =

+  implementInvoke(T)

+

+

+getInvoke(proc(a: int))

diff --git a/tests/macros/t17836.nim b/tests/macros/t17836.nim
new file mode 100644
index 000000000..2453637f5
--- /dev/null
+++ b/tests/macros/t17836.nim
@@ -0,0 +1,15 @@
+import macros
+
+# Ensure that `isNil` works in the typed macro context when pass procs.
+
+type
+  O = object
+    fn: proc(i: int): int
+
+var o: O
+
+macro typedBug(expr: typed) =
+  doAssert expr[1] != nil
+  doAssert not expr[1].isNil
+
+typedBug(o.fn)
\ No newline at end of file
diff --git a/tests/macros/t18203.nim b/tests/macros/t18203.nim
new file mode 100644
index 000000000..aae0a2690
--- /dev/null
+++ b/tests/macros/t18203.nim
@@ -0,0 +1,15 @@
+discard """
+  matrix: "--hint:SuccessX:off --hint:Link:off --hint:Conf:off --hint:CC:off --hint:XDeclaredButNotUsed:on"
+  nimout: '''
+'''
+nimoutFull: true
+action: compile
+"""
+
+# bug #18203
+import std/macros
+
+macro foo(x: typed) = newProc ident"bar"
+proc bar() {.foo.} = raise
+bar()
+
diff --git a/tests/macros/t18235.nim b/tests/macros/t18235.nim
new file mode 100644
index 000000000..ba5c48a24
--- /dev/null
+++ b/tests/macros/t18235.nim
@@ -0,0 +1,18 @@
+import m18235
+
+# this must error out because it was never actually exported
+doAssert(not declared(foo))
+doAssert not compiles(foo())
+
+doAssert(not declared(foooof))
+doAssert not compiles(foooof())
+
+doAssert(not declared(oof))
+doAssert not compiles(oof())
+
+# this should have been exported just fine
+
+bar()
+barrab()
+rab()
+baz()
\ No newline at end of file
diff --git a/tests/macros/t19766_20114.nim b/tests/macros/t19766_20114.nim
new file mode 100644
index 000000000..ac336f150
--- /dev/null
+++ b/tests/macros/t19766_20114.nim
@@ -0,0 +1,16 @@
+discard """
+  action: compile
+  nimout: '''
+const
+  foo {.strdefine.} = "abc"
+let hey {.tddd.} = 5
+'''
+"""
+
+import macros
+
+template tddd {.pragma.}
+
+expandMacros:
+  const foo {.strdefine.} = "abc"
+  let hey {.tddd.} = 5
diff --git a/tests/macros/t20067.nim b/tests/macros/t20067.nim
new file mode 100644
index 000000000..0ee3a4712
--- /dev/null
+++ b/tests/macros/t20067.nim
@@ -0,0 +1,28 @@
+discard """
+  output: '''
+b.defaultVal = foo
+$c.defaultVal = bar
+'''
+"""
+
+import macros
+
+# #18976
+
+macro getString(identifier): string =
+  result = newLit($identifier)
+doAssert getString(abc) == "abc"
+doAssert getString(`a b c`) == "abc"
+
+# #20067
+
+template defaultVal*(value : typed) {.pragma.}
+
+type A = ref object
+  b {.defaultVal: "foo".}: string
+  `$c` {.defaultVal: "bar".}: string
+
+let a = A(b: "a", `$c`: "b")
+
+echo "b.defaultVal = " & a.b.getCustomPragmaVal(defaultVal)
+echo "$c.defaultVal = " & a.`$c`.getCustomPragmaVal(defaultVal)
diff --git a/tests/macros/t20435.nim b/tests/macros/t20435.nim
new file mode 100644
index 000000000..824282198
--- /dev/null
+++ b/tests/macros/t20435.nim
@@ -0,0 +1,30 @@
+
+#[
+  A better test requires matching, so the use of @ working can be showcased
+  For example:
+
+  proc regularCase[T]() = 
+    case [(1, 3), (3, 4)]:
+    of [(1, @a), (_, @b)]:
+      echo a, b
+    else: discard
+]#
+
+{.experimental: "caseStmtMacros".}
+
+import macros
+
+type Foo = object
+
+macro `case`(obj: Foo) = quote do: discard
+
+proc notGeneric() =
+  case Foo()
+  of a b c d: discard
+
+proc generic[T]() =
+  case Foo()
+  of a b c d: discard
+
+notGeneric()
+generic[int]()
diff --git a/tests/macros/t21593.nim b/tests/macros/t21593.nim
new file mode 100644
index 000000000..b0b7ebe75
--- /dev/null
+++ b/tests/macros/t21593.nim
@@ -0,0 +1,13 @@
+discard """
+nimout: '''
+StmtList
+  UIntLit 18446744073709551615
+  IntLit -1'''
+"""
+
+import macros
+
+dumpTree:
+  0xFFFFFFFF_FFFFFFFF'u
+  0xFFFFFFFF_FFFFFFFF
+
diff --git a/tests/macros/t23032_1.nim b/tests/macros/t23032_1.nim
new file mode 100644
index 000000000..4e1707414
--- /dev/null
+++ b/tests/macros/t23032_1.nim
@@ -0,0 +1,19 @@
+import std/macros
+
+type A[T, H] = object
+
+proc `%*`(a: A): bool = true
+proc `%*`[T](a: A[int, T]): bool = false
+
+macro collapse(s: untyped) =
+  result = newStmtList()
+  result.add quote do:
+    doAssert(`s`(A[float, int]()) == true)
+
+macro startHere(n: untyped): untyped =
+  result = newStmtList()
+  let s = n[0]
+  result.add quote do:
+    `s`.collapse()
+
+startHere(`a` %* `b`)
diff --git a/tests/macros/t23032_2.nim b/tests/macros/t23032_2.nim
new file mode 100644
index 000000000..8dde29e10
--- /dev/null
+++ b/tests/macros/t23032_2.nim
@@ -0,0 +1,20 @@
+discard """
+  action: "reject"
+  errormsg: "ambiguous identifier: '%*'"
+"""
+import std/macros
+
+type A[T, H] = object
+
+proc `%*`[T](a: A) = discard
+proc `%*`[T](a: A[int, T]) = discard
+
+macro collapse(s: typed) = discard
+
+macro startHere(n: untyped): untyped =
+  result = newStmtList()
+  let s = n[0]
+  result.add quote do:
+    collapse(`s`.typeof())
+
+startHere(`a` %* `b`)
diff --git a/tests/macros/t23547.nim b/tests/macros/t23547.nim
new file mode 100644
index 000000000..9a2bff9ff
--- /dev/null
+++ b/tests/macros/t23547.nim
@@ -0,0 +1,23 @@
+# https://github.com/nim-lang/Nim/issues/23547
+
+type
+  A[T] = object
+    x: T
+
+proc mulCheckSparse[F](dummy: var A[F], xmulchecksparse: static A[F]) =
+  static:
+    echo "mulCheckSparse: ", typeof(dummy), ", ", typeof(xmulchecksparse) # when generic params not specified: A[system.int], A
+
+template sumImpl(xsumimpl: typed) =
+  static:
+    echo "sumImpl: ", typeof(xsumimpl) # A
+  var a = A[int](x: 55)
+  mulCheckSparse(a, xsumimpl) # fails here
+
+proc sum[T](xsum: static T) =
+  static:
+    echo "sum: ", typeof(xsum) # A[system.int]
+  sumImpl(xsum)
+
+const constA = A[int](x : 100)
+sum[A[int]](constA)
diff --git a/tests/macros/t23784.nim b/tests/macros/t23784.nim
new file mode 100644
index 000000000..31b4544c6
--- /dev/null
+++ b/tests/macros/t23784.nim
@@ -0,0 +1,157 @@
+discard """
+  joinable: false
+"""
+
+
+# debug ICE: genCheckedRecordField
+# apparently after https://github.com/nim-lang/Nim/pull/23477
+
+# bug #23784
+
+import std/bitops, std/macros
+
+# --------------------------------------------------------------
+
+type Algebra = enum
+  BN254_Snarks
+
+type SecretWord* = distinct uint64
+const WordBitWidth* = sizeof(SecretWord) * 8
+
+func wordsRequired*(bits: int): int {.inline.} =
+  const divShiftor = fastLog2(WordBitWidth)
+  result = (bits + WordBitWidth - 1) shr divShiftor
+
+type
+  BigInt*[bits: static int] = object
+    limbs*: array[bits.wordsRequired, SecretWord]  # <--- crash points to here
+
+# --------------------------------------------------------------
+
+const CurveBitWidth = [
+  BN254_Snarks: 254
+]
+
+const BN254_Snarks_Modulus = BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x2, SecretWord 0x3, SecretWord 0x4])
+const BN254_Snarks_Order = BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x1, SecretWord 0x2, SecretWord 0x2])
+
+func montyOne*(M: BigInt[254]): BigInt[254] =
+  ## Returns "1 (mod M)" in the Montgomery domain.
+  ## This is equivalent to R (mod M) in the natural domain
+  BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x1, SecretWord 0x1, SecretWord 0x1])
+
+
+{.experimental: "dynamicBindSym".}
+
+type
+  DerivedConstantMode* = enum
+    kModulus
+    kOrder
+
+macro genDerivedConstants*(mode: static DerivedConstantMode): untyped =
+  ## Generate constants derived from the main constants
+  ##
+  ## For example
+  ## - the Montgomery magic constant "R^2 mod N" in ROM
+  ##   For each curve under the private symbol "MyCurve_R2modP"
+  ## - the Montgomery magic constant -1/P mod 2^Wordbitwidth
+  ##   For each curve under the private symbol "MyCurve_NegInvModWord
+  ## - ...
+
+  # Now typedesc are NimNode and there is no way to translate
+  # NimNode -> typedesc easily so we can't
+  # "for curve in low(Curve) .. high(Curve):"
+  # As an ugly workaround, we count
+  # The item at position 0 is a pragma
+  result = newStmtList()
+
+  template used(name: string): NimNode =
+    nnkPragmaExpr.newTree(
+      ident(name),
+      nnkPragma.newTree(ident"used")
+    )
+
+  let ff = if mode == kModulus: "_Fp" else: "_Fr"
+
+  for curveSym in low(Algebra) .. high(Algebra):
+    let curve = $curveSym
+    let M = if mode == kModulus: bindSym(curve & "_Modulus")
+            else: bindSym(curve & "_Order")
+
+    # const MyCurve_montyOne = montyOne(MyCurve_Modulus)
+    result.add newConstStmt(
+      used(curve & ff & "_MontyOne"), newCall(
+        bindSym"montyOne",
+        M
+      )
+    )
+
+# --------------------------------------------------------------
+
+{.experimental: "dynamicBindSym".}
+
+genDerivedConstants(kModulus)
+genDerivedConstants(kOrder)
+
+proc bindConstant(ff: NimNode, property: string): NimNode =
+  # Need to workaround https://github.com/nim-lang/Nim/issues/14021
+  # which prevents checking if a type FF[Name] = Fp[Name] or Fr[Name]
+  # was instantiated with Fp or Fr.
+  # getTypeInst only returns FF and sameType doesn't work.
+  # so quote do + when checks.
+  let T = getTypeInst(ff)
+  T.expectKind(nnkBracketExpr)
+  doAssert T[0].eqIdent("typedesc")
+
+  let curve =
+    if T[1].kind == nnkBracketExpr: # typedesc[Fp[BLS12_381]] as used internally
+      # doAssert T[1][0].eqIdent"Fp" or T[1][0].eqIdent"Fr", "Found ident: '" & $T[1][0] & "' instead of 'Fp' or 'Fr'"
+      T[1][1].expectKind(nnkIntLit) # static enum are ints in the VM
+      $Algebra(T[1][1].intVal)
+    else: # typedesc[bls12381_fp] alias as used for C exports
+      let T1 = getTypeInst(T[1].getImpl()[2])
+      if T1.kind != nnkBracketExpr or
+         T1[1].kind != nnkIntLit:
+        echo T.repr()
+        echo T1.repr()
+        echo getTypeInst(T1).treerepr()
+        error "getTypeInst didn't return the full instantiation." &
+          " Dealing with types in macros is hard, complain at https://github.com/nim-lang/RFCs/issues/44"
+      $Algebra(T1[1].intVal)
+
+  let curve_fp = bindSym(curve & "_Fp_" & property)
+  let curve_fr = bindSym(curve & "_Fr_" & property)
+  result = quote do:
+    when `ff` is Fp:
+      `curve_fp`
+    elif `ff` is Fr:
+      `curve_fr`
+    else:
+      {.error: "Unreachable, received type: " & $`ff`.}
+
+# --------------------------------------------------------------
+
+template matchingBigInt*(Name: static Algebra): untyped =
+  ## BigInt type necessary to store the prime field Fp
+  # Workaround: https://github.com/nim-lang/Nim/issues/16774
+  # as we cannot do array accesses in type section.
+  # Due to generic sandwiches, it must be exported.
+  BigInt[CurveBitWidth[Name]]
+
+type
+  Fp*[Name: static Algebra] = object
+    mres*: matchingBigInt(Name)
+
+macro getMontyOne*(ff: type Fp): untyped =
+  ## Get one in Montgomery representation (i.e. R mod P)
+  result = bindConstant(ff, "MontyOne")
+
+func getOne*(T: type Fp): T {.noInit, inline.} =
+  result = cast[ptr T](unsafeAddr getMontyOne(T))[]
+
+# --------------------------------------------------------------
+proc foo(T: Fp) =
+  discard T
+
+let a = Fp[BN254_Snarks].getOne()
+foo(a) # oops this was a leftover that broke the bisect.
diff --git a/tests/macros/t7875.nim b/tests/macros/t7875.nim
new file mode 100644
index 000000000..7b6e47b86
--- /dev/null
+++ b/tests/macros/t7875.nim
@@ -0,0 +1,22 @@
+discard """
+  nimout: "var mysym`gensym0: MyType[float32]"
+  joinable: false
+"""
+
+import macros
+
+type
+  MyType[T] = object
+
+# this is totally fine
+var mysym: MyType[float32]
+
+macro foobar(): untyped =
+  let floatSym = bindSym"float32"
+
+  result = quote do:
+    var mysym: MyType[`floatSym`]
+
+  echo result.repr
+
+foobar()
diff --git a/tests/macros/tastrepr.nim b/tests/macros/tastrepr.nim
index e4271f019..96a37c7a2 100644
--- a/tests/macros/tastrepr.nim
+++ b/tests/macros/tastrepr.nim
@@ -1,5 +1,6 @@
 discard """
 output: '''
+
 var data = @[(1, "one"), (2, "two")]
 for (i, d) in pairs(data):
   discard
@@ -7,7 +8,11 @@ for i, d in pairs(data):
   discard
 for i, (x, y) in pairs(data):
   discard
-var (a, b) = (1, 2)
+var
+  a = 1
+  b = 2
+type
+  A* = object
 
 var data = @[(1, "one"), (2, "two")]
 for (i, d) in pairs(data):
@@ -17,6 +22,11 @@ for i, d in pairs(data):
 for i, (x, y) in pairs(data):
   discard
 var (a, b) = (1, 2)
+type
+  A* = object
+
+var t04 = 1.0'f128
+t04 = 2.0'f128
 '''
 """
 
@@ -41,3 +51,8 @@ echoTypedAndUntypedRepr:
   for i, (x,y) in pairs(data):
     discard
   var (a,b) = (1,2)
+  type A* = object # issue #22933
+
+echoUntypedRepr:
+  var t04 = 1'f128
+  t04 = 2'f128
diff --git a/tests/macros/tcasestmtmacro.nim b/tests/macros/tcasestmtmacro.nim
new file mode 100644
index 000000000..32019a92a
--- /dev/null
+++ b/tests/macros/tcasestmtmacro.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''
+yes
+'''
+"""
+
+import macros
+
+macro `case`(n: tuple): untyped =
+  result = newTree(nnkIfStmt)
+  let selector = n[0]
+  for i in 1 ..< n.len:
+    let it = n[i]
+    case it.kind
+    of nnkElse, nnkElifBranch, nnkElifExpr, nnkElseExpr:
+      result.add it
+    of nnkOfBranch:
+      for j in 0..it.len-2:
+        let cond = newCall("==", selector, it[j])
+        result.add newTree(nnkElifBranch, cond, it[^1])
+    else:
+      error "custom 'case' for tuple cannot handle this node", it
+
+var correct = false
+
+case ("foo", 78)
+of ("foo", 78):
+  correct = true
+  echo "yes"
+of ("bar", 88): echo "no"
+else: discard
+
+doAssert correct
diff --git a/tests/macros/tclosuremacro.nim b/tests/macros/tclosuremacro.nim
index 5c41c317a..44c2411a5 100644
--- a/tests/macros/tclosuremacro.nim
+++ b/tests/macros/tclosuremacro.nim
@@ -5,8 +5,6 @@ calling mystuff
 yes
 calling mystuff
 yes
-calling sugarWithPragma
-sugarWithPragma called
 '''
 """
 
@@ -40,7 +38,7 @@ proc pass2(f: (int, int) -> int): (int) -> int =
 
 doAssert pass2((x, y) => x + y)(4) == 6
 
-fun(x, y: int) {.noSideEffect.} => x + y
+const fun = (x, y: int) {.noSideEffect.} => x + y
 
 doAssert typeof(fun) is (proc (x, y: int): int {.nimcall.})
 doAssert fun(3, 4) == 7
@@ -70,4 +68,13 @@ m:
   proc mystuff() =
     echo "yes"
 
-sugarWithPragma() {.m.} => echo "sugarWithPragma called"
+const typedParamAndPragma = (x, y: int) -> int => x + y
+doAssert typedParamAndPragma(1, 2) == 3
+
+type
+  Bot = object
+    call: proc (): string {.noSideEffect.}
+
+var myBot = Bot()
+myBot.call = () {.noSideEffect.} => "I'm a bot."
+doAssert myBot.call() == "I'm a bot."
diff --git a/tests/macros/tdumpast.nim b/tests/macros/tdumpast.nim
index b9d224ab8..484b3c2f3 100644
--- a/tests/macros/tdumpast.nim
+++ b/tests/macros/tdumpast.nim
@@ -2,34 +2,69 @@
 
 import macros
 
-template plus(a, b: untyped): untyped {.dirty} =
-  a + b
+block:
+  template plus(a, b: untyped): untyped {.dirty} =
+    a + b
 
-macro call(e: untyped): untyped =
-  result = newCall("foo", newStrLitNode("bar"))
+  macro call(e: untyped): untyped =
+    result = newCall("foo", newStrLitNode("bar"))
 
-macro dumpAST(n: untyped): untyped =
-  # dump AST as a side-effect and return the inner node
-  let n = callsite()
-  echo n.lispRepr
-  echo n.treeRepr
+  macro dumpAST(n: untyped): string =
+    var msg = ""
+    msg.add "lispRepr:\n" & n.lispRepr & "\n"
+    msg.add "treeRepr:\n" & n.treeRepr & "\n"
 
-  var plusAst = getAst(plus(1, 2))
-  echo plusAst.lispRepr
+    var plusAst = getAst(plus(1, 2))
+    msg.add "lispRepr:\n" & n.lispRepr & "\n"
 
-  var callAst = getAst(call(4))
-  echo callAst.lispRepr
+    var callAst = getAst(call(4))
+    msg.add "callAst.lispRepr:\n" & callAst.lispRepr & "\n"
 
-  var e = parseExpr("foo(bar + baz)")
-  echo e.lispRepr
+    var e = parseExpr("foo(bar + baz)")
+    msg.add "e.lispRepr:\n" & e.lispRepr & "\n"
+    result = msg.newLit
 
-  result = n[1]
+  let a = dumpAST:
+    proc add(x, y: int): int =
+      return x + y
+    const foo = 3
 
-dumpAST:
-  proc add(x, y: int): int =
-    return x + y
-
-  proc sub(x, y: int): int = return x - y
+  doAssert a == """
+lispRepr:
+(StmtList (ProcDef (Ident "add") (Empty) (Empty) (FormalParams (Ident "int") (IdentDefs (Ident "x") (Ident "y") (Ident "int") (Empty))) (Empty) (Empty) (StmtList (ReturnStmt (Infix (Ident "+") (Ident "x") (Ident "y"))))) (ConstSection (ConstDef (Ident "foo") (Empty) (IntLit 3))))
+treeRepr:
+StmtList
+  ProcDef
+    Ident "add"
+    Empty
+    Empty
+    FormalParams
+      Ident "int"
+      IdentDefs
+        Ident "x"
+        Ident "y"
+        Ident "int"
+        Empty
+    Empty
+    Empty
+    StmtList
+      ReturnStmt
+        Infix
+          Ident "+"
+          Ident "x"
+          Ident "y"
+  ConstSection
+    ConstDef
+      Ident "foo"
+      Empty
+      IntLit 3
+lispRepr:
+(StmtList (ProcDef (Ident "add") (Empty) (Empty) (FormalParams (Ident "int") (IdentDefs (Ident "x") (Ident "y") (Ident "int") (Empty))) (Empty) (Empty) (StmtList (ReturnStmt (Infix (Ident "+") (Ident "x") (Ident "y"))))) (ConstSection (ConstDef (Ident "foo") (Empty) (IntLit 3))))
+callAst.lispRepr:
+(Call (Ident "foo") (StrLit "bar"))
+e.lispRepr:
+(Call (Ident "foo") (Infix (Ident "+") (Ident "bar") (Ident "baz")))
+"""
 
 macro fun() =
   let n = quote do:
@@ -48,3 +83,79 @@ macro fun3(): untyped =
     int | float | array | seq | object | ptr | pointer | float32
   doAssert n.repr == "int | float | array | seq | object | ptr | pointer | float32", n.repr
 fun3()
+
+macro fun4() =
+  let n = quote do:
+    (a: 1)
+  doAssert n.repr == "(a: 1)", n.repr
+fun4()
+
+# nkTupleConstr vs nkPar tests:
+block: # lispRepr
+  macro lispRepr2(a: untyped): string = newLit a.lispRepr
+
+  doAssert lispRepr2(()) == """(TupleConstr)"""
+  doAssert lispRepr2((a: 1)) == """(TupleConstr (ExprColonExpr (Ident "a") (IntLit 1)))"""
+  doAssert lispRepr2((a: 1, b: 2)) == """(TupleConstr (ExprColonExpr (Ident "a") (IntLit 1)) (ExprColonExpr (Ident "b") (IntLit 2)))"""
+  doAssert lispRepr2((1,)) == """(TupleConstr (IntLit 1))"""
+  doAssert lispRepr2((1, 2)) == """(TupleConstr (IntLit 1) (IntLit 2))"""
+  doAssert lispRepr2((1, 2, 3.0)) == """(TupleConstr (IntLit 1) (IntLit 2) (FloatLit 3.0))"""
+  doAssert lispRepr2((1)) == """(Par (IntLit 1))"""
+  doAssert lispRepr2((1+2)) == """(Par (Infix (Ident "+") (IntLit 1) (IntLit 2)))"""
+
+block: # repr
+  macro repr2(a: untyped): string = newLit a.repr
+
+  doAssert repr2(()) == "()"
+  doAssert repr2((a: 1)) == "(a: 1)"
+  doAssert repr2((a: 1, b: 2)) == "(a: 1, b: 2)"
+  doAssert repr2((1,)) == "(1,)"
+  doAssert repr2((1, 2)) == "(1, 2)"
+  doAssert repr2((1, 2, 3.0)) == "(1, 2, 3.0)"
+  doAssert repr2((1)) == "(1)"
+  doAssert repr2((1+2)) == "(1 + 2)"
+
+block: # treeRepr
+  macro treeRepr2(a: untyped): string = newLit a.treeRepr
+  macro treeRepr3(a: typed): string = newLit a.treeRepr
+
+  doAssert treeRepr2(1+1 == 2) == """
+Infix
+  Ident "=="
+  Infix
+    Ident "+"
+    IntLit 1
+    IntLit 1
+  IntLit 2"""
+
+  proc baz() = discard
+  proc baz(a: int) = discard
+  proc baz(a: float) = discard
+
+  doAssert treeRepr3(baz()) == """
+Call
+  Sym "baz""""
+
+  let a = treeRepr3(block:
+    proc bar(a: auto) = baz())
+  doAssert a == """
+BlockStmt
+  Empty
+  ProcDef
+    Sym "bar"
+    Empty
+    GenericParams
+      Sym "a:type"
+    FormalParams
+      Empty
+      IdentDefs
+        Sym "a"
+        Sym "auto"
+        Empty
+    Empty
+    Bracket
+      Empty
+      Empty
+    StmtList
+      Call
+        OpenSymChoice 3 "baz""""
diff --git a/tests/macros/tfail_parse.nim b/tests/macros/tfail_parse.nim
new file mode 100644
index 000000000..1925f2b69
--- /dev/null
+++ b/tests/macros/tfail_parse.nim
@@ -0,0 +1,15 @@
+discard """
+action: "reject"
+cmd: "nim check $file"
+errormsg: "expected expression, but got multiple statements [ValueError]"
+file: "macros.nim"
+"""
+
+import macros
+static:
+  discard parseStmt("'")
+  discard parseExpr("'")
+  discard parseExpr("""
+proc foo()
+proc foo() = discard
+""")
diff --git a/tests/macros/tforloop_macro1.nim b/tests/macros/tforloop_macro1.nim
index 49918563d..a8f45c7ac 100644
--- a/tests/macros/tforloop_macro1.nim
+++ b/tests/macros/tforloop_macro1.nim
@@ -12,7 +12,7 @@ discard """
 """
 
 import macros
-{.experimental: "forLoopMacros".}
+
 macro mymacro(): untyped =
   result = newLit([1, 2, 3])
 
diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim
index d231a4336..ab33131b0 100644
--- a/tests/macros/tgetimpl.nim
+++ b/tests/macros/tgetimpl.nim
@@ -1,5 +1,5 @@
 discard """
-  nimout: '''"muhaha"
+  nimout: '''foo = "muhaha"
 proc poo(x, y: int) =
   let y = x
   echo ["poo"]'''
@@ -44,10 +44,11 @@ static:
   doAssert checkOwner(poo, 2) == "nskProc"
   doAssert checkOwner(poo, 3) == "nskModule"
   doAssert isSameOwner(foo, poo)
-  doAssert isSameOwner(foo, echo) == false
-  doAssert isSameOwner(poo, len) == false
-
-#---------------------------------------------------------------
+  proc wrappedScope() =
+    proc dummyproc() = discard
+    doAssert isSameOwner(foo, dummyproc) == false
+    doAssert isSameOwner(poo, dummyproc) == false
+  wrappedScope()
 
 macro check_gen_proc(ex: typed): (bool, bool) =
   let lenChoice = bindsym"len"
@@ -65,3 +66,38 @@ macro check_gen_proc(ex: typed): (bool, bool) =
 let a = @[1,2,3]
 assert: check_gen_proc(len(a)) == (false, true)
 
+
+#---------------------------------------------------------------
+# issue #16110
+
+macro check(x: type): untyped =
+  let z = getType(x)
+  let y = getImpl(z[1])  
+  var sym = y[0]
+  if sym.kind == nnkPragmaExpr: sym = sym[0]
+  if sym.kind == nnkPostfix: sym = sym[1]
+  expectKind(z[1], nnkSym)
+  expectKind(sym, nnkSym)
+  expectKind(y[2], nnkObjectTy)
+  doAssert(sym == z[1])
+
+type
+  TirePtr = ptr object
+    code: int
+
+  TireRef* = ref object
+    code: int
+
+  TireRef2* {.inheritable.} = ref object
+    code: int
+
+  TireRef3* {.inheritable.} = object
+    code: int
+
+var z1: TirePtr
+check(typeof(z1[]))
+var z2: TireRef
+check(typeof(z2[]))
+var z3: TireRef2
+check(typeof(z3[]))
+check(TireRef3)
diff --git a/tests/macros/tgetraiseslist.nim b/tests/macros/tgetraiseslist.nim
new file mode 100644
index 000000000..79694a66f
--- /dev/null
+++ b/tests/macros/tgetraiseslist.nim
@@ -0,0 +1,29 @@
+discard """
+  nimout: '''##[ValueError, Gen[string]]##
+%%[RootEffect]%%
+true true'''
+"""
+
+import macros
+import std / effecttraits
+
+type
+  Gen[T] = object of CatchableError
+    x: T
+
+macro m(call: typed): untyped =
+  echo "##", repr getRaisesList(call[0]), "##"
+  echo "%%", repr getTagsList(call[0]), "%%"
+  echo isGcSafe(call[0]), " ", hasNoSideEffects(call[0])
+  result = call
+
+proc gutenTag() {.tags: RootEffect.} = discard
+
+proc r(inp: int) =
+  if inp == 0:
+    raise newException(ValueError, "bah")
+  elif inp == 1:
+    raise newException(Gen[string], "bahB")
+  gutenTag()
+
+m r(2)
diff --git a/tests/macros/tgettype.nim b/tests/macros/tgettype.nim
index bd70a1c30..d91efe1fe 100644
--- a/tests/macros/tgettype.nim
+++ b/tests/macros/tgettype.nim
@@ -1,29 +1,85 @@
-discard """
-output: '''
-(ObjectTy (Empty) (Sym "Model") (RecList (Sym "name") (Sym "password")))
-(BracketExpr (Sym "typeDesc") (Sym "User"))
-'''
-"""
-import macros
+import std/macros
+import stdtest/testutils
 
-type
-  Model = object of RootObj
-  User = object of Model
-    name : string
-    password : string
+# getType
 
-macro testUser: string =
-  result = newLit(User.getType.lispRepr)
+block:
+  type
+    Model = object of RootObj
+    User = object of Model
+      name : string
+      password : string
 
-macro testGeneric(T: typedesc[Model]): string=
-  result = newLit(T.getType.lispRepr)
+  macro testUser: string =
+    result = newLit(User.getType.lispRepr)
 
-echo testUser
-echo User.testGeneric
+  macro testGeneric(T: typedesc[Model]): string=
+    result = newLit(T.getType.lispRepr)
 
-macro assertVoid(e: typed): untyped =
-  assert(getTypeInst(e).typeKind == ntyVoid)
+  doAssert testUser == """(ObjectTy (Empty) (Sym "Model") (RecList (Sym "name") (Sym "password")))"""
+  doAssert User.testGeneric == """(BracketExpr (Sym "typeDesc") (Sym "User"))"""
 
-proc voidProc() = discard
+  macro assertVoid(e: typed): untyped =
+    assert(getTypeInst(e).typeKind == ntyVoid)
 
-assertVoid voidProc()
+  proc voidProc() = discard
+
+  assertVoid voidProc()
+
+block:
+  # refs #18220; not an actual solution (yet) but at least shows what's currently
+  # possible
+
+  type Callable1[R, T, U] = concept fn
+    fn(default(T)) is R
+    fn is U
+
+  # note that typetraits.arity doesn't work
+  macro arity(a: typed): int =
+    # number of params
+    # this is not production code!
+    let a2 = a.getType[1] # this used to crash nim, with: `vmdeps.nim(292, 25) `false``
+    newLit a2.len - 1
+
+  type Callable2[R, T, U] = concept fn
+    fn(default(T)) is R
+    fn is U
+    arity(U) == 2
+
+  proc map1[T, R, U](a: T, fn: Callable1[R, T, U]): R =
+    let fn = U(fn)
+      # `cast[U](fn)` would also work;
+      # this is currently needed otherwise, sigmatch errors with:
+      # Error: attempting to call routine: 'fn'
+      #  found 'fn' [param declared in tgettype.nim(53, 28)]
+      # this can be fixed in future work
+    fn(a)
+
+  proc map2[T, R, U](a: T, fn: Callable2[R, T, U]): R =
+    let fn = U(fn)
+    fn(a)
+
+  proc fn1(a: int, a2 = 'x'): string = $(a, a2, "fn1")
+  proc fn2(a: int, a2 = "zoo"): string = $(a, a2, "fn2")
+  proc fn3(a: int, a2 = "zoo2"): string = $(a, a2, "fn3")
+  proc fn4(a: int): string {.inline.} = $(a, "fn4")
+  proc fn5(a: int): string = $(a, "fn5")
+
+  assertAll:
+    # Callable1
+    1.map1(fn1) == """(1, 'x', "fn1")"""
+    1.map1(fn2) == """(1, "zoo", "fn2")"""
+    1.map1(fn3) == """(1, "zoo", "fn3")"""
+      # fn3's optional param is not honored, because fn3 and fn2 yield same
+      # generic instantiation; this is a caveat with this approach
+      # There are several possible ways to improve things in future work.
+    1.map1(fn4) == """(1, "fn4")"""
+    1.map1(fn5) == """(1, "fn5")"""
+
+    # Callable2; prevents passing procs with optional params to avoid above
+    # mentioned caveat, but more restrictive
+    not compiles(1.map2(fn1))
+    not compiles(1.map2(fn2))
+    not compiles(1.map2(fn3))
+    1.map2(fn4) == """(1, "fn4")"""
+    1.map2(fn5) == """(1, "fn5")"""
diff --git a/tests/macros/tgettypeinst.nim b/tests/macros/tgettypeinst.nim
index 2f9557160..e722f14aa 100644
--- a/tests/macros/tgettypeinst.nim
+++ b/tests/macros/tgettypeinst.nim
@@ -191,14 +191,14 @@ template myAttr3() {.pragma.}
 template serializationKey(key: string) {.pragma.}
 
 type
-  MyObj = object {.packed,myAttr,serializationKey: "one".}
+  MyObj {.packed,myAttr,serializationKey: "one".} = object
     myField {.myAttr2,serializationKey: "two".}: int
     myField2 {.myAttr3,serializationKey: "three".}: float
 
 # field pragmas not currently supported
 test(MyObj):
   type
-    _ = object {.packed,myAttr,serializationKey: "one".}
+    _ {.packed,myAttr,serializationKey: "one".} = object
       myField: int
       myField2: float
 
diff --git a/tests/macros/tgettypeinst7737.nim b/tests/macros/tgettypeinst7737.nim
new file mode 100644
index 000000000..e49f82562
--- /dev/null
+++ b/tests/macros/tgettypeinst7737.nim
@@ -0,0 +1,61 @@
+discard """
+  nimout: '''
+seq[int]
+CustomSeq[int]
+'''
+"""
+
+import macros, typetraits, sequtils
+
+block: # issue #7737 original
+  type
+    CustomSeq[T] = object
+      data: seq[T]
+
+  proc getSubType(T: NimNode): NimNode =
+    echo getTypeInst(T).repr
+    result = getTypeInst(T)[1]
+
+  macro typed_helper(x: varargs[typed]): untyped =
+    let foo = getSubType(x[0])
+    result = quote do: discard
+
+  macro untyped_heavylifting(x: varargs[untyped]): untyped =
+    var containers = nnkArgList.newTree()
+    for arg in x:
+      case arg.kind:
+      of nnkInfix:
+        if eqIdent(arg[0], "in"):
+          containers.add arg[2]
+      else:
+        discard
+    result = quote do:
+      typed_helper(`containers`)
+  var a, b, c: seq[int]
+  untyped_heavylifting z in c, x in a, y in b:
+    discard
+  ## The following gives me CustomSeq instead
+  ## of CustomSeq[int] in getTypeInst
+  var u, v, w: CustomSeq[int]
+  untyped_heavylifting z in u, x in v, y in w:
+    discard
+
+block: # issue #7737 comment
+  type
+    CustomSeq[T] = object
+      data: seq[T]
+  # when using just one argument, `foo` and `bar` should be exactly
+  # identical.
+  macro foo(arg: typed): string =
+    result = newLit(arg.getTypeInst.repr)
+  macro bar(args: varargs[typed]): untyped =
+    result = newTree(nnkBracket)
+    for arg in args:
+      result.add newLit(arg.getTypeInst.repr)
+  var
+    a: seq[int]
+    b: CustomSeq[int]
+  doAssert foo(a) == "seq[int]"
+  doAssert bar(a) == ["seq[int]"]
+  doAssert foo(b) == "CustomSeq[int]"
+  doAssert bar(b) == ["CustomSeq[int]"]
diff --git a/tests/macros/tmacro2.nim b/tests/macros/tmacro2.nim
index 72972c0c1..1ad63ec8c 100644
--- a/tests/macros/tmacro2.nim
+++ b/tests/macros/tmacro2.nim
@@ -26,3 +26,11 @@ const t = mac("HEllo World")
 echo s, " ", t
 
 
+#-----------------------------------------------------------------------------
+# issue #15326
+macro m(n:typed):auto =
+  result = n
+
+proc f[T](x:T): T {.m.} = x
+
+discard f(3)
\ No newline at end of file
diff --git a/tests/macros/tmacrogetimpl.nim b/tests/macros/tmacrogetimpl.nim
new file mode 100644
index 000000000..1d996ff29
--- /dev/null
+++ b/tests/macros/tmacrogetimpl.nim
@@ -0,0 +1,31 @@
+import macros
+
+# bug #5034
+
+macro copyImpl(srsProc: typed, toSym: untyped) =
+  result = copyNimTree(getImplTransformed(srsProc))
+  result[0] = ident $toSym.toStrLit()
+
+proc foo1(x: float, one: bool = true): float =
+  if one:
+    return 1'f
+  result = x
+
+proc bar1(what: string): string =
+  ## be a little more adversarial with `skResult`
+  proc buzz: string =
+    result = "lightyear"
+  if what == "buzz":
+    result = "buzz " & buzz()
+  else:
+    result = what
+  return result
+
+copyImpl(foo1, foo2)
+doAssert foo1(1'f) == 1.0
+doAssert foo2(10.0, false) == 10.0
+doAssert foo2(10.0) == 1.0
+
+copyImpl(bar1, bar2)
+doAssert bar1("buzz") == "buzz lightyear"
+doAssert bar1("macros") == "macros"
diff --git a/tests/macros/tmacros1.nim b/tests/macros/tmacros1.nim
index 53af4287c..c588ff7e6 100644
--- a/tests/macros/tmacros1.nim
+++ b/tests/macros/tmacros1.nim
@@ -60,3 +60,22 @@ macro foo(t: static Tuple): untyped =
   doAssert t.b == 12345
 
 foo((a: "foo", b: 12345))
+
+
+# bug #16307
+
+macro bug(x: untyped): string =
+  newLit repr(x)
+
+let res = bug:
+  block:
+    ## one
+    ## two
+    ## three
+
+doAssert res == """
+
+block:
+  ## one
+  ## two
+  ## three"""
diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim
index df385c445..a81c51658 100644
--- a/tests/macros/tmacros_issues.nim
+++ b/tests/macros/tmacros_issues.nim
@@ -19,6 +19,8 @@ nil
 42
 false
 true
+@[i0, i1, i2, i3, i4]
+@[tmp, tmp, tmp, tmp, tmp]
 '''
 
   output: '''
@@ -27,6 +29,18 @@ array[0 .. 100, int]
 10
 test
 0o377'i8
+0o000000000755'i32
+1
+2
+3
+foo1
+foo2
+foo3
+true
+false
+true
+false
+1.0
 '''
 """
 
@@ -50,7 +64,7 @@ block t7723:
 
 block t8706:
   macro varargsLen(args:varargs[untyped]): untyped =
-    doAssert args.kind == nnkArglist
+    doAssert args.kind == nnkArgList
     doAssert args.len == 0
     result = newLit(args.len)
 
@@ -244,3 +258,264 @@ macro toRendererBug(n): untyped =
   result = newLit repr(n)
 
 echo toRendererBug(0o377'i8)
+echo toRendererBug(0o755'i32)
+
+# bug #12129
+macro foobar() =
+  var loopVars = newSeq[NimNode](5)
+  for i, sym in loopVars.mpairs():
+    sym = ident("i" & $i)
+  echo loopVars
+  for sym in loopVars.mitems():
+    sym = ident("tmp")
+  echo loopVars
+
+foobar()
+
+
+# bug #13253
+import macros
+
+type
+  FooBar = object
+    a: seq[int]
+
+macro genFoobar(a: static FooBar): untyped =
+  result = newStmtList()
+  for b in a.a:
+    result.add(newCall(bindSym"echo", newLit b))
+
+proc foobar(a: static FooBar) =
+  genFoobar(a)  # removing this make it work
+  for b in a.a:
+    echo "foo" & $b
+
+proc main() =
+  const a: seq[int] = @[1, 2,3]
+  # Error: type mismatch: got <array[0..2, int]> but expected 'seq[int]'
+  const fb = Foobar(a: a)
+  foobar(fb)
+main()
+
+# bug #13484
+
+proc defForward(id, nid: NimNode): NimNode =
+  result = newProc(id, @[newIdentNode("bool"), newIdentDefs(nid, newIdentNode("int"))], body=newEmptyNode())
+
+proc defEven(evenid, oddid, nid: NimNode): NimNode =
+  result = quote do:
+    proc `evenid`(`nid`: int): bool =
+      if `nid` == 0:
+        return true
+      else:
+        return `oddid`(`nid` - 1)
+
+proc defOdd(evenid, oddid, nid: NimNode): NimNode =
+  result = quote do:
+    proc `oddid`(`nid`: int): bool =
+      if `nid` == 0:
+        return false
+      else:
+        return `evenid`(`nid` - 1)
+
+proc callNode(funid, param: NimNode): NimNode =
+  result = quote do:
+    `funid`(`param`)
+
+macro testEvenOdd3(): untyped =
+  let
+    evenid = newIdentNode("even3")
+    oddid = newIdentNode("odd3")
+    nid = newIdentNode("n")
+    oddForward = defForward(oddid, nid)
+    even = defEven(evenid, oddid, nid)
+    odd = defOdd(evenid, oddid, nid)
+    callEven = callNode(evenid, newLit(42))
+    callOdd = callNode(oddid, newLit(42))
+  result = quote do:
+    `oddForward`
+    `even`
+    `odd`
+    echo `callEven`
+    echo `callOdd`
+
+macro testEvenOdd4(): untyped =
+  let
+    evenid = newIdentNode("even4")
+    oddid = newIdentNode("odd4")
+    nid = newIdentNode("n")
+    oddForward = defForward(oddid, nid)
+    even = defEven(evenid, oddid, nid)
+    odd = defOdd(evenid, oddid, nid)
+    callEven = callNode(evenid, newLit(42))
+    callOdd = callNode(oddid, newLit(42))
+  # rewrite the body of proc node.
+  oddForward[6] = newStmtList()
+  result = quote do:
+    `oddForward`
+    `even`
+    `odd`
+    echo `callEven`
+    echo `callOdd`
+
+macro testEvenOdd5(): untyped =
+  let
+    evenid = genSym(nskProc, "even5")
+    oddid = genSym(nskProc, "odd5")
+    nid = newIdentNode("n")
+    oddForward = defForward(oddid, nid)
+    even = defEven(evenid, oddid, nid)
+    odd = defOdd(evenid, oddid, nid)
+    callEven = callNode(evenid, newLit(42))
+    callOdd = callNode(oddid, newLit(42))
+  result = quote do:
+    `oddForward`
+    `even`
+    `odd`
+    echo `callEven`
+    echo `callOdd`
+
+macro testEvenOdd6(): untyped =
+  let
+    evenid = genSym(nskProc, "even6")
+    oddid = genSym(nskProc, "odd6")
+    nid = newIdentNode("n")
+    oddForward = defForward(oddid, nid)
+    even = defEven(evenid, oddid, nid)
+    odd = defOdd(evenid, oddid, nid)
+    callEven = callNode(evenid, newLit(42))
+    callOdd = callNode(oddid, newLit(42))
+  # rewrite the body of proc node.
+  oddForward[6] = newStmtList()
+  result = quote do:
+    `oddForward`
+    `even`
+    `odd`
+    echo `callEven`
+    echo `callOdd`
+
+# it works
+testEvenOdd3()
+
+# it causes an error (redefinition of odd4), which is correct
+assert not compiles testEvenOdd4()
+
+# it caused an error (still forwarded: odd5)
+testEvenOdd5()
+
+# it works, because the forward decl and definition share the symbol and the compiler is forgiving here
+#testEvenOdd6() #Don't test it though, the compiler may become more strict in the future
+
+# bug #15385
+var captured_funcs {.compileTime.}: seq[NimNode] = @[]
+
+macro aad*(fns: varargs[typed]): typed =
+  result = newStmtList()
+  for fn in fns:
+    captured_funcs.add fn[0]
+    result.add fn
+
+func exp*(x: float): float ## get different error if you remove forward declaration
+
+func exp*(x: float): float {.aad.} =
+  var x1 = min(max(x, -708.4), 709.8)
+  var result: float   ## looks weird because it is taken from template expansion
+  result = x1 + 1.0
+  result
+
+template check_accuracy(f: untyped, rng: Slice[float], n: int, verbose = false): auto =
+
+  proc check_accuracy: tuple[avg_ulp: float, max_ulp: int] {.gensym.} =
+    let k = (rng.b - rng.a) / (float) n
+    var
+      res, x: float
+      i, max_ulp = 0
+      avg_ulp = 0.0
+
+    x = rng.a
+    while (i < n):
+      res = f(x)
+      i.inc
+      x = x + 0.001
+    (avg_ulp, max_ulp)
+  check_accuracy()
+
+discard check_accuracy(exp, -730.0..709.4, 4)
+
+# And without forward decl
+macro aad2*(fns: varargs[typed]): typed =
+  result = newStmtList()
+  for fn in fns:
+    captured_funcs.add fn[0]
+    result.add fn
+
+func exp2*(x: float): float {.aad2.} =
+  var x1 = min(max(x, -708.4), 709.8)
+  var result: float   ## looks weird because it is taken from template expansion
+  result = x1 + 1.0
+  result
+
+template check_accuracy2(f: untyped, rng: Slice[float], n: int, verbose = false): auto =
+
+  proc check_accuracy2: tuple[avg_ulp: float, max_ulp: int] {.gensym.} =
+    let k = (rng.b - rng.a) / (float) n
+    var
+      res, x: float
+      i, max_ulp = 0
+      avg_ulp = 0.0
+
+    x = rng.a
+    while (i < n):
+      res = f(x)
+      i.inc
+      x = x + 0.001
+    (avg_ulp, max_ulp)
+  check_accuracy2()
+
+discard check_accuracy2(exp2, -730.0..709.4, 4)
+
+# And minimized:
+macro aadMin(fn: typed): typed = fn
+
+func expMin: float
+
+func expMin: float {.aadMin.} = 1
+
+echo expMin()
+
+
+# doubly-typed forward decls
+macro noop(x: typed) = x
+noop:
+  proc cally() = discard
+
+cally()
+
+noop:
+  proc barry()
+
+proc barry() = discard
+
+# some more:
+proc barry2() {.noop.}
+proc barry2() = discard
+
+proc barry3() {.noop.}
+proc barry3() {.noop.} = discard
+
+
+# issue #15389
+block double_sem_for_procs:
+
+  macro aad(fns: varargs[typed]): typed =
+    result = newStmtList()
+    for fn in fns:
+      result.add fn
+
+  func exp(x: float): float {.aad.} =
+    var x1 = min(max(x, -708.4), 709.8)
+    if x1 > 0.0:
+      return x1 + 1.0
+    result = 10.0
+
+  discard exp(5.0)
diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim
index 533db25e1..e351b4527 100644
--- a/tests/macros/tmacros_various.nim
+++ b/tests/macros/tmacros_various.nim
@@ -22,6 +22,9 @@ a[1]: 45
 x: some string
 ([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")])
 ([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")])
+0
+0
+0
 '''
 """
 
@@ -88,7 +91,7 @@ block tlexerex:
 
 
 
-block tlineinfo:
+block tcopylineinfo:
   # issue #5617, feature request
   type Test = object
 
@@ -100,6 +103,27 @@ block tlineinfo:
   var z = mixer(Test)
   doAssert z
 
+block tsetgetlineinfo:
+  # issue #21098, feature request
+  type Test = object
+
+  macro mixer1(n: typed): untyped =
+    let x = newIdentNode("echo")
+    var lineInfo = n.lineInfoObj
+    x.setLineInfo lineInfo
+    result = newLit(x.lineInfo == n.lineInfo)
+
+  macro mixer2(n: typed): untyped =
+    let x = newIdentNode("echo")
+    var lineInfo = n.lineInfoObj
+    lineInfo.line += 1
+    x.setLineInfo lineInfo
+    result = newLit(x.lineInfo != n.lineInfo)
+
+  doAssert mixer1(Test)
+
+  doAssert mixer2(Test)
+
 
 
 block tdebugstmt:
@@ -202,3 +226,166 @@ block tupleNewLitTests:
     # this `$` test is needed because tuple equality doesn't distinguish
     # between named vs unnamed tuples
   doAssert t() == (1, "foo", (), (1, ), (a1: 'x', a2: @["ba"]))
+
+from strutils import contains
+block getImplTransformed:
+  macro bar(a: typed): string =
+    # newLit a.getImpl.repr # this would be before code transformation
+    let b = a.getImplTransformed
+    newLit b.repr
+  template toExpand() =
+    for ai in 0..2: echo ai
+  proc baz(a=1): int =
+    defer: discard
+    toExpand()
+    12
+  const code = bar(baz)
+  # sanity check:
+  doAssert "finally" in code # `defer` is lowered to try/finally
+  doAssert "while" in code # `for` is lowered to `while`
+  doAssert "toExpand" notin code
+    # template is expanded (but that would already be the case with
+    # `a.getImpl.repr`, unlike the other transformations mentioned above
+
+
+# test macro resemming
+macro makeVar(): untyped =
+  quote:
+    var tensorY {.inject.}: int
+
+macro noop(a: typed): untyped =
+  a
+
+noop:
+  makeVar
+echo tensorY
+
+macro xbenchmark(body: typed): untyped =
+  result = body
+
+xbenchmark:
+  proc fastSHA(inputtest: string) =
+    discard inputtest
+  fastSHA("hey")
+
+block: # issue #4547
+  macro lazy(stmtList : typed) : untyped =
+    let decl = stmtList[0]
+    decl.expectKind nnkLetSection
+    let name = decl[0][0].strVal
+    let call = decl[0][2].copy
+    call.expectKind nnkCall
+    let ident = newIdentNode("get" & name)
+    result = quote do:
+      var value : type(`call`)
+      proc `ident`() : type(`call`) =
+        if value.isNil:
+          value = `call`
+        value
+  type MyObject = object
+    a,b: int    
+  # this part, the macro call and it's result (written in the comment below) is important
+  lazy:
+    let y = new(MyObject)
+  #[
+    var value: type(new(MyObject))
+    proc gety(): type(new(MyObject)) =
+      if value.isNil:
+        value = new(MyObject)
+      value    
+  ]#
+  doAssert gety().a == 0  # works and should work
+  doAssert gety().b == 0  # works and should work
+  doAssert not declared(y)
+  doAssert not compiles(y.a)       # identifier y should not exist anymore
+  doAssert not compiles(y.b)       # identifier y should not exist anymore
+
+block: # bug #13511
+  type
+    Builder = ref object
+      components: seq[Component]
+    Component = object
+
+  proc add(builder: var Builder, component: Component) {.compileTime.} =
+    builder.components.add(component)
+
+  macro debugAst(arg: typed): untyped =
+    ## just for debugging purpose.
+    discard arg.treeRepr
+    return arg
+
+  static:
+    var component = Component()
+    var builder = Builder()
+
+    template foo(): untyped =
+      ## WAS: this doc comment causes compilation failure.
+      builder
+
+    debugAst:
+      add(foo(), component)
+
+block: # bug #15118
+  macro flop(name: static string) =
+    let id = genSym(nskType, "env")
+    let r =
+      nnkStmtList.newTree(
+        nnkTypeSection.newTree(
+          nnkTypeDef.newTree(
+            id,
+            newEmptyNode(),
+            nnkRefTy.newTree(
+              nnkObjectTy.newTree(
+                newEmptyNode(),
+                newEmptyNode(),
+                nnkRecList.newTree(
+                  nnkIdentDefs.newTree(
+                    newIdentNode(name),
+                    newIdentNode("int"),
+                    newEmptyNode()
+                  )
+                )
+              ) 
+            )
+          )
+        ),
+
+        # var f: T
+  
+        nnkVarSection.newTree(
+          nnkIdentDefs.newTree(
+            newIdentNode("f"),
+            id,
+            newEmptyNode()
+          )
+        ),
+
+        # echo f.a
+        nnkCommand.newTree(
+          newIdentNode("new"),
+          newIdentNode("f")
+        ),
+
+        nnkCommand.newTree(
+          newIdentNode("echo"),
+          nnkDotExpr.newTree(
+            newIdentNode("f"),
+            newIdentNode(name)
+          )
+        )
+      )
+    r
+
+
+  block:
+    flop("a")
+
+  block:
+    flop("b")
+
+static:
+  block:
+    const containsTable = CacheTable"containsTable"
+    doAssert "foo" notin containsTable
+    containsTable["foo"] = newLit 42
+    doAssert "foo" in containsTable
diff --git a/tests/macros/tmacrostmt.nim b/tests/macros/tmacrostmt.nim
index 79be5f764..817bc8352 100644
--- a/tests/macros/tmacrostmt.nim
+++ b/tests/macros/tmacrostmt.nim
@@ -124,7 +124,7 @@ static:
   let fn4s = "proc fn4(x: int): int =\n  if x mod 2 == 0:\n    return x + 2\n  else:\n    return 0\n"
   let fn5s = "proc fn5(a, b: float): float =\n  result = -a * a / (b * b)\n"
   let fn6s = "proc fn6() =\n  var a = @[1.0, 2.0]\n  let z = a{0, 1}\n  a{2} = 5.0\n"
-  let fnAddr = "proc fn_unsafeaddr(x: int): int =\n  result = cast[int](unsafeAddr(x))\n"
+  let fnAddr = "proc fn_unsafeaddr(x: int): int =\n  result = cast[int](addr(x))\n"
 
   doAssert fn1.repr_to_string == fn1s
   doAssert fn2.repr_to_string == fn2s
diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim
index cfc4ef7fb..13b421303 100644
--- a/tests/macros/tmacrotypes.nim
+++ b/tests/macros/tmacrotypes.nim
@@ -1,9 +1,9 @@
 discard """
-  nimout: '''intProc; ntyProc; proc[int, int, float]; proc (a: int; b: float): int
+  nimout: '''intProc; ntyProc; proc[int, int, float]; proc (a: int; b: float): int {.nimcall.}
 void; ntyVoid; void; void
 int; ntyInt; int; int
-proc (); ntyProc; proc[void]; proc ()
-voidProc; ntyProc; proc[void]; proc ()
+proc () {.nimcall.}; ntyProc; proc[void]; proc () {.nimcall.}
+voidProc; ntyProc; proc[void]; proc () {.nimcall.}
 listing fields for ObjType
 a: string
 b: int
@@ -43,6 +43,8 @@ macro checkType(ex: typed): untyped =
   echo ex.getTypeInst.repr, "; ", ex.typeKind, "; ", ex.getType.repr, "; ", ex.getTypeImpl.repr
 
 macro checkProcType(fn: typed): untyped =
+  if fn.kind == nnkProcDef:
+    result = fn
   let fn_sym = if fn.kind == nnkProcDef: fn[0] else: fn
   echo fn_sym, "; ", fn_sym.typeKind, "; ", fn_sym.getType.repr, "; ", fn_sym.getTypeImpl.repr
 
diff --git a/tests/macros/tmemit.nim b/tests/macros/tmemit.nim
index 06ab8a1e2..6c9f9f935 100644
--- a/tests/macros/tmemit.nim
+++ b/tests/macros/tmemit.nim
@@ -1,6 +1,5 @@
 discard """
   output: '''
-HELLO WORLD
 c_func
 12
 '''
@@ -8,8 +7,6 @@ c_func
 
 import macros, strutils
 
-emit("echo " & '"' & "hello world".toUpperAscii & '"')
-
 # bug #1025
 
 macro foo(icname): untyped =
diff --git a/tests/macros/tparsefile.nim b/tests/macros/tparsefile.nim
new file mode 100644
index 000000000..a41223f80
--- /dev/null
+++ b/tests/macros/tparsefile.nim
@@ -0,0 +1,11 @@
+import macros
+
+static:
+  let fn = "mparsefile.nim"
+  var raised = false
+  try:
+    discard parseStmt(staticRead(fn), filename = fn)
+  except ValueError as e:
+    raised = true
+    doAssert e.msg == "mparsefile.nim(4, 1) Error: invalid indentation"
+  doAssert raised
diff --git a/tests/macros/tprocgettype.nim b/tests/macros/tprocgettype.nim
new file mode 100644
index 000000000..0c1cc4270
--- /dev/null
+++ b/tests/macros/tprocgettype.nim
@@ -0,0 +1,28 @@
+discard """
+  nimout: '''
+var x: proc () {.cdecl.} = foo
+var x: iterator (): int {.closure.} = bar
+'''
+"""
+
+# issue #19010
+
+import macros
+
+macro createVar(x: typed): untyped =
+  result = nnkVarSection.newTree:
+    newIdentDefs(ident"x", getTypeInst(x), copy(x))
+  
+  echo repr result
+
+block:
+  proc foo() {.cdecl.} = discard
+
+  createVar(foo)
+  x()
+
+block:
+  iterator bar(): int {.closure.} = discard
+
+  createVar(bar)
+  for a in x(): discard
diff --git a/tests/macros/tprochelpers.nim b/tests/macros/tprochelpers.nim
new file mode 100644
index 000000000..d95a2ced8
--- /dev/null
+++ b/tests/macros/tprochelpers.nim
@@ -0,0 +1,22 @@
+import std/macros
+import stdtest/testutils
+
+macro test1(prc: untyped): untyped =
+  assertAll:
+    prc.params.len == 2
+    prc.params[1].len == 4
+    prc.pragma.len == 2
+
+  prc.params = nnkFormalParams.newTree(
+    ident("int")
+  )
+  prc.pragma = newEmptyNode()
+
+  assertAll:
+    prc.params.len == 1
+    prc.pragma.len == 0
+  prc
+
+proc test(a, b: int): int {.gcsafe, raises: [], test1.} = 5
+
+type hello = proc(a, b: int): int {.gcsafe, raises: [], test1.}
diff --git a/tests/macros/tstaticparamsmacro.nim b/tests/macros/tstaticparamsmacro.nim
index 8bd653920..2632ca730 100644
--- a/tests/macros/tstaticparamsmacro.nim
+++ b/tests/macros/tstaticparamsmacro.nim
@@ -7,9 +7,9 @@ numbers
 11
 22
 AST a
-[(11, 22), (33, 44)]
+@[(c: 11, d: 22), (c: 33, d: 44)]
 AST b
-([55, 66], [77, 88])
+(e: @[55, 66], f: @[77, 88])
 55
 10
 20Test
diff --git a/tests/macros/tstructuredlogging.nim b/tests/macros/tstructuredlogging.nim
index 05bb52a40..649c6c0bd 100644
--- a/tests/macros/tstructuredlogging.nim
+++ b/tests/macros/tstructuredlogging.nim
@@ -1,7 +1,7 @@
 discard """
 output: '''
 main started: a=10, b=inner-b, c=10, d=some-d, x=16, z=20
-exiting: a=12, b=overriden-b, c=100, msg=bye bye, x=16
+exiting: a=12, b=overridden-b, c=100, msg=bye bye, x=16
 '''
 """
 
@@ -66,7 +66,7 @@ macro mergeScopes(scopeHolders: typed, newBindings: untyped): untyped =
     newScopeDefinition.add newAssignment(newIdentNode(k), v)
 
   result = quote:
-    template scopeHolder = `newScopeDefinition`
+    template scopeHolder {.redefine.} = `newScopeDefinition`
 
 template scope(newBindings: untyped) {.dirty.} =
   mergeScopes(bindSym"scopeHolder", newBindings)
@@ -134,7 +134,7 @@ scope:
 
 scope:
   x = 16
-  b = "overriden-b"
+  b = "overridden-b"
 
 scope:
   c = 100
diff --git a/tests/macros/ttemplatesymbols.nim b/tests/macros/ttemplatesymbols.nim
index 280b34ff1..3182de79d 100644
--- a/tests/macros/ttemplatesymbols.nim
+++ b/tests/macros/ttemplatesymbols.nim
@@ -148,8 +148,6 @@ proc overloadedProc[T](x: T) =
   echo x
 
 """
-  # XXX: There seems to be a repr rendering problem above.
-  # Notice that `echo [x]`
 
 inspectSymbol overloadedProc[float], """
 proc overloadedProc(x: T) =
diff --git a/tests/macros/ttryparseexpr.nim b/tests/macros/ttryparseexpr.nim
index fc0ee61d0..e6e9e9880 100644
--- a/tests/macros/ttryparseexpr.nim
+++ b/tests/macros/ttryparseexpr.nim
@@ -18,3 +18,7 @@ const
   c = test("\"") # bug #2504
 
 echo a, " ", b
+
+static:
+  # Issue #9918
+  discard parseStmt("echo(1+1);")
diff --git a/tests/macros/ttypenodes.nim b/tests/macros/ttypenodes.nim
new file mode 100644
index 000000000..233ea9780
--- /dev/null
+++ b/tests/macros/ttypenodes.nim
@@ -0,0 +1,16 @@
+import macros
+
+macro makeEnum(): untyped =
+  newTree(nnkEnumTy, newEmptyNode(), ident"a", ident"b", ident"c")
+
+macro makeObject(): untyped =
+  newTree(nnkObjectTy, newEmptyNode(), newEmptyNode(), newTree(nnkRecList,
+    newTree(nnkIdentDefs, ident"x", ident"y", ident"int", newEmptyNode())))
+
+type
+  Foo = makeEnum()
+  Bar = makeObject()
+
+doAssert {a, b, c} is set[Foo]
+let bar = Bar(x: 3, y: 4)
+doAssert (bar.x, bar.y) == (3, 4)
diff --git a/tests/macros/tvtable.nim b/tests/macros/tvtable.nim
index dc07a726b..0f322b7d5 100644
--- a/tests/macros/tvtable.nim
+++ b/tests/macros/tvtable.nim
@@ -18,7 +18,7 @@ type
   # it's also possible to use a strongly typed tuple here
   VTable = array[0..1, pointer]
 
-  TBase = object {.inheritable.}
+  TBase {.inheritable.} = object
     vtbl: ptr VTable
 
   TUserObject1 = object of TBase