…tches
The spec's "Function Defaults" section previously said generic function
TypeVar defaults are "unspecified" in all cases. However, there is a
concrete, well-defined case that can and should be specified: when a
TypeVar S with default D is used as the type of exactly one parameter p,
and p's default argument value is assignable to D, calling the function
without p must be type-checked as if p's default value were passed
explicitly. Type checkers must therefore infer S = D.
Additionally, the function definition itself is valid in this case:
the default argument is checked for assignability against D (the TypeVar's
default type), not against the free TypeVar S.
Spec change: docs/spec/generics.rst — "Function Defaults" section
Conformance test: new section at end of generics_defaults.py using a
Getter[T] class whose .get() method has S=None default.
Checker results:
pyright, pyrefly, pycroscope — pass all new assertions
mypy, zuban — incorrectly reject the function definition (Partial)
ty — incorrectly rejects the function definition; correctly infers
the return types (Partial)
Fixes: python#2213
Summary
Fixes #2213.
The spec's "Function Defaults" section previously left all generic-function TypeVar default semantics unspecified. However, there is a concrete, well-defined case that can and should be specified:
Additionally, the function definition is valid in this case: the default argument is checked against D (the TypeVar's default), not against the free TypeVar S itself.
This is already the behavior of pyright (and pyrefly, pycroscope) — the spec is simply catching up.
Changes
Checker behaviour at a glance
Test plan