Open alaviss opened 3 years ago
Somewhat simplified:
import macros
macro c(n: typed): untyped =
result = n
echo "c"
echo result.repr
macro b(n: typed): untyped =
result = copyNimTree n
result.body = newStmtList(ident"abc") # this is supposed to error
echo "b"
echo result.repr
macro a(n: typed): untyped =
result = copyNimTree n
result.addPragma(bindSym"b")
result.addPragma(bindSym"c")
echo "a"
echo result.repr
proc test() {.a.} =
discard
a
proc test() {.b, c.} =
discard
b
proc test() {.c.} =
abc
c
proc test() =
abc
a.nim(24, 15) template/generic instantiation of `a` from here
a.nim(18, 12) template/generic instantiation of `b` from here
a.nim(20, 12) template/generic instantiation of `c` from here
a.nim(10, 34) Error: undeclared identifier: 'abc'
My guess is when c
is getting called, the proc test() = abc
argument is considered typed since it has type tyVoid
, and so not rechecked by prepareOperand
. Using calls instead of pragmas works, because the next macro receives a different node than the proc node, a call node, always having a nil type.
We can fix this case (checking for formal.kind == tyTyped and a.typ.kind == tyVoid
in prepareOperand
as well as a.typ == nil
), but I don't know about the general case, when the typed
argument has non-void type. We could automatically set the type to nil
for every macro output with type untyped
, but this could break stuff, and there's the question of it being applied recursively. Another option is maybe exposing something like eraseType(node)
which sets the type of the node to nil
. but maybe this makes users depend on an implementation detail.
There's also the question of "should prepareOperand
check for nil
type at all", when it could just sem everything given to it. I don't know if this is feasible but as seen in #16867 other things like nkHiddenCallConv
have similar problems.
This is effectively the same issue as #18348.
Example
Current Output
Expected Output
Additional Information