diff --git a/crates/ty_python_semantic/resources/mdtest/expression/len.md b/crates/ty_python_semantic/resources/mdtest/expression/len.md index 573005d522..31770e9557 100644 --- a/crates/ty_python_semantic/resources/mdtest/expression/len.md +++ b/crates/ty_python_semantic/resources/mdtest/expression/len.md @@ -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 diff --git a/crates/ty_python_semantic/resources/mdtest/generics/legacy/functions.md b/crates/ty_python_semantic/resources/mdtest/generics/legacy/functions.md index 34347ea1aa..c2fb6cbc1b 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/legacy/functions.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/legacy/functions.md @@ -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]): ... diff --git a/crates/ty_python_semantic/resources/mdtest/generics/pep695/functions.md b/crates/ty_python_semantic/resources/mdtest/generics/pep695/functions.md index da4ac30924..6dda932d4f 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/pep695/functions.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/pep695/functions.md @@ -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]): ... diff --git a/crates/ty_python_semantic/resources/mdtest/protocols.md b/crates/ty_python_semantic/resources/mdtest/protocols.md index 7645ba31c5..1cc6e98f47 100644 --- a/crates/ty_python_semantic/resources/mdtest/protocols.md +++ b/crates/ty_python_semantic/resources/mdtest/protocols.md @@ -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