gh-140596: Substitute earlier type parameters into PEP 696 defaults - #155646
Open
KotlinIsland wants to merge 1 commit into
Open
gh-140596: Substitute earlier type parameters into PEP 696 defaults#155646KotlinIsland wants to merge 1 commit into
KotlinIsland wants to merge 1 commit into
Conversation
…ults The default of a type parameter may refer to type parameters that appear earlier in the same type parameter list. Those references are now replaced by the values supplied for the earlier type parameters when the default is filled in, so ``class Bar[T, S = T]`` gives ``Bar[int, int]`` for ``Bar[int]`` instead of leaving ``S`` bound to the unsubstituted ``T``. Leaving it unsubstituted leaked ``T`` into the specialization, which made ``class Baz[U](Bar[U])`` fail with "Some type variables (T) are not listed in Generic[U]". The substitution happens in ``__typing_prepare_subst__``, where the values of all earlier type parameters are already known, so it applies to ``TypeVar``, ``ParamSpec`` and ``TypeVarTuple`` defaults and to both generic classes and generic aliases. A default that refers to a type parameter which is not declared before it, whether a self-reference (``class A[T = T]``) or a cycle (``class A[T = S, S = T]``), now raises TypeError when the default is used.
KotlinIsland
requested review from
AA-Turner,
AlexWaygood,
JelleZijlstra and
willingc
as code owners
August 12, 2026 23:43
Documentation build overview
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A type parameter default may refer to type parameters that appear earlier in
the same type parameter list, but those references were never substituted:
Because the unsubstituted
Tstayed in the specialization, it leaked into__parameters__, so omitting a defaulted type parameter when subclassingfailed:
PEP 696 and the typing spec both allow a default to refer to a prior type
parameter and require non-overridden defaults to be substituted in.
Fix
The substitution is done in
__typing_prepare_subst__, at the point where thedefault is filled in. That is the natural place for it: a type parameter only
falls back to its default once every preceding type parameter has a value, so
argsalready holds exactly the bindings the default needs.Doing it there means one shared helper (
typing._resolve_type_param_default)covers
TypeVar,ParamSpecandTypeVarTupledefaults, and covers both_generic_class_getitemand_GenericAlias._determine_new_args— the aliaspath had the same bug:
TypeVar.__typing_prepare_subst__is implemented in C, so it calls the helperthrough
call_typing_func_object, the same way the neighbouring_typevar_subst,_paramspec_prepare_substand_typevartuple_prepare_substhooks already do. The call only happens when a default is actually used.
Type parameters that come from an enclosing scope (they are not in the
subscripted object's
__parameters__) are left untouched, preserving theexisting behaviour for free type variables.
Behaviour change
A default that refers to a type parameter which is not declared before it now
raises
TypeErrorwhen the default is used, rather than silently producing anonsensical specialization. This covers self-references and cycles, both of
which the typing spec disallows: