Repository navigation
Type substitutions in Callable ignore TypeVar bounds #8922
Description
Activity
When substituting values for type variables in generic type aliases, mypy doesn't check that the value is compatible with the bound. Here's a simplified repro:
from typing import Callable, TypeVar, List N = TypeVar('N', bound='int') F = Callable[[], N] L = List[N] x: F[str] # No error, but should be error y: L[str] # No error, but should be error
Reacted by EdwardBlairThe
fAnycase is working as designed. If a type variable is omitted, it defaults toAny. It's pretty confusing, and I'd suggest using--disallow-any-generics.- addedbugmypy got something wrongmypy got something wrong
on Jun 8, 2020 The
fAnycase is working as designed. If a type variable is omitted, it defaults toAny.What does
Anymean exactly? From the name, I would assume it means "any type": a unique anonymousTypeVar. But in how it is implemented, it seems to mean "we don't know anything about this type".In your simplified repro,
y: L[T]implies:isinstance(a, T)holds for every elementainy(property ofList)issubclass(T, int)holds (bound ofN)
Combining both implications, this means that for any type
Tthat can be substituted forN,isinstance(a, int)holds for every elementainy.So even if we don't know which concrete type is passed to
L, we do know that the elements of the list must all be integers. But this information is lost ifL[Any]is evaluated asList[Any].Note that the
fAnycase isn't important to me as a programmer, but I think it's interesting from a theoretical point of view.I opened a separate issue about the handling of
Any: #8981, since that is not about checking the substitution, but about remembering the bound in the substitution result.The
fAnycase is working as designed. If a type variable is omitted, it defaults toAny.Should this be the case though?
The fact that theboundparameter has been specified implies that theBTtypevar cannot adopt any arbitrary value;
yet defaulting toAnysuggests the opposite.Would it not make more sense to default to whichever value is specified as
bound?When substituting values for type variables in generic type aliases, mypy doesn't check that the value is compatible with the bound. Here's a simplified repro
Deserves separate issue.
Still happens in 0.931.
Mypy now checks for type variable bounds in type aliases.
When I run mypy on the following code:
It outputs:
All of the things mypy warns about are valid. But there are also statements it doesn't warn about that are incorrect code.
The most clear one is the type annotation of
fOther(last line of the test case): while the functionfdoes indeed return an object of typeOther, that type gets substituted forBTin the definition ofFactoryandBThasBaseas its bound, which is a type unrelated toOther.A similar but more complex case can be made for
fAny, which doesn't provide a type argument. However, there cannot exist a type argument that would satisfy both the bound ofBTand the signature off.I have limited knowledge of the internals of mypy, but it seems feasible that the
fOthercase could be reported. If thefAnycase can be reported as well that would be great, but I can imagine that determining that no valid type argument can exist is a lot harder than validating a given type argument.I'm using mypy 0.770 on Python 3.8.2.