Skip to content

Conversation

@dcreager
Copy link
Member

@dcreager dcreager commented Nov 20, 2025

This is a first stab at solving astral-sh/ty#500, at least in part, with the old solver. We add a new TypeRelation that lets us opt into using constraint sets to describe when a typevar is assignability to some type, and then use that to calculate a constraint set that describes when two callable types are assignable. If the callable types contain typevars, that constraint set will describe their valid specializations. We can then walk through all of the ways the constraint set can be satisfied, and record a type mapping in the old solver for each one.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Nov 20, 2025

Diagnostic diff on typing conformance tests

Changes were detected when running ty on typing conformance tests
--- old-output.txt	2025-12-07 20:02:21.310268039 +0000
+++ new-output.txt	2025-12-07 20:02:25.031281607 +0000
@@ -150,7 +150,8 @@
 callables_protocol.py:169:7: error[invalid-assignment] Object of type `def cb8_bad1(x: int) -> Any` is not assignable to `Proto8`
 callables_protocol.py:186:5: error[invalid-assignment] Object of type `Literal["str"]` is not assignable to attribute `other_attribute` of type `int`
 callables_protocol.py:187:5: error[unresolved-attribute] Unresolved attribute `xxx` on type `Proto9[P@decorator1, R@decorator1]`.
-callables_protocol.py:197:7: error[unresolved-attribute] Object of type `Proto9[(x: int), Unknown] | Proto9[Divergent, Unknown]` has no attribute `other_attribute2`
+callables_protocol.py:197:7: error[unresolved-attribute] Object of type `Proto9[(x: int), str] | Proto9[(x: Never), Unknown]` has no attribute `other_attribute2`
+callables_protocol.py:199:10: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Never`, found `Literal[3]`
 callables_protocol.py:238:8: error[invalid-assignment] Object of type `def cb11_bad1(x: int, y: str, /) -> Any` is not assignable to `Proto11`
 callables_protocol.py:260:8: error[invalid-assignment] Object of type `def cb12_bad1(*args: Any, *, kwarg0: Any) -> None` is not assignable to `Proto12`
 callables_protocol.py:284:27: error[invalid-assignment] Object of type `def cb13_no_default(path: str) -> str` is not assignable to `Proto13_Default`
@@ -236,37 +237,42 @@
 constructors_call_type.py:59:9: error[too-many-positional-arguments] Too many positional arguments to bound method `__init__`: expected 1, got 2
 constructors_call_type.py:81:5: error[missing-argument] No argument provided for required parameter `y` of function `__new__`
 constructors_call_type.py:82:12: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `str`, found `Literal[2]`
-constructors_callable.py:36:13: info[revealed-type] Revealed type: `(x: int) -> Unknown`
-constructors_callable.py:37:1: error[type-assertion-failure] Type `Class1` does not match asserted type `Unknown`
+constructors_callable.py:36:13: info[revealed-type] Revealed type: `(x: int) -> Class1`
 constructors_callable.py:38:1: error[missing-argument] No argument provided for required parameter `x`
 constructors_callable.py:39:1: error[missing-argument] No argument provided for required parameter `x`
 constructors_callable.py:39:4: error[unknown-argument] Argument `y` does not match any known parameter
-constructors_callable.py:49:13: info[revealed-type] Revealed type: `() -> Unknown`
-constructors_callable.py:50:1: error[type-assertion-failure] Type `Class2` does not match asserted type `Unknown`
+constructors_callable.py:49:13: info[revealed-type] Revealed type: `() -> Class2`
 constructors_callable.py:51:4: error[too-many-positional-arguments] Too many positional arguments: expected 0, got 1
 constructors_callable.py:57:42: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@__new__`
-constructors_callable.py:63:13: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:64:1: error[type-assertion-failure] Type `Class3` does not match asserted type `Unknown`
+constructors_callable.py:62:23: error[invalid-argument-type] Argument to function `accepts_callable` is incorrect: Expected `() -> Class3`, found `<class 'Class3'>`
+constructors_callable.py:63:13: info[revealed-type] Revealed type: `() -> Class3`
+constructors_callable.py:64:16: error[too-many-positional-arguments] Too many positional arguments: expected 0, got 1
+constructors_callable.py:66:4: error[unknown-argument] Argument `y` does not match any known parameter
+constructors_callable.py:67:4: error[too-many-positional-arguments] Too many positional arguments: expected 0, got 2
 constructors_callable.py:73:33: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
-constructors_callable.py:77:13: info[revealed-type] Revealed type: `(x: int) -> Unknown`
-constructors_callable.py:78:1: error[type-assertion-failure] Type `int` does not match asserted type `Unknown`
+constructors_callable.py:77:13: info[revealed-type] Revealed type: `(x: int) -> int`
 constructors_callable.py:79:1: error[missing-argument] No argument provided for required parameter `x`
 constructors_callable.py:80:1: error[missing-argument] No argument provided for required parameter `x`
 constructors_callable.py:80:4: error[unknown-argument] Argument `y` does not match any known parameter
-constructors_callable.py:97:13: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:100:5: error[type-assertion-failure] Type `Never` does not match asserted type `Unknown`
-constructors_callable.py:105:5: error[type-assertion-failure] Type `Never` does not match asserted type `Unknown`
-constructors_callable.py:125:13: info[revealed-type] Revealed type: `() -> Unknown`
-constructors_callable.py:126:1: error[type-assertion-failure] Type `Class6Proxy` does not match asserted type `Unknown`
+constructors_callable.py:97:13: info[revealed-type] Revealed type: `() -> Never`
+constructors_callable.py:105:20: error[too-many-positional-arguments] Too many positional arguments: expected 0, got 1
+constructors_callable.py:105:23: error[unknown-argument] Argument `x` does not match any known parameter
+constructors_callable.py:125:13: info[revealed-type] Revealed type: `() -> Class6Proxy`
 constructors_callable.py:127:4: error[too-many-positional-arguments] Too many positional arguments: expected 0, got 1
-constructors_callable.py:142:13: info[revealed-type] Revealed type: `(...) -> Unknown`
-constructors_callable.py:162:5: info[revealed-type] Revealed type: `Overload[(x: int) -> Unknown, (x: str) -> Unknown]`
-constructors_callable.py:164:1: error[type-assertion-failure] Type `Class7[int]` does not match asserted type `Unknown`
-constructors_callable.py:165:1: error[type-assertion-failure] Type `Class7[str]` does not match asserted type `Unknown`
-constructors_callable.py:182:13: info[revealed-type] Revealed type: `(x: list[Unknown], y: list[Unknown]) -> Unknown`
-constructors_callable.py:183:1: error[type-assertion-failure] Type `Class8[str]` does not match asserted type `Unknown`
-constructors_callable.py:193:13: info[revealed-type] Revealed type: `(x: list[T@__init__], y: list[T@__init__]) -> Unknown`
-constructors_callable.py:194:1: error[type-assertion-failure] Type `Class9` does not match asserted type `Unknown`
+constructors_callable.py:141:27: error[invalid-argument-type] Argument to function `accepts_callable` is incorrect: Expected `() -> Class6Any`, found `<class 'Class6Any'>`
+constructors_callable.py:142:13: info[revealed-type] Revealed type: `() -> Class6Any`
+constructors_callable.py:143:1: error[type-assertion-failure] Type `Any` does not match asserted type `Class6Any`
+constructors_callable.py:144:8: error[too-many-positional-arguments] Too many positional arguments: expected 0, got 1
+constructors_callable.py:162:5: info[revealed-type] Revealed type: `Overload[(x: int) -> Class7[int] | Class7[str], (x: str) -> Class7[int] | Class7[str]]`
+constructors_callable.py:164:1: error[type-assertion-failure] Type `Class7[int]` does not match asserted type `Class7[int] | Class7[str]`
+constructors_callable.py:165:1: error[type-assertion-failure] Type `Class7[str]` does not match asserted type `Class7[int] | Class7[str]`
+constructors_callable.py:182:13: info[revealed-type] Revealed type: `(x: list[T@Class8], y: list[T@Class8]) -> Class8[T@Class8]`
+constructors_callable.py:183:1: error[type-assertion-failure] Type `Class8[str]` does not match asserted type `Class8[T@Class8]`
+constructors_callable.py:183:16: error[invalid-argument-type] Argument is incorrect: Expected `list[T@Class8]`, found `list[Unknown | str]`
+constructors_callable.py:183:22: error[invalid-argument-type] Argument is incorrect: Expected `list[T@Class8]`, found `list[Unknown | str]`
+constructors_callable.py:184:4: error[invalid-argument-type] Argument is incorrect: Expected `list[T@Class8]`, found `list[Unknown | int]`
+constructors_callable.py:184:9: error[invalid-argument-type] Argument is incorrect: Expected `list[T@Class8]`, found `list[Unknown | str]`
+constructors_callable.py:193:13: info[revealed-type] Revealed type: `(x: list[T@__init__], y: list[T@__init__]) -> Class9`
 constructors_callable.py:194:16: error[invalid-argument-type] Argument is incorrect: Expected `list[T@__init__]`, found `list[Unknown | str]`
 constructors_callable.py:194:22: error[invalid-argument-type] Argument is incorrect: Expected `list[T@__init__]`, found `list[Unknown | str]`
 constructors_callable.py:195:4: error[invalid-argument-type] Argument is incorrect: Expected `list[T@__init__]`, found `list[Unknown | int]`
@@ -305,6 +311,7 @@
 dataclasses_transform_converter.py:25:6: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `T@model_field`
 dataclasses_transform_converter.py:48:31: error[invalid-argument-type] Argument to function `model_field` is incorrect: Expected `(Unknown, /) -> Unknown`, found `def bad_converter1() -> int`
 dataclasses_transform_converter.py:49:31: error[invalid-argument-type] Argument to function `model_field` is incorrect: Expected `(Unknown, /) -> Unknown`, found `def bad_converter2(*, x: int) -> int`
+dataclasses_transform_converter.py:104:30: error[invalid-assignment] Object of type `dataclasses.Field[dict[str, str] | dict[_KT@dict, _VT@dict]]` is not assignable to `dict[str, str]`
 dataclasses_transform_converter.py:107:8: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `Literal["f1"]`
 dataclasses_transform_converter.py:107:14: error[invalid-argument-type] Argument is incorrect: Expected `int`, found `Literal["f2"]`
 dataclasses_transform_converter.py:107:20: error[invalid-argument-type] Argument is incorrect: Expected `ConverterClass`, found `Literal[b"f3"]`
@@ -407,7 +414,7 @@
 enums_member_values.py:96:1: error[type-assertion-failure] Type `int` does not match asserted type `Unknown`
 enums_members.py:82:1: error[type-assertion-failure] Type `Unknown` does not match asserted type `Unknown | ((x) -> Unknown)`
 enums_members.py:82:37: error[invalid-type-form] Type arguments for `Literal` must be `None`, a literal value (int, bool, str, or bytes), or an enum member
-enums_members.py:83:1: error[type-assertion-failure] Type `Unknown` does not match asserted type `Unknown | ((x: int) -> Unknown)`
+enums_members.py:83:1: error[type-assertion-failure] Type `Unknown` does not match asserted type `Unknown | ((x: int) -> int)`
 enums_members.py:83:37: error[invalid-type-form] Type arguments for `Literal` must be `None`, a literal value (int, bool, str, or bytes), or an enum member
 enums_members.py:84:1: error[type-assertion-failure] Type `Unknown` does not match asserted type `property`
 enums_members.py:84:35: error[invalid-type-form] Type arguments for `Literal` must be `None`, a literal value (int, bool, str, or bytes), or an enum member
@@ -1030,4 +1037,4 @@
 typeddicts_usage.py:28:17: error[missing-typed-dict-key] Missing required key 'name' in TypedDict `Movie` constructor
 typeddicts_usage.py:28:18: error[invalid-key] Unknown key "title" for TypedDict `Movie`: Unknown key "title"
 typeddicts_usage.py:40:24: error[invalid-type-form] The special form `typing.TypedDict` is not allowed in type expressions
-Found 1032 diagnostics
+Found 1039 diagnostics

@astral-sh-bot
Copy link

astral-sh-bot bot commented Nov 20, 2025

mypy_primer results

Changes were detected when running on open source projects
attrs (https://github.com/python-attrs/attrs)
+ tests/test_validators.py:297:18: error[no-matching-overload] No overload of function `attrib` matches arguments
+ tests/test_validators.py:787:21: error[invalid-argument-type] Argument to function `and_` is incorrect: Expected `(Any, Attribute[int], int, /) -> Any`, found `(Any, Attribute[Literal[10]], Literal[10], /) -> Any`
+ tests/test_validators.py:1257:20: error[invalid-argument-type] Argument is incorrect: Expected `int | float`, found `Literal["spam"]`
- Found 601 diagnostics
+ Found 604 diagnostics

anyio (https://github.com/agronholm/anyio)
- src/anyio/_backends/_asyncio.py:2565:13: error[invalid-argument-type] Argument to bound method `run` is incorrect: Expected `Coroutine[Any, Any, _T@run_coroutine_threadsafe]`, found `CoroutineType[Any, Any, T_Retval@run_async_from_thread]`
+ src/anyio/_backends/_asyncio.py:2650:31: warning[redundant-cast] Value is already of type `tuple[Transport, StreamProtocol]`
+ src/anyio/_core/_fileio.py:190:22: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `IO[str]`, found `Top[IO[Any]]`
+ src/anyio/_core/_fileio.py:627:26: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `IO[str]`, found `Top[IO[Any]]`
- Found 90 diagnostics
+ Found 92 diagnostics

nionutils (https://github.com/nion-software/nionutils)
+ nion/utils/ThreadPool.py:40:26: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Never`, found `Queue[Unknown]`
- Found 23 diagnostics
+ Found 24 diagnostics

async-utils (https://github.com/mikeshardmind/async-utils)
+ src/async_utils/corofunc_cache.py:146:16: error[invalid-return-type] Return type does not match returned value: expected `CoroFunc[P@wrapper, R@wrapper]`, found `_Wrapped[(...), Unknown, (...), Unknown] | _Wrapped[(...), Unknown, (...), CoroutineType[object, Never, object]]`
+ src/async_utils/corofunc_cache.py:229:16: error[invalid-return-type] Return type does not match returned value: expected `CoroFunc[P@wrapper, R@wrapper]`, found `_Wrapped[(...), Unknown, (...), Unknown] | _Wrapped[(...), Unknown, (...), CoroutineType[object, Never, object]]`
- src/async_utils/gen_transform.py:110:36: error[invalid-argument-type] Argument to function `to_thread` is incorrect: Expected `Queue[Y@_consumer]`, found `Queue[Y@_sync_to_async_gen]`
- src/async_utils/gen_transform.py:110:48: error[invalid-argument-type] Argument to function `to_thread` is incorrect: Expected `(**P@_consumer) -> Generator[Y@_consumer, None, None]`, found `(**P@_sync_to_async_gen) -> Generator[Y@_sync_to_async_gen, None, None]`
- src/async_utils/gen_transform.py:110:60: error[invalid-argument-type] Argument to function `to_thread` is incorrect: Expected `P@_consumer.args`, found `P@_sync_to_async_gen.args`
- src/async_utils/gen_transform.py:110:63: error[invalid-argument-type] Argument to function `to_thread` is incorrect: Expected `P@_consumer.kwargs`, found `P@_sync_to_async_gen.kwargs`
- Found 15 diagnostics
+ Found 13 diagnostics

pip (https://github.com/pypa/pip)
+ src/pip/_internal/index/collector.py:215:12: error[invalid-return-type] Return type does not match returned value: expected `ParseLinks`, found `_Wrapped[(page: IndexContent), Iterable[Link], (page: IndexContent), list[Link]] | _Wrapped[(page: IndexContent), Iterable[Link], (page: Never), Unknown]`
- Found 601 diagnostics
+ Found 602 diagnostics

asynq (https://github.com/quora/asynq)
- asynq/tests/test_tools.py:72:39: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@afilter]`, found `list[Unknown | None | int]`
- asynq/tests/test_tools.py:74:34: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@afilter]`, found `list[Unknown | None | int]`
- asynq/tests/test_tools.py:82:53: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@afilterfalse]`, found `list[Unknown | None | int]`
- asynq/tests/test_tools.py:90:53: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@asift]`, found `list[Unknown | None | int]`
- asynq/tests/test_tools.py:95:45: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amap]`, found `list[Unknown | None]`
- asynq/tests/test_tools.py:96:44: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amap]`, found `list[Unknown | int]`
- asynq/tests/test_tools.py:98:58: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amap]`, found `list[Unknown | None | str]`
- asynq/tests/test_tools.py:103:31: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@asorted]`, found `list[Unknown | None]`
- asynq/tests/test_tools.py:104:37: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@asorted]`, found `list[Unknown | bool | None]`
- asynq/tests/test_tools.py:105:31: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@asorted]`, found `list[Unknown | int]`
- asynq/tests/test_tools.py:109:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `Literal[1]`
- asynq/tests/test_tools.py:109:26: error[too-many-positional-arguments] Too many positional arguments to bound method `__call__`: expected 2, got 3
- asynq/tests/test_tools.py:110:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `list[Unknown | int | None]`
- asynq/tests/test_tools.py:111:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `GeneratorType[Literal[1] | None, None, None]`
- asynq/tests/test_tools.py:112:31: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `list[Unknown | int]`
- asynq/tests/test_tools.py:112:36: error[too-many-positional-arguments] Too many positional arguments to bound method `__call__`: expected 2, got 4
- asynq/tests/test_tools.py:113:31: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `list[Unknown | list[Unknown | int]]`
- asynq/tests/test_tools.py:115:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `Literal[1]`
- asynq/tests/test_tools.py:115:26: error[too-many-positional-arguments] Too many positional arguments to bound method `__call__`: expected 2, got 5
- asynq/tests/test_tools.py:118:9: error[missing-argument] No argument provided for required parameter `arg` of bound method `__call__`
- asynq/tests/test_tools.py:122:33: error[unknown-argument] Argument `random_keyword_argument` does not match any known parameter of bound method `__call__`
- asynq/tests/test_tools.py:126:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amin]`, found `Literal[1]`
- asynq/tests/test_tools.py:126:35: error[parameter-already-assigned] Multiple values provided for parameter `key` of bound method `__call__`
- asynq/tests/test_tools.py:127:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amin]`, found `list[Unknown | int | None]`
- asynq/tests/test_tools.py:128:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amin]`, found `GeneratorType[Literal[1] | None, None, None]`
- asynq/tests/test_tools.py:129:25: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amin]`, found `list[Unknown | int]`
- asynq/tests/test_tools.py:129:30: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((_T@amin, /) -> Any) | None`, found `list[Unknown | int]`
- asynq/tests/test_tools.py:129:41: error[too-many-positional-arguments] Too many positional arguments to bound method `__call__`: expected 3, got 4
- asynq/tests/test_tools.py:129:49: error[parameter-already-assigned] Multiple values provided for parameter `key` of bound method `__call__`
- asynq/tests/test_tools.py:130:25: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amin]`, found `list[Unknown | list[Unknown | int]]`
- asynq/tests/test_tools.py:132:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amin]`, found `Literal[1]`
- asynq/tests/test_tools.py:132:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((_T@amin, /) -> Any) | None`, found `Literal[2]`
- asynq/tests/test_tools.py:132:29: error[too-many-positional-arguments] Too many positional arguments to bound method `__call__`: expected 3, got 5
- asynq/tests/test_tools.py:135:9: error[missing-argument] No argument provided for required parameter `__arg` of bound method `__call__`
- asynq/tests/test_tools.py:139:33: error[unknown-argument] Argument `random_keyword_argument` does not match any known parameter of bound method `__call__`
- asynq/tests/test_typing.py:16:9: error[type-assertion-failure] Type `FutureBase[str]` does not match asserted type `FutureBase[Unknown]`
+ asynq/tests/test_typing.py:16:9: error[type-assertion-failure] Type `FutureBase[str]` does not match asserted type `FutureBase[str] | FutureBase[Unknown]`
- asynq/tests/test_typing.py:41:43: error[invalid-argument-type] Argument to bound method `asyncio` is incorrect: Expected `_T@generic`, found `str`
+ asynq/tests/test_typing.py:16:31: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[1]`
+ asynq/tests/test_typing.py:46:38: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
- asynq/tests/test_typing.py:54:16: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((...) -> _T@async_call) | ((...) -> FutureBase[_T@async_call])`, found `def f(x: int) -> str`
- asynq/tests/test_typing.py:56:20: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((...) -> _T@async_call) | ((...) -> FutureBase[_T@async_call])`, found `def f(x: int) -> str`
- asynq/tests/test_typing.py:61:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `Literal[1]`
- asynq/tests/test_typing.py:61:29: error[too-many-positional-arguments] Too many positional arguments to bound method `__call__`: expected 2, got 3
- asynq/tests/test_typing.py:61:32: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((_T@amax, /) -> Any) | None`, found `def len(obj: Sized, /) -> int`
- asynq/tests/test_typing.py:62:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `list[Unknown | int]`
- asynq/tests/test_typing.py:62:34: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((_T@amax, /) -> Any) | None`, found `def len(obj: Sized, /) -> int`
- Found 218 diagnostics
+ Found 177 diagnostics

spack (https://github.com/spack/spack)
+ lib/spack/spack/binary_distribution.py:1524:13: error[invalid-argument-type] Argument to bound method `submit` is incorrect: Expected `Bottom[dict[Unknown, Unknown]] | None`, found `dict[Unknown | str, Unknown]`
+ lib/spack/spack/install_test.py:680:21: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Unknown & ~None`
+ lib/spack/spack/install_test.py:684:21: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `bool`
+ lib/spack/spack/url_buildcache.py:610:37: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `str`
+ lib/spack/spack/url_buildcache.py:610:51: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `str`
+ lib/spack/spack/url_buildcache.py:610:64: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal["sha256"]`
+ lib/spack/spack/url_buildcache.py:1284:29: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `str`
+ lib/spack/spack/url_buildcache.py:1284:42: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal["gzip"]`
+ lib/spack/spack/url_buildcache.py:1284:50: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `str`
- Found 7953 diagnostics
+ Found 7962 diagnostics

beartype (https://github.com/beartype/beartype)
- beartype/claw/_package/clawpkgtrie.py:66:29: warning[unsupported-base] Unsupported class base with type `<class 'dict[str, PackagesTrieBlacklist]'> | <class 'dict[str, Divergent]'>`
- beartype/claw/_package/clawpkgtrie.py:247:29: warning[unsupported-base] Unsupported class base with type `<class 'dict[str, PackagesTrieWhitelist]'> | <class 'dict[str, Divergent]'>`
- Found 494 diagnostics
+ Found 492 diagnostics

werkzeug (https://github.com/pallets/werkzeug)
+ src/werkzeug/test.py:370:36: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Mapping[str, Any]`
- Found 366 diagnostics
+ Found 367 diagnostics

jinja (https://github.com/pallets/jinja)
+ src/jinja2/nativetypes.py:109:17: error[invalid-argument-type] Argument is incorrect: Expected `Iterable[Never]`, found `Iterator[str]`
- Found 181 diagnostics
+ Found 182 diagnostics

black (https://github.com/psf/black)
+ src/black/files.py:92:16: error[unsupported-operator] Operator `in` is not supported between objects of type `Literal["black"]` and `object`
+ src/black/files.py:127:30: error[unresolved-attribute] Object of type `object` has no attribute `get`
+ src/black/linegen.py:1312:12: error[invalid-return-type] Return type does not match returned value: expected `(Line, Collection[Feature], Mode, /) -> Iterator[Line]`, found `_Wrapped[(Line, Collection[Feature], Mode, /), Iterator[Line], (line: Line, features: Collection[Feature], mode: Mode), Iterator[Line]] | _Wrapped[(Line, Collection[Feature], Mode, /), Iterator[Line], (line: Never, features: Never, mode: Never), Unknown]`
- Found 68 diagnostics
+ Found 71 diagnostics

graphql-core (https://github.com/graphql-python/graphql-core)
- src/graphql/execution/execute.py:216:59: error[invalid-assignment] Object of type `staticmethod[(value: Any), Unknown]` is not assignable to `(Any, /) -> Unknown`
+ src/graphql/execution/execute.py:216:59: error[invalid-assignment] Object of type `staticmethod[(value: Never), Unknown]` is not assignable to `(Any, /) -> Unknown`
+ src/graphql/validation/rules/possible_type_extensions.py:48:29: error[invalid-assignment] Object of type `str | bytes` is not assignable to `str | None`
+ tests/pyutils/test_description.py:63:25: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `<class 'LazyString'>`
+ tests/pyutils/test_description.py:110:29: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `<class 'LazyString'>`
+ tests/pyutils/test_description.py:121:29: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `<class 'LazyString'>`
+ tests/pyutils/test_description.py:135:29: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `<class 'LazyString'>`
+ tests/pyutils/test_description.py:145:29: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `<class 'LazyString'>`
+ tests/pyutils/test_description.py:157:29: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `<class 'LazyString'>`
+ tests/pyutils/test_description.py:166:29: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `<class 'LazyString'>`
+ tests/pyutils/test_description.py:184:25: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `<class 'Lazy'>`
+ tests/pyutils/test_description.py:220:25: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `<class 'Lazy'>`
- tests/validation/test_no_deprecated.py:23:8: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
- Found 428 diagnostics
+ Found 437 diagnostics

pytest (https://github.com/pytest-dev/pytest)
- src/_pytest/_py/path.py:760:17: error[invalid-argument-type] Argument to bound method `checked_call` is incorrect: Expected `Overload[(file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: Literal["r+", "+r", "rt+", "r+t", "+rt", ... omitted 48 literals] = Literal["r"], buffering: int = Literal[-1], encoding: str | None = None, errors: str | None = None, newline: str | None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown, (file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: Literal["rb+", "r+b", "+rb", "br+", "b+r", ... omitted 33 literals], buffering: Literal[0], encoding: None = None, errors: None = None, newline: None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown, (file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: Literal["rb+", "r+b", "+rb", "br+", "b+r", ... omitted 19 literals], buffering: Literal[-1, 1] = Literal[-1], encoding: None = None, errors: None = None, newline: None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown, (file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: Literal["wb", "bw", "ab", "ba", "xb", "bx"], buffering: Literal[-1, 1] = Literal[-1], encoding: None = None, errors: None = None, newline: None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown, (file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: Literal["rb", "br", "rbU", "rUb", "Urb", ... omitted 3 literals], buffering: Literal[-1, 1] = Literal[-1], encoding: None = None, errors: None = None, newline: None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown, (file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: Literal["rb+", "r+b", "+rb", "br+", "b+r", ... omitted 33 literals], buffering: int = Literal[-1], encoding: None = None, errors: None = None, newline: None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown, (file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: str, buffering: int = Literal[-1], encoding: str | None = None, errors: str | None = None, newline: str | None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown]`, found `Unknown | Literal["r"]`
- src/_pytest/_py/path.py:763:55: error[invalid-argument-type] Argument to bound method `checked_call` is incorrect: Expected `Overload[(file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: Literal["r+", "+r", "rt+", "r+t", "+rt", ... omitted 48 literals] = Literal["r"], buffering: int = Literal[-1], encoding: str | None = None, errors: str | None = None, newline: str | None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown, (file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: Literal["rb+", "r+b", "+rb", "br+", "b+r", ... omitted 33 literals], buffering: Literal[0], encoding: None = None, errors: None = None, newline: None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown, (file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: Literal["rb+", "r+b", "+rb", "br+", "b+r", ... omitted 19 literals], buffering: Literal[-1, 1] = Literal[-1], encoding: None = None, errors: None = None, newline: None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown, (file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: Literal["wb", "bw", "ab", "ba", "xb", "bx"], buffering: Literal[-1, 1] = Literal[-1], encoding: None = None, errors: None = None, newline: None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown, (file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: Literal["rb", "br", "rbU", "rUb", "Urb", ... omitted 3 literals], buffering: Literal[-1, 1] = Literal[-1], encoding: None = None, errors: None = None, newline: None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown, (file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: Literal["rb+", "r+b", "+rb", "br+", "b+r", ... omitted 33 literals], buffering: int = Literal[-1], encoding: None = None, errors: None = None, newline: None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown, (file: int | str | bytes | PathLike[str] | PathLike[bytes], mode: str, buffering: int = Literal[-1], encoding: str | None = None, errors: str | None = None, newline: str | None = None, closefd: bool = Literal[True], opener: ((str, int, /) -> int) | None = None) -> Unknown]`, found `Unknown | Literal["r"]`
- src/_pytest/_py/path.py:1271:53: error[invalid-argument-type] Argument to bound method `checked_call` is incorrect: Expected `Overload[(suffix: str | None = None, prefix: str | None = None, dir: str | PathLike[str] | None = None) -> Unknown, (suffix: bytes | None = None, prefix: bytes | None = None, dir: bytes | PathLike[bytes] | None = None) -> Unknown]`, found `str`
- src/_pytest/unittest.py:583:14: error[missing-argument] No argument provided for required parameter `cls`
- src/_pytest/unittest.py:583:14: error[missing-argument] No argument provided for required parameter `cls`
- testing/test_config.py:1426:14: error[missing-argument] No argument provided for required parameter `cls`
- testing/test_config.py:1426:14: error[missing-argument] No argument provided for required parameter `cls`
- testing/test_config.py:1748:10: error[missing-argument] No argument provided for required parameter `cls`
- testing/test_config.py:1748:10: error[missing-argument] No argument provided for required parameter `cls`
- testing/test_faulthandler.py:216:10: error[missing-argument] No argument provided for required parameter `cls`
- testing/test_faulthandler.py:216:10: error[missing-argument] No argument provided for required parameter `cls`
+ testing/test_link_resolve.py:73:16: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Path`
- testing/test_monkeypatch.py:426:10: error[missing-argument] No argument provided for required parameter `cls`
- testing/test_monkeypatch.py:426:10: error[missing-argument] No argument provided for required parameter `cls`
- Found 446 diagnostics
+ Found 434 diagnostics

starlette (https://github.com/encode/starlette)
+ starlette/endpoints.py:42:15: error[call-non-callable] Object of type `CoroutineType[object, Never, Response]` is not callable
- Found 209 diagnostics
+ Found 210 diagnostics

kopf (https://github.com/nolar/kopf)
+ kopf/_core/actions/execution.py:361:29: error[invalid-argument-type] Argument is incorrect: Expected `Iterable[Never]`, found `list[Unknown | tuple[ContextVar[LifeCycleFn | None], LifeCycleFn | None] | tuple[ContextVar[OperatorSettings], OperatorSettings] | ... omitted 3 union elements]`
+ kopf/_core/reactor/subhandling.py:19:29: error[invalid-argument-type] Argument is incorrect: Expected `Iterable[Never]`, found `list[Unknown | tuple[ContextVar[ChangingRegistry], ChangingRegistry] | tuple[ContextVar[bool], bool]]`
- Found 260 diagnostics
+ Found 262 diagnostics

scrapy (https://github.com/scrapy/scrapy)
+ scrapy/core/spidermw.py:401:40: error[invalid-argument-type] Argument to bound method `scrape_response_async` is incorrect: Expected `(Response | Unknown, Request, /) -> Coroutine[Any, Any, Iterable[Unknown] | AsyncIterator[Unknown]]`, found `_Wrapped[(Response, Request, /), Unknown, (response: Response, request: Request), Unknown] | _Wrapped[(Response, Request, /), Unknown, (response: Never, request: Never), CoroutineType[object, Never, object]]`
+ scrapy/utils/decorators.py:111:16: error[invalid-return-type] Return type does not match returned value: expected `((**_P@_warn_spider_arg) -> _T@_warn_spider_arg) | ((**_P@_warn_spider_arg) -> Coroutine[Any, Any, _T@_warn_spider_arg]) | ((**_P@_warn_spider_arg) -> AsyncGenerator[_T@_warn_spider_arg, None])`, found `_Wrapped[(...), Unknown, (...), Unknown] | _Wrapped[(...), Unknown, (...), CoroutineType[object, Never, object]]`
+ tests/test_spidermiddleware_urllength.py:42:17: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Request]`, found `Iterable[object] | Unknown`
- Found 1735 diagnostics
+ Found 1738 diagnostics

rich (https://github.com/Textualize/rich)
- examples/table_movie.py:62:1: error[invalid-argument-type] Argument to function `contextmanager` is incorrect: Expected `(length: int = Literal[1]) -> Iterator[Unknown]`, found `def beat(length: int = Literal[1]) -> None`
+ examples/table_movie.py:62:1: error[invalid-argument-type] Argument to function `contextmanager` is incorrect: Expected `(...) -> Iterator[Unknown]`, found `def beat(length: int = Literal[1]) -> None`

paasta (https://github.com/yelp/paasta)
+ paasta_tools/generate_deployments_for_service.py:245:41: error[invalid-argument-type] Argument to function `dump` is incorrect: Expected `SupportsWrite[str]`, found `Top[IO[Unknown]] | Unknown`
+ paasta_tools/generate_services_file.py:91:9: error[no-matching-overload] No overload of bound method `write` matches arguments
+ paasta_tools/generate_services_file.py:92:9: error[no-matching-overload] No overload of bound method `write` matches arguments
+ paasta_tools/kubernetes_tools.py:4246:47: error[unresolved-attribute] Object of type `object` has no attribute `metadata`
+ paasta_tools/metrics/metastatus_lib.py:843:36: error[unresolved-attribute] Object of type `object` has no attribute `spec`
+ paasta_tools/utils.py:4335:13: error[invalid-argument-type] Argument to function `dump` is incorrect: Expected `SupportsWrite[str]`, found `Top[IO[Unknown]] | Unknown`
+ paasta_tools/utils.py:4357:9: error[no-matching-overload] No overload of bound method `write` matches arguments
- Found 1101 diagnostics
+ Found 1108 diagnostics

sockeye (https://github.com/awslabs/sockeye)
+ sockeye/rerank.py:93:65: error[invalid-argument-type] Argument to function `_sort_by_ranking` is incorrect: Expected `list[int]`, found `Unknown | Top[list[Unknown]]`
+ sockeye/rerank.py:95:46: error[invalid-argument-type] Method `__getitem__` of type `Overload[(i: SupportsIndex, /) -> Unknown, (s: slice[Any, Any, Any], /) -> list[Unknown]]` cannot be called with key of type `object` on object of type `list[Unknown]`
- sockeye/test_utils.py:147:1: error[invalid-argument-type] Argument to function `contextmanager` is incorrect: Expected `(prefix: str, train_line_count: int, train_line_count_empty: int, train_max_length: int, dev_line_count: int, dev_max_length: int, test_line_count: int, test_line_count_empty: int, test_max_length: int, sort_target: bool = Literal[False], seed_train: int = Literal[13], seed_dev: int = Literal[13], source_text_prefix_token: str = Literal[""], with_n_source_factors: int = Literal[0], with_n_target_factors: int = Literal[0]) -> Iterator[Unknown]`, found `def tmp_digits_dataset(prefix: str, train_line_count: int, train_line_count_empty: int, train_max_length: int, dev_line_count: int, dev_max_length: int, test_line_count: int, test_line_count_empty: int, test_max_length: int, sort_target: bool = Literal[False], seed_train: int = Literal[13], seed_dev: int = Literal[13], source_text_prefix_token: str = Literal[""], with_n_source_factors: int = Literal[0], with_n_target_factors: int = Literal[0]) -> dict[str, Any]`
+ sockeye/test_utils.py:147:1: error[invalid-argument-type] Argument to function `contextmanager` is incorrect: Expected `(...) -> Iterator[Unknown]`, found `def tmp_digits_dataset(prefix: str, train_line_count: int, train_line_count_empty: int, train_max_length: int, dev_line_count: int, dev_max_length: int, test_line_count: int, test_line_count_empty: int, test_max_length: int, sort_target: bool = Literal[False], seed_train: int = Literal[13], seed_dev: int = Literal[13], source_text_prefix_token: str = Literal[""], with_n_source_factors: int = Literal[0], with_n_target_factors: int = Literal[0]) -> dict[str, Any]`
- Found 413 diagnostics
+ Found 415 diagnostics

dulwich (https://github.com/dulwich/dulwich)
- dulwich/porcelain.py:610:38: error[invalid-argument-type] Argument is incorrect: Expected `T@_noop_context_manager`, found `(str & BaseRepo) | (PathLike[str] & BaseRepo) | T@open_repo`
- dulwich/porcelain.py:664:38: error[invalid-argument-type] Argument is incorrect: Expected `T@_noop_context_manager`, found `(str & BaseRepo) | (bytes & BaseRepo) | (PathLike[str] & BaseRepo) | T@open_repo_closing`
+ dulwich/walk.py:474:35: error[invalid-argument-type] Argument to bound method `_reorder` is incorrect: Expected `Iterator[WalkEntry]`, found `Iterator[WalkEntry | None]`
- Found 227 diagnostics
+ Found 226 diagnostics

mkosi (https://github.com/systemd/mkosi)
+ mkosi/__init__.py:3866:24: error[invalid-argument-type] Argument is incorrect: Expected `Mapping[str, Never]`, found `dict[Unknown | str, Unknown | str]`
+ mkosi/__init__.py:4125:43: error[invalid-argument-type] Argument is incorrect: Expected `Mapping[str, Never]`, found `dict[Unknown | str, Unknown | str]`
+ mkosi/__init__.py:4399:9: error[invalid-argument-type] Argument is incorrect: Expected `None | int | Bottom[IO[Any]]`, found `TextIO | Any`
+ mkosi/__init__.py:4400:9: error[invalid-argument-type] Argument is incorrect: Expected `None | int | Bottom[IO[Any]]`, found `TextIO | Any`
+ mkosi/__init__.py:4417:17: error[invalid-argument-type] Argument is incorrect: Expected `None | int | Bottom[IO[Any]]`, found `TextIO | Any`
+ mkosi/__init__.py:4418:17: error[invalid-argument-type] Argument is incorrect: Expected `None | int | Bottom[IO[Any]]`, found `TextIO | Any`
- Found 97 diagnostics
+ Found 103 diagnostics

poetry (https://github.com/python-poetry/poetry)
+ src/poetry/console/commands/build.py:76:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal["sdist", "wheel"]`
+ src/poetry/inspection/info.py:540:41: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal["wheel"]`
+ src/poetry/installation/chef.py:71:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal["editable", "wheel"]`
- tests/utils/env/test_env.py:540:34: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
+ tests/utils/test_isolated_build.py:127:39: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal["wheel"]`
- Found 964 diagnostics
+ Found 967 diagnostics

schemathesis (https://github.com/schemathesis/schemathesis)
+ src/schemathesis/engine/phases/probes.py:159:13: error[no-matching-overload] No overload of bound method `setdefault` matches arguments
+ src/schemathesis/specs/openapi/checks.py:65:12: error[invalid-return-type] Return type does not match returned value: expected `(CheckContext, Response, Case, /) -> bool | None`, found `_Wrapped[(CheckContext, Response, Case, /), bool | None, (ctx: CheckContext, response: Response, case: Case), bool | None] | _Wrapped[(CheckContext, Response, Case, /), bool | None, (ctx: Never, response: Never, case: Never), Unknown]`
+ src/schemathesis/specs/openapi/checks.py:77:12: error[invalid-return-type] Return type does not match returned value: expected `(CheckContext, Response, Case, /) -> bool | None`, found `_Wrapped[(CheckContext, Response, Case, /), bool | None, (ctx: CheckContext, response: Response, case: Case), bool | None] | _Wrapped[(CheckContext, Response, Case, /), bool | None, (ctx: Never, response: Never, case: Never), Unknown]`
+ src/schemathesis/specs/openapi/checks.py:89:12: error[invalid-return-type] Return type does not match returned value: expected `(CheckContext, Response, Case, /) -> bool | None`, found `_Wrapped[(CheckContext, Response, Case, /), bool | None, (ctx: CheckContext, response: Response, case: Case), bool | None] | _Wrapped[(CheckContext, Response, Case, /), bool | None, (ctx: Never, response: Never, case: Never), Unknown]`
+ src/schemathesis/specs/openapi/negative/mutations.py:220:16: error[invalid-return-type] Return type does not match returned value: expected `(MutationContext, (SearchStrategy[Unknown], /) -> Unknown, dict[str, Any], /) -> tuple[MutationResult, MutationMetadata | None]`, found `_Wrapped[(MutationContext, (SearchStrategy[object], /) -> Never, Bottom[dict[str, Any]], /), tuple[MutationResult, MutationMetadata | None], (ctx: MutationContext, draw: (SearchStrategy[object], /) -> Never, schema: Bottom[dict[str, Any]]), tuple[MutationResult, MutationMetadata | None]] | _Wrapped[(MutationContext, (SearchStrategy[object], /) -> Never, Bottom[dict[str, Any]], /), tuple[MutationResult, MutationMetadata | None], (ctx: Never, draw: Never, schema: Never), Unknown]`
+ src/schemathesis/transport/prepare.py:36:5: error[no-matching-overload] No overload of bound method `setdefault` matches arguments
+ src/schemathesis/transport/prepare.py:38:9: error[no-matching-overload] No overload of bound method `update` matches arguments
- Found 272 diagnostics
+ Found 279 diagnostics

nox (https://github.com/wntrblm/nox)
+ nox/registry.py:91:16: error[invalid-return-type] Return type does not match returned value: expected `Func | ((((...) -> Any) | Func, /) -> Func)`, found `partial[Func | ((((*args: object, **kwargs: object) -> Never) | Func, /) -> Func)]`
- Found 23 diagnostics
+ Found 24 diagnostics

tornado (https://github.com/tornadoweb/tornado)
- tornado/wsgi.py:180:39: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
- Found 323 diagnostics
+ Found 322 diagnostics

typeshed-stats (https://github.com/AlexWaygood/typeshed-stats)
+ src/typeshed_stats/gather.py:403:12: error[invalid-return-type] Return type does not match returned value: expected `str | None`, found `object`
+ src/typeshed_stats/gather.py:424:22: error[unresolved-attribute] Object of type `object` has no attribute `get`
+ src/typeshed_stats/gather.py:875:12: error[invalid-return-type] Return type does not match returned value: expected `str | None`, found `object`
- Found 17 diagnostics
+ Found 20 diagnostics

mitmproxy (https://github.com/mitmproxy/mitmproxy)
+ mitmproxy/addons/save.py:101:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `BinaryIO`, found `IO[Any]`
- test/mitmproxy/addons/test_clientplayback.py:18:1: error[invalid-argument-type] Argument to function `asynccontextmanager` is incorrect: Expected `(handle_conn, **server_args) -> AsyncIterator[Unknown]`, found `def tcp_server(handle_conn, **server_args) -> tuple[str, int]`
+ test/mitmproxy/addons/test_clientplayback.py:18:1: error[invalid-argument-type] Argument to function `asynccontextmanager` is incorrect: Expected `(...) -> AsyncIterator[Unknown]`, found `def tcp_server(handle_conn, **server_args) -> tuple[str, int]`
- test/mitmproxy/addons/test_next_layer.py:492:13: error[invalid-argument-type] Argument is incorrect: Expected `list[type[Layer]]`, found `list[type[Layer] | partial[Unknown]]`
+ test/mitmproxy/addons/test_next_layer.py:492:13: error[invalid-argument-type] Argument is incorrect: Expected `list[type[Layer]]`, found `list[type[Layer] | partial[HttpLayer] | partial[HttpStream]]`
- test/mitmproxy/addons/test_next_layer.py:524:13: error[invalid-argument-type] Argument is incorrect: Expected `list[type[Layer]]`, found `list[type[Layer] | partial[Unknown]]`
+ test/mitmproxy/addons/test_next_layer.py:524:13: error[invalid-argument-type] Argument is incorrect: Expected `list[type[Layer]]`, found `list[type[Layer] | partial[HttpLayer] | partial[HttpStream]]`
- test/mitmproxy/addons/test_next_layer.py:536:13: error[invalid-argument-type] Argument is incorrect: Expected `list[type[Layer]]`, found `list[type[Layer] | partial[Unknown]]`
+ test/mitmproxy/addons/test_next_layer.py:536:13: error[invalid-argument-type] Argument is incorrect: Expected `list[type[Layer]]`, found `list[type[Layer] | partial[HttpLayer] | partial[HttpStream]]`
- test/mitmproxy/addons/test_next_layer.py:554:13: error[invalid-argument-type] Argument is incorrect: Expected `list[type[Layer]]`, found `list[type[Layer] | partial[Unknown]]`
+ test/mitmproxy/addons/test_next_layer.py:554:13: error[invalid-argument-type] Argument is incorrect: Expected `list[type[Layer]]`, found `list[type[Layer] | partial[HttpLayer] | partial[HttpStream]]`
- test/mitmproxy/addons/test_next_layer.py:575:13: error[invalid-argument-type] Argument is incorrect: Expected `list[type[Layer]]`, found `list[type[Layer] | partial[Unknown]]`
+ test/mitmproxy/addons/test_next_layer.py:575:13: error[invalid-argument-type] Argument is incorrect: Expected `list[type[Layer]]`, found `list[type[Layer] | partial[HttpLayer] | partial[HttpStream]]`
- test/mitmproxy/addons/test_proxyserver.py:337:1: error[invalid-argument-type] Argument to function `asynccontextmanager` is incorrect: Expected `(handle_datagram: (DatagramTransport, bytes, tuple[str, int], /) -> None) -> AsyncIterator[Unknown]`, found `def udp_server(handle_datagram: (DatagramTransport, bytes, tuple[str, int], /) -> None) -> tuple[str, int]`
+ test/mitmproxy/addons/test_proxyserver.py:337:1: error[invalid-argument-type] Argument to function `asynccontextmanager` is incorrect: Expected `(...) -> AsyncIterator[Unknown]`, found `def udp_server(handle_datagram: (DatagramTransport, bytes, tuple[str, int], /) -> None) -> tuple[str, int]`
- test/mitmproxy/addons/test_proxyserver.py:798:37: error[invalid-argument-type] Argument is incorrect: Expected `type[T@quic_connect]`, found `<class 'H3Client'>`
- test/mitmproxy/addons/test_proxyserver.py:832:17: error[invalid-argument-type] Argument is incorrect: Expected `type[T@quic_connect]`, found `<class 'QuicDatagramClient'>`
- test/mitmproxy/addons/test_proxyserver.py:877:37: error[invalid-argument-type] Argument is incorrect: Expected `type[T@quic_connect]`, found `<class 'H3Client'>`
+ test/mitmproxy/tools/console/test_quickhelp.py:63:19: error[invalid-argument-type] Argument to bound method `unbind` is incorrect: Expected `Binding`, found `Binding | None | Unknown`
- Found 2139 diagnostics
+ Found 2138 diagnostics

urllib3 (https://github.com/urllib3/urllib3)
+ dummyserver/testcase.py:264:63: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `ProxyApp`
+ dummyserver/testcase.py:269:54: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `ProxyApp`
+ test/conftest.py:83:40: error[invalid-argument-type] Argument is incorrect: Expected `Bottom[dict[str, Any]] | None`, found `dict[str, str]`
+ test/conftest.py:104:50: error[invalid-argument-type] Argument is incorrect: Expected `Bottom[dict[str, Any]] | None`, found `dict[str, str]`
+ test/conftest.py:107:49: error[invalid-argument-type] Argument is incorrect: Expected `Bottom[dict[str, Any]] | None`, found `dict[str, str]`
+ test/conftest.py:107:62: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `ProxyApp`
- test/with_dummyserver/test_chunked_transfer.py:299:14: error[missing-argument] No argument provided for required parameter `monkeypatch`
- test/with_dummyserver/test_chunked_transfer.py:299:14: error[missing-argument] No argument provided for required parameter `monkeypatch`
- test/with_dummyserver/test_chunked_transfer.py:299:36: error[invalid-argument-type] Argument is incorrect: Expected `Self@mark`, found `MonkeyPatch`
- test/with_dummyserver/test_chunked_transfer.py:327:14: error[missing-argument] No argument provided for required parameter `monkeypatch`
- test/with_dummyserver/test_chunked_transfer.py:327:14: error[missing-argument] No argument provided for required parameter `monkeypatch`
- test/with_dummyserver/test_chunked_transfer.py:327:36: error[invalid-argument-type] Argument is incorrect: Expected `Self@mark`, found `MonkeyPatch`

vision (https://github.com/pytorch/vision)
- test/datasets_utils.py:570:50: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `Unknown | Mock`
- test/datasets_utils.py:570:50: error[invalid-argument-type] Argument is incorrect: Expected `bool | None`, found `Unknown | Mock`
+ torchvision/utils.py:763:14: error[invalid-assignment] Object of type `list[tuple[int, int, int] | tuple[int, int, int, int] | Unknown]` is not assignable to `None | str | tuple[int, int, int] | list[str | tuple[int, int, int]]`
- Found 1474 diagnostics
+ Found 1473 diagnostics

cki-lib (https://gitlab.com/cki-project/cki-lib)
+ cki_lib/messagequeue.py:170:41: error[invalid-argument-type] Argument is incorrect: Expected `Bottom[dict[str, Any]]`, found `dict[Unknown | str, Unknown | dict[Unknown | str, Unknown | str | dict[str, str] | None]]`
+ cki_lib/stomp.py:116:33: error[invalid-argument-type] Argument is incorrect: Expected `Bottom[dict[str, Any]]`, found `dict[Unknown | str, Unknown | dict[Unknown | str, Unknown | str]]`
- Found 230 diagnostics
+ Found 232 diagnostics

Expression (https://github.com/cognitedata/Expression)
+ expression/core/result.py:209:24: error[invalid-return-type] Return type does not match returned value: expected `Result[_TErrorOut@Result, _TSourceOut@Result]`, found `Result[_TSourceOut@Result, _TSourceOut@Result]`
+ expression/core/result.py:211:24: error[invalid-return-type] Return type does not match returned value: expected `Result[_TErrorOut@Result, _TSourceOut@Result]`, found `Result[_TSourceOut@Result, _TSourceOut@Result]`
- Found 214 diagnostics
+ Found 216 diagnostics

optuna (https://github.com/optuna/optuna)
+ optuna/storages/_rdb/alembic/versions/v2.4.0.a.py:181:42: error[invalid-argument-type] Argument to bound method `drop_constraint` is incorrect: Expected `str`, found `str | None`
+ tests/samplers_tests/tpe_tests/test_multi_objective_sampler.py:44:9: error[unresolved-attribute] Unresolved attribute `return_value` on type `CallableMixin`.
+ tests/samplers_tests/tpe_tests/test_multi_objective_sampler.py:45:9: error[unresolved-attribute] Unresolved attribute `return_value` on type `CallableMixin`.
+ tests/samplers_tests/tpe_tests/test_multi_objective_sampler.py:113:13: error[unresolved-attribute] Unresolved attribute `return_value` on type `CallableMixin`.
+ tests/samplers_tests/tpe_tests/test_multi_objective_sampler.py:114:13: error[unresolved-attribute] Unresolved attribute `return_value` on type `CallableMixin`.
- Found 547 diagnostics
+ Found 552 diagnostics

pandera (https://github.com/pandera-dev/pandera)
+ pandera/api/polars/components.py:152:29: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `ValidationDepth | None`
+ pandera/api/polars/container.py:55:29: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `ValidationDepth`
- pandera/engines/engine.py:112:13: error[invalid-argument-type] Argument is incorrect: Expected `Dispatch`, found `_SingleDispatchCallable[Unknown]`
+ pandera/engines/engine.py:112:13: error[invalid-argument-type] Argument is incorrect: Expected `Dispatch`, found `_SingleDispatchCallable[DataType] | _SingleDispatchCallable[Unknown]`
+ pandera/typing/pandas.py:263:33: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[False]`
+ pandera/typing/polars.py:324:37: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[False]`
- tests/mypy/pandas_modules/pandas_dataframe.py:35:12: error[no-matching-overload] No overload of bound method `pipe` matches arguments
+ tests/mypy/pandas_modules/pandas_dataframe.py:35:12: error[invalid-return-type] Return type does not match returned value: expected `DataFrame[SchemaOut]`, found `DataFrame[SchemaOut] | DataFrame[AnotherSchema]`
+ tests/pandas/test_pandas_config.py:16:25: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[False]`
+ tests/polars/test_polars_config.py:116:25: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[ValidationDepth.SCHEMA_AND_DATA]`
+ tests/polars/test_polars_config.py:191:25: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[ValidationDepth.SCHEMA_AND_DATA]`
+ tests/pyspark/test_pyspark_config.py:54:29: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[False]`
+ tests/pyspark/test_pyspark_config.py:78:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[True]`
+ tests/pyspark/test_pyspark_config.py:79:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[ValidationDepth.SCHEMA_ONLY]`
+ tests/pyspark/test_pyspark_config.py:116:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[True]`
+ tests/pyspark/test_pyspark_config.py:117:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[ValidationDepth.SCHEMA_ONLY]`
+ tests/pyspark/test_pyspark_config.py:164:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[True]`
+ tests/pyspark/test_pyspark_config.py:165:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[ValidationDepth.DATA_ONLY]`
+ tests/pyspark/test_pyspark_config.py:205:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[True]`
+ tests/pyspark/test_pyspark_config.py:206:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[ValidationDepth.DATA_ONLY]`
+ tests/pyspark/test_pyspark_config.py:260:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[True]`
+ tests/pyspark/test_pyspark_config.py:261:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[ValidationDepth.SCHEMA_AND_DATA]`
+ tests/pyspark/test_pyspark_config.py:317:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[True]`
+ tests/pyspark/test_pyspark_config.py:318:13: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[ValidationDepth.SCHEMA_AND_DATA]`
+ tests/pyspark/test_pyspark_decorators.py:51:29: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[True]`
- Found 1638 diagnostics
+ Found 1659 diagnostics

artigraph (https://github.com/artigraph/artigraph)
+ tests/arti/graphs/test_graph.py:450:20: error[unresolved-attribute] Object of type `CallableMixin` has no attribute `called`
+ tests/arti/graphs/test_graph.py:452:16: error[unresolved-attribute] Object of type `CallableMixin` has no attribute `called`
- Found 147 diagnostics
+ Found 149 diagnostics

antidote (https://github.com/Finistere/antidote)
- tests/core/test_thread_safety.py:277:61: error[invalid-argument-type] Argument to bound method `set_value` is incorrect: Expected `() -> Literal["a"]`, found `def callback() -> str`
+ tests/lib/interface/test_function.py:97:34: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[17]`
+ tests/lib/interface/test_lazy.py:43:28: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:44:28: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:44:51: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:45:37: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:46:37: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:46:69: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:47:34: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:48:34: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:48:67: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:59:42: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Never`, found `Literal[9]`
+ tests/lib/interface/test_lazy.py:63:52: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[9]`
+ tests/lib/interface/test_lazy.py:67:59: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[9]`
+ tests/lib/interface/test_lazy.py:75:35: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:76:44: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:77:41: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:90:28: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:91:37: error[invalid-argument-type] Argument is incorrect: Expected `Never`, found `Literal[7]`
+ tests/lib/interface/test_lazy.py:92:34: erro

... (truncated 3338 lines) ...
Memory usage changes were detected when running on open source projects
trio (https://github.com/python-trio/trio)
-     memo metadata = ~35MB
+     memo metadata = ~36MB

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Nov 21, 2025
@dcreager dcreager force-pushed the dcreager/callable-return branch from 965a9f8 to dbecc68 Compare November 26, 2025 21:22
@dcreager dcreager changed the title [ty] Infer typevar specializations for Callable return types [ty] Infer typevar specializations for Callable types Nov 26, 2025
@dcreager dcreager force-pushed the dcreager/callable-return branch from 7995e43 to f89ec1a Compare November 26, 2025 23:14
return fn(value)

def identity(x: T) -> T:
def identity(x: T, /) -> T:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting nuance: Callable[[A], B] creates a signature containing positional-only parameters, so we have to make the signature here positional-only as well to make identity pass the assignability check for it to be a valid argument to the fn parameter.

(That said, I'm not convinced that's...correct? Are we mixing up the ordering of the assignability check operands somewhere?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this should work, it does when there aren't any type variables involved (https://play.ty.dev/1663d70f-4daa-492f-84d7-c35c9009fbba):

from typing import Callable

def f(c: Callable[[int], int]): ...

def c(a: int) -> int: return 1

f(c)

Copy link
Member

@dhruvmanila dhruvmanila Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I looked into this a bit more and what I'm seeing is that:

In infer_map_impl, the formal signature is Callable[[A], B] and the actual signature is the identity function and you invoke formal_signature.when_constraint_set_assignable_to(..., actual_signature, ...) which means we're checking when is Callable[[A], B] assignable to identity function which leads to checking when is the positional-only parameter (A) is assignable to positional-or-keyword parameter (a: int) which is never. This is because you cannot substitute a callable that takes a positional-or-keyword parameter with a callable that takes a positional-only parameter (https://play.ty.dev/7b31e7a0-19c8-4d2b-8bf6-507764372c0d).

This can be tested using Protocol to define a callable that takes a positional-or-keyword parameter:

from typing import Protocol

class PositionalOrKeyword(Protocol):
    def __call__(self, a: int) -> None: ...

def positional_only(a: int, /) -> None: ...
def positional_or_keyword(a: int) -> None: ...

def test(c: PositionalOrKeyword) -> None:
    c(a=1)

Calling test using positional_only would fail at runtime.

Comment on lines 390 to 391
# TODO: this should be `Unknown | int`
reveal_type(invoke(head, [1, 2, 3])) # revealed: Unknown
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This TODO is not also removed because we end up inferring this constraint set when comparing head to Callable[[A], B]:

(B@invoke ≤ T@head) ∧ (list[T@head] ≤ A@invoke)

We then try to remove T@head from the constraint set by calculating

∃T@head ⋅ (B@invoke ≤ T@head) ∧ (list[T@head] ≤ A@invoke)

We should be able to pick T@head = B@invoke and simplify that to

(B@invoke = *) ∧ (list[B@invoke] ≤ A@invoke)

which I think would then be enough to propagate through the return type to discharge this TODO. I think this would require adding more derived facts to the sequent map.


x12: Y[Y[Literal[1]]] = [[1]]
reveal_type(x12) # revealed: list[Y[Literal[1]]]
reveal_type(x12) # revealed: list[list[Literal[1]]]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because we're now using specialize_recursive instead of specialize_partial.

Comment on lines 1680 to 1718
let when = formal_signature.when_constraint_set_assignable_to(
self.db,
actual_signature,
self.inferable,
);
when.for_each_path(self.db, |path| {
for constraint in path.positive_constraints() {
let typevar = constraint.typevar(self.db);
let lower = constraint.lower(self.db);
let upper = constraint.upper(self.db);
if !upper.is_object() {
self.add_type_mapping(typevar, upper, polarity, &mut f);
}
if let Type::TypeVar(lower_bound_typevar) = lower {
self.add_type_mapping(
lower_bound_typevar,
Type::TypeVar(typevar),
polarity,
&mut f,
);
}
}
});
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the meat of the change. We use the new ConstraintAssignability type relation here to calculate a constraint set describing when the two callables are assignable. That will recurse into any typevars in the callables, and find whatever constraint set allows them to unify.

We then use this new for_each_path method to find each way that constraint set can be satisfied, and add new typevar bindings to the old solver for whatever we find.

Comment on lines +968 to +1020
result.intersect(
db,
ConstraintSet::from(
relation.is_assignability() || relation.is_constraint_set_assignability(),
),
);
return result;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to combine this with result to hang on to any typevar mapping our constraint set has recorded for the return type comparison above. That's need to support something like

Callable[[int], int] ≤ Callable[..., T]

and have it return int ≤ T.

Comment on lines +1751 to +1973
// A typevar satisfies a relation when...it satisfies the relation. Yes that's a
// tautology! We're moving the caller's subtyping/assignability requirement into a
// constraint set. If the typevar has an upper bound or constraints, then the relation
// only has to hold when the typevar has a valid specialization (i.e., one that
// satisfies the upper bound/constraints).
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what #20093 is trying to add to replace assignability across the board. In the meantime, I've added a new TypeRelation that lets us opt into the new behavior only in certain places.

@dcreager dcreager force-pushed the dcreager/callable-return branch from 3868294 to 2c62674 Compare November 26, 2025 23:37
@dcreager dcreager marked this pull request as ready for review November 26, 2025 23:38
@astral-sh-bot
Copy link

astral-sh-bot bot commented Nov 26, 2025

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-argument-type 657 44 36
non-subscriptable 345 0 0
invalid-return-type 89 0 1
no-matching-overload 81 5 0
unresolved-attribute 71 3 4
type-assertion-failure 0 23 41
invalid-assignment 31 0 9
possibly-missing-attribute 35 0 4
unsupported-operator 8 0 16
unused-ignore-comment 1 21 0
not-iterable 18 0 0
unknown-argument 14 0 0
too-many-positional-arguments 11 0 0
possibly-unresolved-reference 0 4 0
unsupported-base 2 1 0
call-non-callable 1 0 0
invalid-await 1 0 0
invalid-context-manager 1 0 0
invalid-raise 1 0 0
redundant-cast 1 0 0
Total 1,368 101 111

Full report with detailed diff (timing results)

* origin/main: (67 commits)
  Move `Token`, `TokenKind` and `Tokens` to `ruff-python-ast` (#21760)
  [ty] Don't confuse multiple occurrences of `typing.Self` when binding bound methods (#21754)
  Use our org-wide Renovate preset (#21759)
  Delete `my-script.py` (#21751)
  [ty] Move `all_members`, and related types/routines, out of `ide_support.rs` (#21695)
  [ty] Fix find-references for import aliases (#21736)
  [ty] add tests for workspaces (#21741)
  [ty] Stop testing the (brittle) constraint set display implementation (#21743)
  [ty] Use generator over list comprehension to avoid cast (#21748)
  [ty] Add a diagnostic for prohibited `NamedTuple` attribute overrides (#21717)
  [ty] Fix subtyping with `type[T]` and unions (#21740)
  Use `npm ci --ignore-scripts` everywhere (#21742)
  [`flake8-simplify`] Fix truthiness assumption for non-iterable arguments in tuple/list/set calls (`SIM222`, `SIM223`) (#21479)
  [`flake8-use-pathlib`] Mark fixes unsafe for return type changes (`PTH104`, `PTH105`, `PTH109`, `PTH115`) (#21440)
  [ty] Fix auto-import code action to handle pre-existing import
  Enable PEP 740 attestations when publishing to PyPI (#21735)
  [ty] Fix find references for type defined in stub (#21732)
  Use OIDC instead of codspeed token (#21719)
  [ty] Exclude `typing_extensions` from completions unless it's really available
  [ty] Fix false positives for `class F(Generic[*Ts]): ...` (#21723)
  ...
@carljm
Copy link
Contributor

carljm commented Dec 2, 2025

Took a look at the conformance suite. Everything looks good except that it seems like we've lost our ability to recognize the deprecated decorator? See the conformance suite changes on directives_deprecated.py.

@dcreager
Copy link
Member Author

dcreager commented Dec 2, 2025

Took a look at the conformance suite. Everything looks good except that it seems like we've lost our ability to recognize the deprecated decorator? See the conformance suite changes on directives_deprecated.py.

Yeah this showed up in the deprecated mdtest too. I'm looking at whether it's affected by the same cycle-merging issue as functools.cache.

@dcreager
Copy link
Member Author

dcreager commented Dec 4, 2025

xarray is one of the problematic repos, and in particular the xarray/groupers.py file in the repo. I'm letting Codex take a stab at diagnosing where the increased running time is coming from.

Codex helped pinpoint that the issue was this call involving slice:

group_indices: GroupIndices = tuple(
    list(itertools.starmap(slice, pairwise(sbins))) + [slice(sbins[-1], None)]
)

It turns out that slice.__new__ is very overloaded, and many of the overloads are generic. When checking assignability of an overloaded Callable, I was taking the constraint sets for each overload (each pair of overloads, actually, since both sides can be overloaded) and merging them together using OR. Then I would use walk_path on that single constraint set to pull out any assignments we should add to the old solver.

That was building up a very large BDD, that was taking a long time to iterate through. But since each of those overload pairs is independent, we can just do the path walk on each one separately. That gets rid of the combinatorial explosion. mypy_primer has already passed without timeout, and xarray worked fine locally even in the debug profile.

So I'm waiting for CI to confirm, but I think the timeouts have been solved now too.

@dcreager
Copy link
Member Author

dcreager commented Dec 4, 2025

Still in the middle of reviewing the ecosystem results, but this one stands out as interesting:

[error] invalid-argument-type - [:1257:20] - Argument is incorrect: Expected `int | float`, found `Literal["spam"]`

It looks like we're now correctly catching a runtime attrs error during type-checking!

dcreager added a commit that referenced this pull request Dec 5, 2025
…le` (#21798)

When converting a class (whether specialized or not) into a `Callable`
type, we should carry through any generic context that the constructor
has. This includes both the generic context of the class itself (if it's
generic) and of the constructor methods (if they are separately
generic).

To help test this, this also updates the `generic_context` extension
function to work on `Callable` types and unions; and adds a new
`into_callable` extension function that works just like
`CallableTypeOf`, but on value forms instead of type forms.

Pulled this out of #21551 for separate review.
* origin/main: (41 commits)
  [ty] Carry generic context through when converting class into `Callable` (#21798)
  [ty] Add more tests for renamings (#21810)
  [ty] Minor improvements to `assert_type` diagnostics (#21811)
  [ty] Add some attribute/method renaming test cases (#21809)
  Update mkdocs-material to 9.7.0 (Insiders now free) (#21797)
  Remove unused whitespaces in test cases (#21806)
  [ty] fix panic when instantiating a type variable with invalid constraints (#21663)
  [ty] fix build failure caused by conflicts between #21683 and #21800 (#21802)
  [ty] do nothing with `store_expression_type` if `inner_expression_inference_state` is `Get` (#21718)
  [ty] increase the limit on the number of elements in a non-recursively defined literal union (#21683)
  [ty] normalize typevar bounds/constraints in cycles (#21800)
  [ty] Update completion eval to include modules
  [ty] Add modules to auto-import
  [ty] Add support for module-only import requests
  [ty] Refactor auto-import symbol info
  [ty] Clarify the use of `SymbolKind` in auto-import
  [ty] Redact ranking of completions from e2e LSP tests
  [ty] Tweaks tests to use clearer language
  [ty] Update evaluation results
  [ty] Make auto-import ignore symbols in modules starting with a `_`
  ...
dhruvmanila added a commit that referenced this pull request Dec 5, 2025
## Summary

Closes: astral-sh/ty#157

This PR adds support for the following capabilities involving a
`ParamSpec` type variable:
- Representing `P.args` and `P.kwargs` in the type system
- Matching against a callable containing `P` to create a type mapping
- Specializing `P` against the stored parameters

The value of a `ParamSpec` type variable is being represented using
`CallableType` with a `CallableTypeKind::ParamSpecValue` variant. This
`CallableTypeKind` is expanded from the existing `is_function_like`
boolean flag. An `enum` is used as these variants are mutually
exclusive.

For context, an initial iteration made an attempt to expand the
`Specialization` to use `TypeOrParameters` enum that represents that a
type variable can specialize into either a `Type` or `Parameters` but
that increased the complexity of the code as all downstream usages would
need to handle both the variants appropriately. Additionally, we'd have
also need to establish an invariant that a regular type variable always
maps to a `Type` while a paramspec type variable always maps to a
`Parameters`.

I've intentionally left out checking and raising diagnostics when the
`ParamSpec` type variable and it's components are not being used
correctly to avoid scope increase and it can easily be done as a
follow-up. This would also include the scoping rules which I don't think
a regular type variable implements either.

## Test Plan

Add new mdtest cases and update existing test cases.

Ran this branch on pyx, no new diagnostics.

### Ecosystem analysis

There's a case where in an annotated assignment like:
```py
type CustomType[P] = Callable[...]

def value[**P](...): ...

def another[**P](...):
	target: CustomType[P] = value
```
The type of `value` is a callable and it has a paramspec that's bound to
`value`, `CustomType` is a type alias that's a callable and `P` that's
used in it's specialization is bound to `another`. Now, ty infers the
type of `target` same as `value` and does not use the declared type
`CustomType[P]`. [This is the
assignment](https://github.com/mikeshardmind/async-utils/blob/0980b9d9ab2bc7a24777684a884f4ea96cbbe5f9/src/async_utils/gen_transform.py#L108)
that I'm referring to which then leads to error in downstream usage.
Pyright and mypy does seem to use the declared type.

There are multiple diagnostics in `dd-trace-py` that requires support
for `cls`.

I'm seeing `Divergent` type for an example like which ~~I'm not sure
why, I'll look into it tomorrow~~ is because of a cycle as mentioned in
astral-sh/ty#1729 (comment):
```py
from typing import Callable

def decorator[**P](c: Callable[P, int]) -> Callable[P, str]: ...

@decorator
def func(a: int) -> int: ...

# ((a: int) -> str) | ((a: Divergent) -> str)
reveal_type(func)
```

I ~~need to look into why are the parameters not being specialized
through multiple decorators in the following code~~ think this is also
because of the cycle mentioned in
astral-sh/ty#1729 (comment) and
the fact that we don't support `staticmethod` properly:
```py
from contextlib import contextmanager

class Foo:
    @staticmethod
    @contextmanager
    def method(x: int):
        yield

foo = Foo()
# ty: Revealed type: `() -> _GeneratorContextManager[Unknown, None, None]` [revealed-type]
reveal_type(foo.method)
```

There's some issue related to `Protocol` that are generic over a
`ParamSpec` in `starlette` which might be related to
astral-sh/ty#1635 but I'm not sure. Here's a
minimal example to reproduce:

<details><summary>Code snippet:</summary>
<p>

```py
from collections.abc import Awaitable, Callable, MutableMapping
from typing import Any, Callable, ParamSpec, Protocol

P = ParamSpec("P")

Scope = MutableMapping[str, Any]
Message = MutableMapping[str, Any]
Receive = Callable[[], Awaitable[Message]]
Send = Callable[[Message], Awaitable[None]]

ASGIApp = Callable[[Scope, Receive, Send], Awaitable[None]]

_Scope = Any
_Receive = Callable[[], Awaitable[Any]]
_Send = Callable[[Any], Awaitable[None]]

# Since `starlette.types.ASGIApp` type differs from `ASGIApplication` from `asgiref`
# we need to define a more permissive version of ASGIApp that doesn't cause type errors.
_ASGIApp = Callable[[_Scope, _Receive, _Send], Awaitable[None]]


class _MiddlewareFactory(Protocol[P]):
    def __call__(
        self, app: _ASGIApp, *args: P.args, **kwargs: P.kwargs
    ) -> _ASGIApp: ...


class Middleware:
    def __init__(
        self, factory: _MiddlewareFactory[P], *args: P.args, **kwargs: P.kwargs
    ) -> None:
        self.factory = factory
        self.args = args
        self.kwargs = kwargs


class ServerErrorMiddleware:
    def __init__(
        self,
        app: ASGIApp,
        value: int | None = None,
        flag: bool = False,
    ) -> None:
        self.app = app
        self.value = value
        self.flag = flag

    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: ...


# ty: Argument to bound method `__init__` is incorrect: Expected `_MiddlewareFactory[(...)]`, found `<class 'ServerErrorMiddleware'>` [invalid-argument-type]
Middleware(ServerErrorMiddleware, value=500, flag=True)
```

</p>
</details> 

### Conformance analysis

> ```diff
> -constructors_callable.py:36:13: info[revealed-type] Revealed type:
`(...) -> Unknown`
> +constructors_callable.py:36:13: info[revealed-type] Revealed type:
`(x: int) -> Unknown`
> ```

Requires return type inference i.e.,
#21551

> ```diff
> +constructors_callable.py:194:16: error[invalid-argument-type]
Argument is incorrect: Expected `list[T@__init__]`, found `list[Unknown
| str]`
> +constructors_callable.py:194:22: error[invalid-argument-type]
Argument is incorrect: Expected `list[T@__init__]`, found `list[Unknown
| str]`
> +constructors_callable.py:195:4: error[invalid-argument-type] Argument
is incorrect: Expected `list[T@__init__]`, found `list[Unknown | int]`
> +constructors_callable.py:195:9: error[invalid-argument-type] Argument
is incorrect: Expected `list[T@__init__]`, found `list[Unknown | str]`
> ```

I might need to look into why this is happening...

> ```diff
> +generics_defaults.py:79:1: error[type-assertion-failure] Type
`type[Class_ParamSpec[(str, int, /)]]` does not match asserted type
`<class 'Class_ParamSpec'>`
> ```

which is on the following code
```py
DefaultP = ParamSpec("DefaultP", default=[str, int])

class Class_ParamSpec(Generic[DefaultP]): ...

assert_type(Class_ParamSpec, type[Class_ParamSpec[str, int]])
```

It's occurring because there's no equivalence relationship defined
between `ClassLiteral` and `KnownInstanceType::TypeGenericAlias` which
is what these types are.

Everything else looks good to me!
* origin/main:
  [ty] Allow `tuple[Any, ...]` to assign to `tuple[int, *tuple[int, ...]]` (#21803)
  [ty] Support renaming import aliases (#21792)
  [ty] Add redeclaration LSP tests (#21812)
  [ty] more detailed description of "Size limit on unions of literals" in mdtest (#21804)
  [ty] Complete support for `ParamSpec` (#21445)
  [ty] Update benchmark dependencies (#21815)
This reverts commit 94aca37.
@dcreager dcreager marked this pull request as draft December 5, 2025 23:42
* origin/main:
  [ty] Add test case for fixed panic (#21832)
  [ty] Avoid double-analyzing tuple in `Final` subscript (#21828)
  [flake8-bandit] Fix false positive when using non-standard `CSafeLoader` path (S506). (#21830)
  Add minimal-size build profile (#21826)
@dcreager dcreager force-pushed the dcreager/callable-return branch from 0138dc3 to f29200c Compare December 7, 2025 20:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ecosystem-analyzer ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants