-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cannot instantiate T when generating AST from macro #10902
Comments
This seems like another case of nim-lang/RFCs#44 (Working with types in macro is difficult). Unfortunately the naive regen idents that worked wonder in #8531 and nim-lang/RFCs#44 (comment) doesn't work here: import macros
type
Base[T] = ref object
dumpTree: # reference tree to be produced by macro below
proc clone[T](self: Base[T]): Base[T] =
discard
proc replaceNodes*(ast: NimNode): NimNode =
# Replace NimIdent and NimSym by a fresh ident node
proc inspect(node: NimNode): NimNode =
case node.kind:
of {nnkIdent, nnkSym}:
return ident($node)
of nnkEmpty:
return node
of nnkLiterals:
return node
else:
var rTree = node.kind.newTree()
for child in node:
rTree.add inspect(child)
return rTree
result = inspect(ast)
macro genCloneProc(typeWithGenArg: untyped): untyped =
echo typeWithGenArg.treeRepr
# =>
# BracketExpr
# Ident "Base"
# Ident "T"
result = newProc(
ident "clone", [
typeWithGenArg, # return type: Base[T]
newIdentDefs(
ident "self",
typeWithGenArg,
)
],
newStmtList(
newNimNode(nnkDiscardStmt).add(newEmptyNode())
)
)
# set the generic param
let genericParamIdent = newIdentNode($typeWithGenArg[1]) # the `T`
result[2] = newNimNode(nnkGenericParams)
result[2].add(newIdentDefs(genericParamIdent, newEmptyNode()))
echo result.repr
echo result.treeRepr
genCloneProc(Base[T]) and even building the AST from scratch doesn't: import macros
type
Base[T] = ref object
dumpASTGen: # reference tree to be produced by macro below
proc clone[T](self: Base[T]): Base[T] =
discard
macro genCloneProc(typeWithGenArg: untyped): untyped =
echo typeWithGenArg.treeRepr
# let typeWithGenArg = typeWithGenArg.replaceNodes
# =>
# BracketExpr
# Ident "Base"
# Ident "T"
result = newStmtList()
result.add nnkProcDef.newTree(
newIdentNode"clone",
newEmptyNode(),
nnkGenericParams.newTree(
newIdentDefs(
typeWithGenArg[1],
newEmptyNode()
)
),
nnkFormalParams.newTree(
typeWithGenArg,
newIdentDefs(
newIdentNode"self",
typeWithGenArg
)
),
newEmptyNode(),
newEmptyNode(),
nnkStmtList.newTree(
nnkDiscardStmt.newTree(
newEmptyNode()
)
)
)
echo result.repr
echo result.treeRepr
expandMacros:
genCloneProc(Base[T]) |
I can confirm it's a compiler bug. And one that I don't understand (yet). |
It's simply a problem of some parts of the AST points to the same NimNode. The solution is just copy the result once. The following compiles. import macros
type
Base[T] = ref object
dumpTree: # reference tree to be produced by macro below
proc clone[T](self: Base[T]): Base[T] =
discard
macro genCloneProc(typeWithGenArg: untyped): untyped =
echo typeWithGenArg.treeRepr
# =>
# BracketExpr
# Ident "Base"
# Ident "T"
result = newProc(
ident "clone", [
typeWithGenArg, # return type: Base[T] ::: This is used multiple times in the AST
newIdentDefs(
ident "self",
typeWithGenArg,
)
],
newStmtList(
newNimNode(nnkDiscardStmt).add(newEmptyNode())
)
)
# set the generic param
let genericParamIdent = typeWithGenArg[1] # the `T`
result[2] = newNimNode(nnkGenericParams)
result[2].add(newIdentDefs(genericParamIdent, newEmptyNode()))
result = result.copy # Notice the copy here.
echo result.repr
echo result.treeRepr
genCloneProc(Base[T]) |
Thanks for figuring out a work-around! I can confirm this also works in my actual use case. |
I'm repeatedly running into the same problem here, maybe this is the actual problem behind #10858. The macro also produces an AST involving generics that is valid when written manually, but somehow the AST returned from the macro doesn't compile -- this time with a different error though.
Would be great if a more experience Nim dev could quickly comment if this looks like a bug, or if I'm trying to do something that is not possible? (I'm trying to base a design decision on whether this is possible or not.)
Example
Current Output
Additional Information
Comparing the refernce AST to the macro AST:
The text was updated successfully, but these errors were encountered: