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.
This commit is contained in:
ringabout
2026-06-08 14:55:37 +08:00
committed by GitHub
parent 4497d89267
commit f5930d0bb3
3 changed files with 37 additions and 1 deletions

View File

@@ -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

16
tests/generics/t20811.nim Normal file
View File

@@ -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)

View File

@@ -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