Python: omit PEP 695 type-param names from FunctionDefExpr/ClassDefExpr children

PEP 695 type-param names (e.g. `T` in `def func[T]:` or `class Box[T]:`)
bind in an annotation scope that nests the function/class body, so
their AST scope is the inner function/class — not the enclosing scope
where the FunctionDefExpr/ClassDefExpr CFG node lives. Visiting them
as children created scope-crossing CFG edges (nonLocalStep violations:
96 across CPython).

Drop them from the children list; the legacy CFG omitted them too.
TypeAliasStmt is unaffected (its type-params share scope with the
alias's enclosing scope).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
yoff
2026-05-26 17:09:09 +00:00
parent d5f1e092dd
commit 2d997aaaf4
2 changed files with 22 additions and 36 deletions

View File

@@ -1,15 +1,18 @@
# PEP 695 type parameters (Python 3.12+).
def func[T](x: T) -> T: # $ cfgdefines=func cfgdefines=x cfgdefines=T
# PEP 695 type-param names on `def`/`class` bind in an annotation scope
# that nests the function/class body — they have no CFG node in the
# enclosing scope (matching the legacy CFG).
def func[T](x: T) -> T: # $ cfgdefines=func cfgdefines=x
return x
class Box[T]: # $ cfgdefines=Box cfgdefines=T
class Box[T]: # $ cfgdefines=Box
item: T # $ cfgdefines=item
# Multi-parameter, with bound and variadics.
def multi[T: int, *Ts, **P](x: T, *args: *Ts, **kwargs: P.kwargs) -> T: # $ cfgdefines=multi cfgdefines=x cfgdefines=args cfgdefines=kwargs cfgdefines=T cfgdefines=Ts cfgdefines=P
def multi[T: int, *Ts, **P](x: T, *args: *Ts, **kwargs: P.kwargs) -> T: # $ cfgdefines=multi cfgdefines=x cfgdefines=args cfgdefines=kwargs
return x