[ty] Minor fixes to Protocol tests (#20347)

This commit is contained in:
Alex Waygood 2025-09-11 15:42:13 +01:00 committed by GitHub
parent ffd4340dce
commit 0e3697a643
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 25 additions and 6 deletions

View file

@ -260,7 +260,7 @@ class SecondRequiredArgument:
def __len__(self, v: int) -> Literal[1]:
return 1
# TODO: Emit a diagnostic
# this is fine: the call succeeds at runtime since the second argument is optional
reveal_type(len(SecondOptionalArgument())) # revealed: Literal[0]
# TODO: Emit a diagnostic

View file

@ -77,7 +77,7 @@ from typing import Protocol, TypeVar
T = TypeVar("T")
class CanIndex(Protocol[T]):
def __getitem__(self, index: int) -> T: ...
def __getitem__(self, index: int, /) -> T: ...
class ExplicitlyImplements(CanIndex[T]): ...

View file

@ -72,7 +72,7 @@ from typing import Protocol, TypeVar
S = TypeVar("S")
class CanIndex(Protocol[S]):
def __getitem__(self, index: int) -> S: ...
def __getitem__(self, index: int, /) -> S: ...
class ExplicitlyImplements[T](CanIndex[T]): ...

View file

@ -1813,9 +1813,28 @@ class Foo:
static_assert(not is_assignable_to(Foo, Iterable[Any]))
```
Because method members must always be available on the class, it is safe to access a method on
`type[P]`, where `P` is a protocol class, just like it is generally safe to access a method on
`type[C]` where `C` is a nominal class:
Because method members are always looked up on the meta-type of an object when testing assignability
and subtyping, we understand that `IterableClass` here is a subtype of `Iterable[int]` even though
`IterableClass.__iter__` has the wrong signature:
```py
from typing import Iterator, Iterable
from ty_extensions import static_assert, is_subtype_of, TypeOf
class Meta(type):
def __iter__(self) -> Iterator[int]:
yield from range(42)
class IterableClass(metaclass=Meta):
def __iter__(self) -> Iterator[str]:
yield from "abc"
static_assert(is_subtype_of(TypeOf[IterableClass], Iterable[int]))
```
Enforcing that members must always be available on the class also means that it is safe to access a
method on `type[P]`, where `P` is a protocol class, just like it is generally safe to access a
method on `type[C]` where `C` is a nominal class:
```py
from typing import Protocol