diff options
-rw-r--r-- | compiler/semtempl.nim | 12 | ||||
-rw-r--r-- | doc/manual.md | 9 | ||||
-rw-r--r-- | tests/errmsgs/tinconsistentgensym.nim | 2 | ||||
-rw-r--r-- | tests/template/tinnerouterproc.nim | 12 |
4 files changed, 26 insertions, 9 deletions
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index f2083c85c..c6f2fb60c 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -256,25 +256,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) @@ -286,7 +288,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: diff --git a/doc/manual.md b/doc/manual.md index 16c116328..e471658a4 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -6216,9 +6216,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 = diff --git a/tests/errmsgs/tinconsistentgensym.nim b/tests/errmsgs/tinconsistentgensym.nim index 026c17fca..8e4c85106 100644 --- a/tests/errmsgs/tinconsistentgensym.nim +++ b/tests/errmsgs/tinconsistentgensym.nim @@ -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() diff --git a/tests/template/tinnerouterproc.nim b/tests/template/tinnerouterproc.nim index 1f15fb13e..56e0d02df 100644 --- a/tests/template/tinnerouterproc.nim +++ b/tests/template/tinnerouterproc.nim @@ -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() |