Open arnetheduck opened 6 years ago
I have a workaround with macros:
type
X[T] = object
inner: T
import macros
macro nest(arg: typed): untyped =
if arg.getTypeInst == bindSym"int":
result = newLit(42)
else:
result = quote do:
nest(`arg`.inner)
var tmp: X[X[int]]
echo nest(tmp)
It seems the template doesn't take itself into consideration for symbol lookup. But that macro above does technically the same thing.
yeah, macros obfuscate the intent of the code though - it can also be worked around by adding explicitly instantiated overloads, but neither is really a general / satisfactory solution
The macro solution is a general solution. It is even more general than the template solution. But I agree that it would be better if overloading would be nicer. This workaround is more scaleable than the explicit overloads.
ah, sorry, something I failed to mention is that nest
is an extension point for an api, so it might come from any module, really, meaning we can't implement the macro in the suggested way - the bug was discovered while trying to move away from a macro to use a more natural feature of the language :)
Adding a mixin
works. Otherwise, since there is only one previous definition of nest
, the call gets bound to a closed symbol.
type
X[T] = object
inner: T
template nest(t: int): untyped = 42
template nest(t: X): untyped =
mixin nest
nest(t.inner)
var tmp: X[X[int]]
echo nest(tmp)
@jcosborn perfect - works and expresses the intent clearly, thanks!
so.. is this just a poor error message / should the mixin
be necessary for recursive calls?
The error message is correct, but if one isn't aware of the rule, it can be confusing. Adding a suggestion to try mixin if the symbol is closed could be useful.
I don't know if having the routine name symbol visible in the routine body is feasible, but it does seem like it would be useful.
This issue has been automatically marked as stale because it has not had recent activity. If you think it is still a valid issue, write a comment below; otherwise it will be closed. Thank you for your contributions.
import macros
macro typedTree(foo: typed) =
echo foo.treeRepr
foo
type X[T] = object
inner: T
template nest(t: int): untyped = 42
typedTree:
template nest(t: X): untyped = nest(t.inner)
Gives:
StmtList
TemplateDef
Sym "nest"
Empty
GenericParams
Sym "X"
FormalParams
Sym "untyped"
IdentDefs
Sym "t"
Sym "X"
Empty
Empty
Bracket
Empty
Empty
StmtList
Call
Sym "nest"
DotExpr
Sym "t"
Ident "inner"
Important part being Sym "nest"
. Template doesn't notice itself when getting a sym choice for nest
. Maybe related: #12012
Also mixin nest
is a workaround
this should compile:
instead, it gives: