When a proc call a macro with typedesc parameter, we can just user the type name, but when we call another macro in the macro and pass the typedesc parameter to it, something is strange, look at the code:
type
User = object
id: int
name: string
age: int
macro stepTwo(T: typedesc): untyped =
echo "In step 2: "
echo repr T.getType()
macro m2(T: typedesc): untyped =
let nT = quote do: `T` #Sym "User"
let t1 = T.getType()[1] #Sym "User"
let t2 = bindSym"User" #Sym "User"
echo t1 == nT # true
echo t1 == t2 # true
echo t2 == nT # true
#result = newCall("stepTwo", t1) # ERROR!!
#result = newCall("stepTwo", t2) # ERROR!!
result = newCall("stepTwo", nT) # OK!
m2(User)
How can I pass the User as typedesc paramter to the macro stepTwo if there is no 'T' parameter? Why the t1, t2 cannot be treated as correct typedesc, they all Sym "User" just like nT.
Help needed, thanks.
The following code is ok:
result = newCall("stepTwo", ident("User")) # OK!
result = newCall("stepTwo", T.getType) # OK!
Now, I know how to pass User as typedesc, but still it is a little confusion about typedesc to me. Now here is problem how to pass typedesc to template:
template create(x: int, T: typedesc): untyped = T(age: x)
macro m2(T: typedesc): untyped =
let nT = quote do: `T` #Sym "User"
let t1 = T.getType()[1] #Sym "User"
let t2 = bindSym"User" #Sym "User"
# all of the following code is ERROR!
#result = getAst create(10, t2)
#result = getAst create(10, t1)
#result = getAst create(10, T)
#result = getAst create(10, nT)
#result = getAst create(10, ident("User"))
result = getAst create(10, User)
#echo create(User, 10) # OK!
echo m2(User)
All the code of the getAst call result ERROR.
Change the code:
template create(x: int, T: typedesc): untyped = T(age: x)
to:
template create(x: int, T: untyped): untyped = T(age: x)
All the code of above works!
when you cross macro boundary, not only typedesc transformed into NimNode, practically all args passed to macros will be transformed into NimNode, no matter it is an int, string, int literal, string literal, or a block of code/statements, all will be transformed into NimNode with specific kind.
macro mymacro(x: int): untyped =
echo x # perhaps failed to compile, x is not an int anymore, it is a NimNode of int literal
the same is also happened with T: typedesc, inside a macro, T is not a typedesc anymore, it is a NimNode of symbol. When you call template create(x: int, T: typedesc): untyped = T(age: x), it will not works because the template create expecting a T and constrained the type to typedesc not NimNode. while template create(x: int, T: untyped): untyped = T(age: x) will accept T wihout any specific type.
when you have more than one macro with the same name, and they don't have varargs or untyped parameters, they can participate in macro overloading
macro mymacro(T: typedesc): untyped
macro mymacro(T: int): untyped
macro mymacro(T: string): untyped
etc
typedesc seems different from other type in the macro.
macro m1(T: typed): untyped =
echo treeRepr T
macro m2(T: typedesc): untyped =
#echo treeRepr T # compile error
echo repr T.getType
m1(int) # Sym "int"
m2(int) # typeDesc[int]
Why the t1, t2 cannot be treated as correct typedesc, they all Sym "User" just like nT.
echo repr nT.getType() # typeDesc[User]
echo repr t1.getType() # object
echo repr t2.getType() # object
I don't know if this just some inconsistencies or qualified as a bug
@Araq
Yes, I think static[T] should be nnkLitXXX, and typedesc should be nnkLitType maybe. Every should be NimNode in the macro, but it affect compatibility.