Repository navigation
Conversation
Contributor
|
Diff from mypy_primer, showing the effect of this PR on open source code: pywin32 (https://github.com/mhammond/pywin32)
./pythonwin/pywin/test/_dbgscript.py: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
- version: 2.5.0+dev.1e2ea5350dd8fa4d44a1d381b1ae0097d880ed2d
+ version: 2.5.0+dev.7d5b2b3f0d73599f10bbac8393ee465d1cd91044
|
Author
|
Primer note on the pywin32 |
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.
Fixes #22399
When a function return type is a generic alias over
CallablewhoseParamSpec slot is filled with a concrete parameter list, e.g.
Alias[[int], T]whereAlias = Callable[P, T], mypy reportedType variable "T" is unbound(orName "T" is not definedfor thePEP 695
typeform), even though the equivalent literalCallable[[int], T]is accepted. pyright, pyrefly and ty all acceptthe alias form.
Two things combined to produce the error:
infer_type_variablesscans the return type withinclude_callables = False, soFindTypeVarVisitorreturns earlyon the alias application (its first argument looks like a callable
argument list) and never collects
T.TypeAliasbranch ofvisit_unbound_type_nonoptionalthenanalyzes the alias arguments in the enclosing scope before the
alias is expanded, so the unbound
Terrors out before expansion.The fix mirrors how a literal
Callableis handled: when the aliastarget is a
CallableTypeand its arguments contain a type variablethat is not bound in the enclosing scope, expand the alias and
analyze the resulting callable, so the callable itself binds the
free type variable — exactly as
Callable[[int], T]does. That iswhy
Alias[[int], T]now reveals asdef () -> def [T] (int) -> T, withTbound to the inner callableand not to the outer function.
A second pass (
ResolveUnboundTypeVars) replaces any remainingUnboundTypeoccurrences inside the analyzed callable with thecallable's own type variables of the same name. Analyzing a callable
does not recurse into already-analyzed instances or alias
applications, so without it a type variable nested inside a generic
instance in the alias target (e.g.
Chain[P, T]in the motivatingexample from the issue) stayed unresolved and broke generic
inference. If the alias cannot be expanded to a callable, the code
falls back to the previous analysis unchanged.
Disclosure: this PR was developed with the assistance of an LLM
(Muse), with the fix verified against the test suites listed below.
Tests run (all with the repo's pytest data-driven suites):
testParamSpecAliasUnboundTypeVar(
check-parameter-specification.test) andtestPEP695ParamSpecAliasUnboundTypeVar(
check-python312.test). Both fail on unmodified code and passwith this change.
check-parameter-specification.test,check-python312.test,check-generic-alias.test,check-type-aliases.test,check-typevar-unbound.test: 373 passed.check-generics.test,check-callable.test,check-functions.test: 518 passed, 2 skipped.mypy/test/testcheck.py: 8318 passed, 27 skipped,7 xfailed.
mypy/test/testsemanal.py -k "typealiases or paramspec":28 passed.
python -m mypy --config-file mypy_self_check.ini mypy/typeanal.py: no issues.