mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-12 06:18:51 +00:00
make routine implicitly gensym when other gensym symbol exists again (#23842)
fixes #23813, partially reverts #23392
Before #23392, if a `gensym` symbol was defined before a proc with the
same name in a template even with an `inject` annotation, the proc would
be `gensym`. After #23392 the proc was instead changed to be `inject` as
long as no `gensym` annotation was given. Now, to keep compatibility
with the old behavior, the behavior is changed back to infer the proc as
`gensym` when no `inject` annotation is given, however an explicit
`inject` annotation will still inject the proc. This is also documented
in the manual as the old behavior was undocumented and the new behavior
is slightly different.
(cherry picked from commit cd946084ab)
This commit is contained in:
@@ -255,25 +255,27 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode =
|
||||
if not isField:
|
||||
styleCheckUse(c, n.info, s)
|
||||
|
||||
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
|
||||
proc semRoutineInTemplName(c: var TemplCtx, n: PNode, explicitInject: bool): PNode =
|
||||
result = n
|
||||
if n.kind == nkIdent:
|
||||
let s = qualifiedLookUp(c.c, n, {})
|
||||
if s != nil:
|
||||
if s.owner == c.owner and s.kind == skParam:
|
||||
if s.owner == c.owner and (s.kind == skParam or
|
||||
(sfGenSym in s.flags and not explicitInject)):
|
||||
incl(s.flags, sfUsed)
|
||||
result = newSymNode(s, n.info)
|
||||
onUse(n.info, s)
|
||||
else:
|
||||
for i in 0..<n.safeLen:
|
||||
result[i] = semRoutineInTemplName(c, n[i])
|
||||
result[i] = semRoutineInTemplName(c, n[i], explicitInject)
|
||||
|
||||
proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
|
||||
result = n
|
||||
checkSonsLen(n, bodyPos + 1, c.c.config)
|
||||
if n.kind notin nkLambdaKinds:
|
||||
# routines default to 'inject':
|
||||
if symBinding(n[pragmasPos]) == spGenSym:
|
||||
let binding = symBinding(n[pragmasPos])
|
||||
if binding == spGenSym:
|
||||
let (ident, hasParam) = getIdentReplaceParams(c, n[namePos])
|
||||
if not hasParam:
|
||||
var s = newGenSym(k, ident, c)
|
||||
@@ -285,7 +287,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
|
||||
else:
|
||||
n[namePos] = ident
|
||||
else:
|
||||
n[namePos] = semRoutineInTemplName(c, n[namePos])
|
||||
n[namePos] = semRoutineInTemplName(c, n[namePos], binding == spInject)
|
||||
# open scope for parameters
|
||||
openScope(c)
|
||||
for i in patternPos..paramsPos-1:
|
||||
|
||||
@@ -6154,9 +6154,12 @@ scope is controlled by the `inject`:idx: and `gensym`:idx: pragmas:
|
||||
`gensym`'ed symbols are not exposed but `inject`'ed symbols are.
|
||||
|
||||
The default for symbols of entity `type`, `var`, `let` and `const`
|
||||
is `gensym` and for `proc`, `iterator`, `converter`, `template`,
|
||||
`macro` is `inject`. However, if the name of the entity is passed as a
|
||||
template parameter, it is an `inject`'ed symbol:
|
||||
is `gensym`. For `proc`, `iterator`, `converter`, `template`,
|
||||
`macro`, the default is `inject`, but if a `gensym` symbol with the same name
|
||||
is defined in the same syntax-level scope, it will be `gensym` by default.
|
||||
This can be overriden by marking the routine as `inject`.
|
||||
|
||||
If the name of the entity is passed as a template parameter, it is an `inject`'ed symbol:
|
||||
|
||||
```nim
|
||||
template withFile(f, fn, mode: untyped, actions: untyped): untyped =
|
||||
|
||||
@@ -7,7 +7,7 @@ block:
|
||||
when false:
|
||||
let x = 123
|
||||
else:
|
||||
template x: untyped = 456
|
||||
template x: untyped {.inject.} = 456
|
||||
echo x #[tt.Error
|
||||
^ undeclared identifier: 'x`gensym0'; if declared in a template, this identifier may be inconsistently marked inject or gensym]#
|
||||
foo()
|
||||
|
||||
@@ -6,3 +6,15 @@ block: # #20002
|
||||
discard 3.bar # evaluates to 10 but only check if it compiles for now
|
||||
block:
|
||||
foo()
|
||||
|
||||
block: # issue #23813
|
||||
template r(body: untyped) =
|
||||
proc x() {.gensym.} =
|
||||
body
|
||||
template g() =
|
||||
r:
|
||||
let y = 0
|
||||
r:
|
||||
proc y() = discard
|
||||
y()
|
||||
g()
|
||||
|
||||
Reference in New Issue
Block a user