You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
templatedeclare1(x: untyped) =let x =1templatedeclare2(x: untyped) =declare1 a
let x = a +1declare2 a
assert a ==2
An explicit {.gensym.} pragma does not help (still causes a redefinition error):
templatedeclare1(x: untyped) =let x =1templatedeclare2(x: untyped) =declare1(a {.gensym.})
let x = a +1declare2 a
assert a ==2
Investigation
Implementing declare1 as a macro and inspecting x shows that it is given as a simple ident instead of a gensym symbol, even with the explicit {.gensym.} pragma from before:
import macros
macrodeclare1(x: untyped) =echo x.lispRepr # outputs (PragmaExpr (Ident "a") (Pragma (Ident "gensym")))result=quotedo:
let `x` =1templatedeclare2(x: untyped) =declare1(a {.gensym.})
let x = a +1declare2 a
assert a ==2
Discussion
First of all, note that this issue is similar to #24260, but the focus there was on how templates ignore gensyms in their names, while this issue is focused on identifiers not being gensym'ed.
I originally expected that every identifier that is "created" in a template, in the sense that it does not refer to an existing symbol, should be gensym'ed. In this way, everything that would later be derived from that identifier (like a let declaration in declare1) would only be visible in the template that created the identifier (declare2), not the surrounding scope. This is currently only the case for identifiers that are directly used in declarations like let a = 1.
However, as @metagnnoted, an automatic gensymming of identifiers cannot be done in templates, because identifiers could be bound at the instantiation site.
Even if not every identifier should be gensym'ed, I still think identifiers that are "later" used in declarations should/could be retroactively gensym'ed. Although I'm not sure whether this can be implemented (easily).
Another alternative that was mentioned by @metagn is what I tried to do myself: using the {.gensym.} pragma to force identifiers to be gensym'ed, even if they aren't immediately used in a declaration.
Nim Version
Nim Compiler Version 2.0.8 [Linux: amd64]
Compiled at 2024-07-03
Copyright (c) 2006-2023 by Andreas Rumpf
git hash: 5935c3b
active boot switches: -d:release
Description
This produces a "redefinition of
a
" error:An explicit
{.gensym.}
pragma does not help (still causes a redefinition error):Investigation
Implementing
declare1
as a macro and inspectingx
shows that it is given as a simple ident instead of a gensym symbol, even with the explicit{.gensym.}
pragma from before:Discussion
First of all, note that this issue is similar to #24260, but the focus there was on how templates ignore gensyms in their names, while this issue is focused on identifiers not being gensym'ed.
I originally expected that every identifier that is "created" in a template, in the sense that it does not refer to an existing symbol, should be gensym'ed. In this way, everything that would later be derived from that identifier (like a
let
declaration indeclare1
) would only be visible in the template that created the identifier (declare2
), not the surrounding scope. This is currently only the case for identifiers that are directly used in declarations likelet a = 1
.However, as @metagn noted, an automatic gensymming of identifiers cannot be done in templates, because identifiers could be bound at the instantiation site.
Even if not every identifier should be gensym'ed, I still think identifiers that are "later" used in declarations should/could be retroactively gensym'ed. Although I'm not sure whether this can be implemented (easily).
Another alternative that was mentioned by @metagn is what I tried to do myself: using the
{.gensym.}
pragma to force identifiers to be gensym'ed, even if they aren't immediately used in a declaration.Nim Version
Nim Compiler Version 2.0.8 [Linux: amd64]
Compiled at 2024-07-03
Copyright (c) 2006-2023 by Andreas Rumpf
git hash: 5935c3b
active boot switches: -d:release
Current Output
Expected Output
Known Workarounds
use a different name for the temporary variable. note that this still (unintentionally) leaks the temporary:
do not use nested template invocations:
Additional Information
Also checked with versions (same error everywhere):
The text was updated successfully, but these errors were encountered: