From f5930d0bb36c94980e4c0bc3d455c6f42e740672 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 8 Jun 2026 14:55:37 +0800 Subject: [PATCH] fixes #20811; Nested proc with inner being generic cannot access parameters of outer proc (#25837) fixes #20811 This pull request addresses issues with parameter capture in nested generic procedures and templates, ensuring that outer parameters are correctly visible and accessible within nested scopes. The main changes include a fix in the semantic analysis logic and the addition of targeted regression tests. ### Semantic analysis improvements: * Updated `semGenericStmtSymbol` in `compiler/semgnrc.nim` to ensure that parameters from outer scopes are preserved and accessible in nested generic procedures, fixing visibility issues with captured parameters. ### Added regression tests: * Added `tests/generics/t20811.nim` to verify that both generic and plain inner procedures can access parameters from their enclosing procedure. * Extended `tests/template/topensym.nim` with a new block for issue #20811 to test that template-injected parameters are correctly captured and visible in nested generic procedures. --- compiler/semgnrc.nim | 9 ++++++++- tests/generics/t20811.nim | 16 ++++++++++++++++ tests/template/topensym.nim | 13 +++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 tests/generics/t20811.nim diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 10bb33bcdc..1d12ae970a 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -129,7 +129,14 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, result.typ = nil onUse(n.info, s) of skParam: - result = n + if s.owner == c.p.owner: + # Parameters of the routine currently being semchecked stay as local + # identifiers + result = n + else: + # Preserve captured outer parameters so nested generic procs can still + # see them after the generic pre-pass. + result = newSymNode(s, n.info) onUse(n.info, s) of skType: if (s.typ != nil) and diff --git a/tests/generics/t20811.nim b/tests/generics/t20811.nim new file mode 100644 index 0000000000..f165782719 --- /dev/null +++ b/tests/generics/t20811.nim @@ -0,0 +1,16 @@ +discard """ + output: '''42 +42''' +""" + +proc outer(j: int) = + proc genericInner[T](): int = + j + + proc plainInner(): int = + j + + echo genericInner[int]() + echo plainInner() + +outer(42) \ No newline at end of file diff --git a/tests/template/topensym.nim b/tests/template/topensym.nim index 2f930407b9..25127021d9 100644 --- a/tests/template/topensym.nim +++ b/tests/template/topensym.nim @@ -135,6 +135,19 @@ block: # issue #22605 for templates, original complex example doAssert g2(int) == "error" +block: # issue #20811 + template injectError(body: untyped): untyped = + template error: untyped {.used, inject.} = "injected" + body + + proc outerOpen(error: string): string = + injectError: + proc genericInner[T](): string = + error + genericInner[int]() + + doAssert outerOpen("captured") == "injected" + block: # issue #23865 for templates type Xxx = enum error