Skip to content

[ty] add support for intersections on the "actual" side of generic inference#23728

Merged
oconnor663 merged 3 commits intomainfrom
jack/infer_map_impl_intersections
Mar 10, 2026
Merged

[ty] add support for intersections on the "actual" side of generic inference#23728
oconnor663 merged 3 commits intomainfrom
jack/infer_map_impl_intersections

Conversation

@oconnor663
Copy link
Contributor

@oconnor663 oconnor663 added the ty Multi-file analysis & type inference label Mar 5, 2026
@oconnor663 oconnor663 assigned dcreager and unassigned ibraheemdev Mar 5, 2026
@oconnor663
Copy link
Contributor Author

@dcreager are you the best reviewer for this? This is my first time in this area of the code so please don't hesitate to ELI5.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 5, 2026

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 85.05%. The percentage of expected errors that received a diagnostic held steady at 78.05%. The number of fully passing files held steady at 63/132.

Comment on lines +917 to +933
In the formal parameter position:

```py
from typing import TypeVar, Iterable
from ty_extensions import Intersection

T = TypeVar("T")

class Foo: ...

def foo(x: Intersection[Iterable[T], Foo]) -> T:
return next(iter(x))

class Bar(list[int], Foo): ...

reveal_type(foo(Bar())) # revealed: int
```
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test case is for the preexisting (Type::Intersection(formal), _) branch, which as far as I can tell wasn't tested before. The case below is for the new branch.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 5, 2026

Memory usage report

Summary

Project Old New Diff Outcome
prefect 701.70MB 701.78MB +0.01% (82.29kB)
sphinx 265.37MB 265.43MB +0.02% (61.13kB)
trio 117.86MB 117.87MB +0.01% (8.27kB)
flake8 47.91MB 47.91MB +0.00% (12.00B)

Significant changes

Click to expand detailed breakdown

prefect

Name Old New Diff Outcome
infer_expression_types_impl 60.40MB 60.41MB +0.02% (10.85kB)
Type<'db>::apply_specialization_ 3.57MB 3.58MB +0.29% (10.57kB)
infer_definition_types 88.46MB 88.46MB +0.01% (8.85kB)
check_file_impl 17.83MB 17.83MB +0.05% (8.31kB)
Type<'db>::apply_specialization_::interned_arguments 2.86MB 2.86MB +0.24% (7.11kB)
FunctionType 8.44MB 8.45MB +0.07% (5.88kB)
Type<'db>::try_call_dunder_get_ 10.43MB 10.43MB +0.04% (4.61kB)
Type<'db>::class_member_with_policy_ 17.20MB 17.21MB +0.02% (4.33kB)
FunctionType<'db>::signature_ 3.86MB 3.86MB +0.09% (3.44kB)
CallableType 1.89MB 1.89MB +0.14% (2.74kB)
Type<'db>::class_member_with_policy_::interned_arguments 9.31MB 9.31MB +0.03% (2.64kB)
Type<'db>::member_lookup_with_policy_ 15.34MB 15.34MB +0.01% (2.19kB)
Specialization 2.49MB 2.50MB +0.08% (2.11kB)
StaticClassLiteral<'db>::try_mro_ 6.02MB 6.02MB +0.03% (1.73kB)
cached_protocol_interface 397.73kB 399.33kB +0.40% (1.59kB)
... 27 more

sphinx

Name Old New Diff Outcome
infer_definition_types 24.05MB 24.06MB +0.05% (11.12kB)
infer_expression_types_impl 21.50MB 21.51MB +0.03% (6.81kB)
Type<'db>::apply_specialization_ 1.65MB 1.66MB +0.38% (6.46kB)
Type<'db>::apply_specialization_::interned_arguments 1.45MB 1.45MB +0.42% (6.17kB)
CallableType 1.07MB 1.08MB +0.43% (4.71kB)
Type<'db>::try_call_dunder_get_ 4.94MB 4.94MB +0.09% (4.51kB)
Type<'db>::class_member_with_policy_ 7.55MB 7.55MB +0.06% (4.27kB)
Type<'db>::class_member_with_policy_::interned_arguments 3.99MB 3.99MB +0.07% (2.74kB)
Specialization 1.02MB 1.02MB +0.22% (2.30kB)
FunctionType 3.12MB 3.12MB +0.07% (2.16kB)
check_file_impl 5.13MB 5.13MB -0.03% (1.55kB)
infer_scope_types_impl 15.59MB 15.59MB +0.01% (1.50kB)
FunctionType<'db>::signature_ 2.27MB 2.28MB +0.05% (1.17kB)
BoundMethodType<'db>::into_callable_type_ 277.52kB 278.70kB +0.42% (1.17kB)
is_redundant_with_impl 1.81MB 1.80MB -0.06% (1.14kB)
... 22 more

trio

Name Old New Diff Outcome
infer_expression_types_impl 7.06MB 7.07MB +0.04% (2.62kB)
Type<'db>::class_member_with_policy_ 1.98MB 1.98MB +0.05% (1.04kB)
Type<'db>::try_call_dunder_get_ 1.37MB 1.37MB +0.07% (1.04kB)
FunctionType 1.50MB 1.50MB +0.06% (880.00B)
Type<'db>::class_member_with_policy_::interned_arguments 1.10MB 1.10MB +0.07% (832.00B)
FunctionType<'db>::signature_ 1.07MB 1.07MB +0.04% (472.00B)
StaticClassLiteral<'db>::try_mro_ 863.18kB 863.60kB +0.05% (432.00B)
CallableType 572.43kB 572.79kB +0.06% (360.00B)
BoundMethodType<'db>::into_callable_type_ 75.04kB 75.29kB +0.34% (264.00B)
Type<'db>::try_call_dunder_get_::interned_arguments 349.78kB 349.98kB +0.06% (208.00B)
BoundMethodType 187.19kB 187.34kB +0.08% (160.00B)
bound_typevar_default_type 14.75kB 14.64kB -0.74% (112.00B)
Type<'db>::member_lookup_with_policy_::interned_arguments 872.32kB 872.22kB -0.01% (104.00B)
infer_unpack_types 148.08kB 148.15kB +0.05% (72.00B)
GenericAlias 201.02kB 201.09kB +0.03% (72.00B)
... 5 more

flake8

Name Old New Diff Outcome
infer_definition_types 1.87MB 1.87MB +0.00% (24.00B)
infer_scope_types_impl 1004.35kB 1004.34kB -0.00% (12.00B)

@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 5, 2026

mypy_primer results

Changes were detected when running on open source projects
bidict (https://github.com/jab/bidict)
+ bidict/_base.py:562:12: error[invalid-return-type] Return type does not match returned value: expected `Iterator[KT@_fwdm_reversed]`, found `reversed[object]`
- Found 17 diagnostics
+ Found 18 diagnostics

pip (https://github.com/pypa/pip)
- src/pip/_internal/operations/check.py:99:37: error[no-matching-overload] No overload of function `sorted` matches arguments
- src/pip/_internal/operations/check.py:101:41: error[no-matching-overload] No overload of function `sorted` matches arguments
+ src/pip/_vendor/dependency_groups/_implementation.py:149:56: error[invalid-argument-type] Argument is incorrect: Expected `str`, found `object`
+ src/pip/_vendor/urllib3/packages/six.py:1070:17: error[unresolved-attribute] Object of type `MetaPathFinderProtocol` has no attribute `name`

spack (https://github.com/spack/spack)
- lib/spack/spack/util/s3.py:61:16: error[invalid-argument-type] Method `__getitem__` of type `bound method dict[tuple[str, str], Any].__getitem__(key: tuple[str, str], /) -> Any` cannot be called with key of type `tuple[None | Unknown, Unknown | Literal["fetch"]]` on object of type `dict[tuple[str, str], Any]`
+ lib/spack/spack/util/s3.py:61:16: error[invalid-argument-type] Method `__getitem__` of type `bound method dict[tuple[str, str], Any].__getitem__(key: tuple[str, str], /) -> Any` cannot be called with key of type `tuple[None | str | Unknown, Unknown | Literal["fetch"]]` on object of type `dict[tuple[str, str], Any]`
- lib/spack/spack/util/s3.py:75:5: error[invalid-assignment] Invalid subscript assignment with key of type `tuple[None | Unknown, Unknown | Literal["fetch"]]` and value of type `Unknown` on object of type `dict[tuple[str, str], Any]`
+ lib/spack/spack/util/s3.py:75:5: error[invalid-assignment] Invalid subscript assignment with key of type `tuple[None | str | Unknown, Unknown | Literal["fetch"]]` and value of type `Unknown` on object of type `dict[tuple[str, str], Any]`
+ lib/spack/spack/vendor/six.py:993:17: error[unresolved-attribute] Object of type `MetaPathFinderProtocol` has no attribute `name`
- Found 4431 diagnostics
+ Found 4432 diagnostics

stone (https://github.com/dropbox/stone)
+ stone/backends/python_rsrc/stone_serializers.py:788:52: error[invalid-argument-type] Argument to function `ensure_str` is incorrect: Expected `bytes | str`, found `object`
- Found 251 diagnostics
+ Found 252 diagnostics

werkzeug (https://github.com/pallets/werkzeug)
- src/werkzeug/routing/rules.py:510:43: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Buffer]`, found `Mapping[str, Any] & ~AlwaysFalsy`
- Found 387 diagnostics
+ Found 386 diagnostics

pytest (https://github.com/pytest-dev/pytest)
+ src/_pytest/assertion/rewrite.py:759:40: error[invalid-argument-type] Argument to bound method `append` is incorrect: Expected `AST`, found `~Assert`
- testing/test_monkeypatch.py:171:25: error[invalid-argument-type] Argument to bound method `setitem` is incorrect: Expected `Mapping[Literal["y"], Literal[1700]]`, found `dict[str, object] & ~AlwaysTruthy`
- testing/test_monkeypatch.py:174:25: error[invalid-argument-type] Argument to bound method `setitem` is incorrect: Expected `Mapping[Literal["x"], Literal[1500]]`, found `dict[str, object] & ~AlwaysTruthy`
- Found 382 diagnostics
+ Found 381 diagnostics

scrapy (https://github.com/scrapy/scrapy)
+ scrapy/core/spidermw.py:371:20: error[invalid-return-type] Return type does not match returned value: expected `MutableChain[_T@_process_callback_output] | MutableAsyncChain[_T@_process_callback_output]`, found `MutableAsyncChain[object]`
- scrapy/utils/decorators.py:40:16: error[invalid-assignment] Object of type `(...) -> Unknown` is not assignable to `def deco[**_P, _T](func: (**_P) -> _T) -> ((**_P) -> _T)`
+ scrapy/utils/decorators.py:40:16: error[invalid-assignment] Object of type `(...) -> object` is not assignable to `def deco[**_P, _T](func: (**_P) -> _T) -> ((**_P) -> _T)`
- Found 1794 diagnostics
+ Found 1795 diagnostics

dulwich (https://github.com/dulwich/dulwich)
+ dulwich/dumb.py:541:30: error[invalid-argument-type] Argument to bound method `add` is incorrect: Expected `ObjectID`, found `Unknown | bytes`
- dulwich/walk.py:376:17: error[unresolved-attribute] Attribute `add` is not defined on `Sequence[bytes] & ~AlwaysTruthy & ~AlwaysFalsy` in union `(Unknown & ~AlwaysFalsy) | (Sequence[bytes] & ~AlwaysTruthy & ~AlwaysFalsy) | (set[Unknown] & ~AlwaysFalsy)`
+ dulwich/walk.py:376:17: error[unresolved-attribute] Attribute `add` is not defined on `Sequence[bytes] & ~AlwaysTruthy & ~AlwaysFalsy` in union `(Unknown & ~AlwaysFalsy) | (Sequence[bytes] & ~AlwaysTruthy & ~AlwaysFalsy) | (set[bytes] & ~AlwaysFalsy)`
- dulwich/walk.py:377:17: error[unresolved-attribute] Attribute `remove` is not defined on `Sequence[bytes] & ~AlwaysTruthy & ~AlwaysFalsy` in union `(Unknown & ~AlwaysFalsy) | (Sequence[bytes] & ~AlwaysTruthy & ~AlwaysFalsy) | (set[Unknown] & ~AlwaysFalsy)`
+ dulwich/walk.py:377:17: error[unresolved-attribute] Attribute `remove` is not defined on `Sequence[bytes] & ~AlwaysTruthy & ~AlwaysFalsy` in union `(Unknown & ~AlwaysFalsy) | (Sequence[bytes] & ~AlwaysTruthy & ~AlwaysFalsy) | (set[bytes] & ~AlwaysFalsy)`
- Found 231 diagnostics
+ Found 232 diagnostics

dedupe (https://github.com/dedupeio/dedupe)
+ dedupe/branch_and_bound.py:82:35: error[invalid-argument-type] Argument to bound method `append` is incorrect: Expected `tuple[dict[Predicate, frozenset[int]], tuple[()]]`, found `tuple[dict[Any, frozenset[int]], tuple[Predicate, ...]]`
- Found 55 diagnostics
+ Found 56 diagnostics

tornado (https://github.com/tornadoweb/tornado)
+ tornado/routing.py:409:17: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `(HTTPServerRequest, /) -> None`, found `partial[object]`
- Found 330 diagnostics
+ Found 331 diagnostics

sphinx (https://github.com/sphinx-doc/sphinx)
+ sphinx/config.py:628:16: error[invalid-return-type] Return type does not match returned value: expected `frozenset[type] | ENUM`, found `frozenset[object]`
- Found 406 diagnostics
+ Found 407 diagnostics

mypy (https://github.com/python/mypy)
- mypy/main.py:302:33: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Buffer]`, found `tuple[int, int] & ~tuple[Literal[3], Literal[10]]`
+ mypy/test/test_diff_cache.py:125:42: error[unsupported-operator] Operator `in` is not supported between objects of type `Literal["/b."]` and `object`
+ mypy/test/test_diff_cache.py:125:56: error[unresolved-attribute] Object of type `object` has no attribute `startswith`
+ mypy/test/test_diff_cache.py:126:42: error[unsupported-operator] Operator `in` is not supported between objects of type `Literal["/c."]` and `object`
+ mypy/test/test_diff_cache.py:126:56: error[unresolved-attribute] Object of type `object` has no attribute `startswith`
+ mypy/test/test_diff_cache.py:127:42: error[unsupported-operator] Operator `in` is not supported between objects of type `Literal["/a."]` and `object`
+ mypy/test/test_diff_cache.py:127:56: error[unresolved-attribute] Object of type `object` has no attribute `startswith`
- Found 1763 diagnostics
+ Found 1768 diagnostics

optuna (https://github.com/optuna/optuna)
- optuna/storages/_rdb/storage.py:651:16: error[invalid-return-type] Return type does not match returned value: expected `int | float`, found `Unknown | Column[Unknown]`
+ optuna/storages/_rdb/storage.py:651:16: error[invalid-return-type] Return type does not match returned value: expected `int | float`, found `Unknown | Column[int | float | Any]`

pandera (https://github.com/pandera-dev/pandera)
- pandera/decorators.py:394:17: error[invalid-assignment] Invalid subscript assignment with key of type `int | str` and value of type `Unknown` on object of type `list[Unknown]`
+ pandera/decorators.py:394:17: error[invalid-assignment] Invalid subscript assignment with key of type `int | str` and value of type `Unknown` on object of type `list[object]`
- pandera/decorators.py:398:20: error[invalid-return-type] Return type does not match returned value: expected `None`, found `(Any & ~tuple[object, ...]) | tuple[Unknown, ...]`
+ pandera/decorators.py:398:20: error[invalid-return-type] Return type does not match returned value: expected `None`, found `(Any & ~tuple[object, ...]) | tuple[object, ...]`

schemathesis (https://github.com/schemathesis/schemathesis)
+ src/schemathesis/core/output/sanitization.py:19:25: error[unresolved-attribute] Object of type `object` has no attribute `lower`
+ src/schemathesis/specs/openapi/adapter/responses.py:378:16: error[invalid-return-type] Return type does not match returned value: expected `str | None`, found `object`
+ src/schemathesis/specs/openapi/adapter/responses.py:398:16: error[invalid-return-type] Return type does not match returned value: expected `str | None`, found `object`
+ src/schemathesis/specs/openapi/adapter/responses.py:411:16: error[invalid-return-type] Return type does not match returned value: expected `str | None`, found `object`
+ src/schemathesis/specs/openapi/adapter/responses.py:421:12: error[invalid-return-type] Return type does not match returned value: expected `str | None`, found `object`
+ src/schemathesis/specs/openapi/converter.py:145:21: error[invalid-argument-type] Argument to function `_to_json_schema` is incorrect: Expected `dict[str, Any] | bool`, found `object`
- Found 337 diagnostics
+ Found 343 diagnostics

urllib3 (https://github.com/urllib3/urllib3)
- test/test_ssltransport.py:308:59: error[invalid-argument-type] Argument to function `select` is incorrect: Expected `Iterable[Never]`, found `list[socket] & ~AlwaysFalsy`
- test/test_ssltransport.py:308:75: error[invalid-argument-type] Argument to function `select` is incorrect: Expected `Iterable[Never]`, found `list[socket] & ~AlwaysFalsy`
- Found 279 diagnostics
+ Found 277 diagnostics

artigraph (https://github.com/artigraph/artigraph)
+ src/arti/storage/_internal.py:146:9: error[invalid-assignment] Invalid subscript assignment with key of type `Unknown` and value of type `object` on object of type `dict[str, str]`
- Found 155 diagnostics
+ Found 156 diagnostics

discord.py (https://github.com/Rapptz/discord.py)
+ discord/utils.py:744:24: error[unresolved-attribute] Object of type `type` has no attribute `__slots__`
- Found 558 diagnostics
+ Found 559 diagnostics

apprise (https://github.com/caronc/apprise)
+ apprise/config/base.py:1116:31: error[no-matching-overload] No overload of bound method `match` matches arguments
+ apprise/config/base.py:1170:37: error[invalid-argument-type] Method `__delitem__` of type `bound method Top[dict[Unknown, Unknown]].__delitem__(key: Never, /) -> None` cannot be called with key of type `Literal["schema"]` on object of type `Top[dict[Unknown, Unknown]]`
+ apprise/config/base.py:1175:45: error[invalid-argument-type] Argument to function `_special_token_handler` is incorrect: Expected `dict[str, object]`, found `Top[dict[Unknown, Unknown]]`
+ apprise/config/base.py:1179:29: error[no-matching-overload] No overload of bound method `update` matches arguments
+ apprise/config/base.py:1188:37: error[invalid-argument-type] Argument to function `_special_token_handler` is incorrect: Expected `dict[str, object]`, found `Top[dict[Unknown, Unknown]]`
+ apprise/config/base.py:1196:21: error[no-matching-overload] No overload of bound method `update` matches arguments
- Found 3575 diagnostics
+ Found 3581 diagnostics

xarray (https://github.com/pydata/xarray)
+ xarray/backends/api.py:1602:24: error[invalid-assignment] Object of type `list[str | ReadBuffer[Unknown] | NestedSequence[str | ReadBuffer[Unknown]]]` is not assignable to `list[str | ReadBuffer[Unknown]]`
- xarray/core/dataset.py:5385:77: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Buffer]`, found `set[Hashable] & ~AlwaysFalsy`
+ xarray/structure/combine.py:69:57: error[invalid-argument-type] Argument to function `_infer_tile_ids_from_nested_list` is incorrect: Expected `NestedSequence[Unknown]`, found `object`
- Found 1712 diagnostics
+ Found 1713 diagnostics

cloud-init (https://github.com/canonical/cloud-init)
+ cloudinit/config/cc_ubuntu_pro.py:129:16: error[no-matching-overload] No overload of function `search` matches arguments
+ cloudinit/config/cc_ubuntu_pro.py:130:48: error[invalid-argument-type] Argument to function `escape` is incorrect: Argument type `~None` does not satisfy constraints (`str`, `bytes`) of type variable `AnyStr`
+ cloudinit/config/cc_ubuntu_pro.py:136:23: error[invalid-argument-type] Argument to function `subp` is incorrect: Expected `str | bytes | list[str] | list[bytes]`, found `list[object] | list[str]`
+ cloudinit/config/cc_ubuntu_pro.py:140:27: error[no-matching-overload] No overload of bound method `replace` matches arguments
+ cloudinit/net/eni.py:132:25: error[no-matching-overload] No overload of bound method `join` matches arguments
- Found 1310 diagnostics
+ Found 1315 diagnostics

vision (https://github.com/pytorch/vision)
+ test/test_models.py:225:13: error[unresolved-attribute] Object of type `object` has no attribute `requires_grad_`
- torchvision/prototype/utils/_internal.py:34:82: error[invalid-argument-type] Argument is incorrect: Expected `Sequence[str]`, found `(Collection[str] & Sequence[object]) | list[Unknown]`
+ torchvision/prototype/utils/_internal.py:34:82: error[invalid-argument-type] Argument is incorrect: Expected `Sequence[str]`, found `Collection[str] & Sequence[object]`
- Found 1418 diagnostics
+ Found 1419 diagnostics

openlibrary (https://github.com/internetarchive/openlibrary)
+ openlibrary/plugins/upstream/utils.py:369:49: error[no-matching-overload] No overload of function `sorted` matches arguments
+ openlibrary/plugins/worksearch/code.py:314:59: error[invalid-argument-type] Argument to bound method `q_to_solr_params` is incorrect: Expected `list[tuple[str, str]]`, found `list[tuple[str, str] | tuple[str, Unknown | int]] | Unknown`
- Found 1153 diagnostics
+ Found 1155 diagnostics

prefect (https://github.com/PrefectHQ/prefect)
+ src/prefect/cli/flow_run.py:264:17: error[unresolved-attribute] Attribute `state_details` is not defined on `None` in union `State[Any] | None | Unknown`
+ src/prefect/cli/flow_run.py:265:20: error[unresolved-attribute] Attribute `is_scheduled` is not defined on `None` in union `State[Any] | None | Unknown`
+ src/prefect/cli/flow_run.py:266:22: error[unresolved-attribute] Attribute `timestamp` is not defined on `None` in union `State[Any] | None | Unknown`
+ src/prefect/cli/flow_run.py:272:21: error[unresolved-attribute] Attribute `type` is not defined on `None` in union `State[Any] | None | Unknown`
- src/prefect/flow_runs.py:251:26: error[invalid-assignment] Object of type `type[AutomaticRunInput[@Todo] | Unknown]` is not assignable to `type[T@apause_flow_run] | None`
+ src/prefect/flow_runs.py:251:26: error[invalid-assignment] Object of type `type[AutomaticRunInput[T@apause_flow_run] | Unknown]` is not assignable to `type[T@apause_flow_run] | None`
- src/prefect/flow_runs.py:405:26: error[invalid-assignment] Object of type `type[AutomaticRunInput[@Todo] | Unknown]` is not assignable to `type[T@pause_flow_run] | None`
+ src/prefect/flow_runs.py:405:26: error[invalid-assignment] Object of type `type[AutomaticRunInput[T@pause_flow_run] | Unknown]` is not assignable to `type[T@pause_flow_run] | None`
- src/prefect/flow_runs.py:557:26: error[invalid-assignment] Object of type `type[AutomaticRunInput[@Todo] | Unknown]` is not assignable to `type[T@asuspend_flow_run] | None`
+ src/prefect/flow_runs.py:557:26: error[invalid-assignment] Object of type `type[AutomaticRunInput[T@asuspend_flow_run] | Unknown]` is not assignable to `type[T@asuspend_flow_run] | None`
- src/prefect/flow_runs.py:682:26: error[invalid-assignment] Object of type `type[AutomaticRunInput[@Todo] | Unknown]` is not assignable to `type[T@suspend_flow_run] | None`
+ src/prefect/flow_runs.py:682:26: error[invalid-assignment] Object of type `type[AutomaticRunInput[T@suspend_flow_run] | Unknown]` is not assignable to `type[T@suspend_flow_run] | None`
- Found 5880 diagnostics
+ Found 5884 diagnostics

setuptools (https://github.com/pypa/setuptools)
+ setuptools/_distutils/command/build_ext.py:418:39: error[invalid-argument-type] Method `__getitem__` of type `bound method Top[dict[Unknown, Unknown]].__getitem__(key: Never, /) -> object` cannot be called with key of type `Literal["sources"]` on object of type `Top[dict[Unknown, Unknown]]`
+ setuptools/_distutils/command/build_ext.py:418:39: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[str | PathLike[str]]`, found `object`
+ setuptools/_distutils/command/build_ext.py:430:38: error[invalid-argument-type] Argument to bound method `get` is incorrect: Expected `Never`, found `Literal["include_dirs", "library_dirs", "libraries", "extra_objects", "extra_compile_args", "extra_link_args"]`
+ setuptools/_distutils/command/build_ext.py:435:55: error[invalid-argument-type] Argument to bound method `get` is incorrect: Expected `Never`, found `Literal["rpath"]`
+ setuptools/_distutils/command/build_ext.py:441:37: error[invalid-argument-type] Argument to bound method `get` is incorrect: Expected `Never`, found `Literal["macros"]`
- setuptools/_distutils/dist.py:74:12: error[invalid-return-type] Return type does not match returned value: expected `str | list[str]`, found `str | (Iterable[str] & Top[list[Unknown]]) | list[Unknown]`
+ setuptools/_distutils/dist.py:74:12: error[invalid-return-type] Return type does not match returned value: expected `str | list[str]`, found `str | (Iterable[str] & Top[list[Unknown]])`
- setuptools/_distutils/extension.py:123:37: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(str | bytes, /) -> str | bytes`, found `Overload[(path: str) -> str, (path: bytes) -> bytes, [AnyStr](path: PathLike[AnyStr]) -> AnyStr]`
+ setuptools/_distutils/extension.py:123:37: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(str | bytes | PathLike[str], /) -> str | bytes | PathLike[str]`, found `Overload[(path: str) -> str, (path: bytes) -> bytes, [AnyStr](path: PathLike[AnyStr]) -> AnyStr]`
- setuptools/_distutils/extension.py:123:48: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[str | bytes]`, found `Iterable[str | PathLike[str]] & ~str`
- Found 1173 diagnostics
+ Found 1177 diagnostics

scikit-build-core (https://github.com/scikit-build/scikit-build-core)
- src/scikit_build_core/cmake.py:180:53: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Buffer]`, found `list[Path] & ~AlwaysFalsy`
- src/scikit_build_core/cmake.py:188:53: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Buffer]`, found `list[Path] & ~AlwaysFalsy`
- Found 61 diagnostics
+ Found 59 diagnostics

dd-trace-py (https://github.com/DataDog/dd-trace-py)
+ ddtrace/contrib/internal/pymemcache/client.py:294:20: error[no-matching-overload] No overload of bound method `join` matches arguments
+ ddtrace/contrib/internal/pymemcache/client.py:296:30: error[invalid-argument-type] Argument to bound method `join` is incorrect: Expected `Iterable[Buffer]`, found `(Unknown & Top[list[Unknown]]) | list[object]`
+ ddtrace/contrib/internal/pymongo/utils.py:142:26: error[no-matching-overload] No overload of bound method `get` matches arguments
+ ddtrace/llmobs/_integrations/bedrock_agents.py:116:31: error[invalid-argument-type] Argument to bound method `get` is incorrect: Expected `Never`, found `Literal["traceId"]`
+ ddtrace/llmobs/_integrations/bedrock_agents.py:120:12: error[unresolved-attribute] Object of type `object` has no attribute `get`
- Found 9276 diagnostics
+ Found 9281 diagnostics

sympy (https://github.com/sympy/sympy)
+ sympy/core/function.py:3260:37: error[unsupported-operator] Unary operator `-` is not supported for object of type `Basic`
+ sympy/core/function.py:3264:37: error[invalid-argument-type] Argument to bound method `append` is incorrect: Expected `Unknown & Expr`, found `Basic`
+ sympy/core/numbers.py:923:26: error[unresolved-attribute] Object of type `object` has no attribute `removeprefix`
+ sympy/functions/elementary/piecewise.py:1266:30: error[not-iterable] Object of type `Basic` is not iterable
+ sympy/ntheory/tests/test_factor_.py:61:13: error[unsupported-operator] Operator `*=` is not supported between objects of type `Literal[1]` and `object`
+ sympy/ntheory/tests/test_factor_.py:63:16: error[unsupported-operator] Operator `%` is not supported between objects of type `~AlwaysFalsy & ~Literal[1]` and `Literal[2]`
+ sympy/ntheory/tests/test_factor_.py:64:17: error[unsupported-operator] Operator `*=` is not supported between objects of type `Literal[1]` and `object`
+ sympy/ntheory/tests/test_factor_.py:65:33: error[unsupported-operator] Operator `//` is not supported between objects of type `~AlwaysFalsy & ~Literal[1]` and `Literal[2]`
+ sympy/physics/control/lti.py:1355:25: error[unsupported-operator] Unary operator `-` is not supported for object of type `Basic`
+ sympy/physics/quantum/operatorset.py:117:33: error[call-non-callable] Object of type `object` is not callable
+ sympy/physics/quantum/operatorset.py:118:34: error[invalid-argument-type] Method `__getitem__` of type `bound method dict[frozenset[<class 'J2Op'> | <class 'JxOp'>] | frozenset[<class 'J2Op'> | <class 'JyOp'>] | frozenset[<class 'J2Op'> | <class 'JzOp'>] | ... omitted 4 union elements, <class 'JxKet'> | <class 'JyKet'> | <class 'JzKet'> | ... omitted 4 union elements].__getitem__(key: frozenset[<class 'J2Op'> | <class 'JxOp'>] | frozenset[<class 'J2Op'> | <class 'JyOp'>] | frozenset[<class 'J2Op'> | <class 'JzOp'>] | ... omitted 4 union elements, /) -> <class 'JxKet'> | <class 'JyKet'> | <class 'JzKet'> | ... omitted 4 union elements` cannot be called with key of type `frozenset[object]` on object of type `dict[frozenset[<class 'J2Op'> | <class 'JxOp'>] | frozenset[<class 'J2Op'> | <class 'JyOp'>] | frozenset[<class 'J2Op'> | <class 'JzOp'>] | ... omitted 4 union elements, <class 'JxKet'> | <class 'JyKet'> | <class 'JzKet'> | ... omitted 4 union elements]`
+ sympy/physics/quantum/operatorset.py:120:23: error[invalid-argument-type] Method `__getitem__` of type `bound method dict[frozenset[<class 'J2Op'> | <class 'JxOp'>] | frozenset[<class 'J2Op'> | <class 'JyOp'>] | frozenset[<class 'J2Op'> | <class 'JzOp'>] | ... omitted 4 union elements, <class 'JxKet'> | <class 'JyKet'> | <class 'JzKet'> | ... omitted 4 union elements].__getitem__(key: frozenset[<class 'J2Op'> | <class 'JxOp'>] | frozenset[<class 'J2Op'> | <class 'JyOp'>] | frozenset[<class 'J2Op'> | <class 'JzOp'>] | ... omitted 4 union elements, /) -> <class 'JxKet'> | <class 'JyKet'> | <class 'JzKet'> | ... omitted 4 union elements` cannot be called with key of type `frozenset[object]` on object of type `dict[frozenset[<class 'J2Op'> | <class 'JxOp'>] | frozenset[<class 'J2Op'> | <class 'JyOp'>] | frozenset[<class 'J2Op'> | <class 'JzOp'>] | ... omitted 4 union elements, <class 'JxKet'> | <class 'JyKet'> | <class 'JzKet'> | ... omitted 4 union elements]`
+ sympy/physics/quantum/operatorset.py:128:34: error[invalid-argument-type] Method `__getitem__` of type `bound method dict[frozenset[<class 'J2Op'> | <class 'JxOp'>] | frozenset[<class 'J2Op'> | <class 'JyOp'>] | frozenset[<class 'J2Op'> | <class 'JzOp'>] | ... omitted 4 union elements, <class 'JxKet'> | <class 'JyKet'> | <class 'JzKet'> | ... omitted 4 union elements].__getitem__(key: frozenset[<class 'J2Op'> | <class 'JxOp'>] | frozenset[<class 'J2Op'> | <class 'JyOp'>] | frozenset[<class 'J2Op'> | <class 'JzOp'>] | ... omitted 4 union elements, /) -> <class 'JxKet'> | <class 'JyKet'> | <class 'JzKet'> | ... omitted 4 union elements` cannot be called with key of type `frozenset[type]` on object of type `dict[frozenset[<class 'J2Op'> | <class 'JxOp'>] | frozenset[<class 'J2Op'> | <class 'JyOp'>] | frozenset[<class 'J2Op'> | <class 'JzOp'>] | ... omitted 4 union elements, <class 'JxKet'> | <class 'JyKet'> | <class 'JzKet'> | ... omitted 4 union elements]`
+ sympy/polys/domains/domain.py:1033:40: error[invalid-argument-type] Argument to bound method `map` is incorrect: Argument type `Iterable[int | Er@Domain]` does not satisfy upper bound `RingElement` of type variable `Er`
+ sympy/polys/rings.py:1769:69: error[not-iterable] Object of type `object` is not iterable
+ sympy/utilities/misc.py:465:24: error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `object`
- Found 16494 diagnostics
+ Found 16510 diagnostics

bokeh (https://github.com/bokeh/bokeh)
+ src/bokeh/server/tornado.py:295:71: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `(Document, /) -> None`, found `(Application & Top[(...) -> object]) | ((Document, /) -> None)`
+ src/bokeh/server/tornado.py:295:71: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `(Document, /) -> None`, found `(Application & Top[(...) -> object]) | ((Document, /) -> None)`
- Found 864 diagnostics
+ Found 866 diagnostics

streamlit (https://github.com/streamlit/streamlit)
- lib/streamlit/elements/layouts.py:611:41: warning[division-by-zero] Cannot divide object of type `int` by zero
- lib/streamlit/elements/layouts.py:611:41: warning[division-by-zero] Cannot divide object of type `float` by zero
- Found 14 diagnostics
+ Found 12 diagnostics

ibis (https://github.com/ibis-project/ibis)
+ ibis/backends/tests/test_api.py:53:52: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(object, /) -> object`, found `Overload[(self: LiteralString) -> LiteralString, (self) -> str]`
- Found 4888 diagnostics
+ Found 4889 diagnostics

zulip (https://github.com/zulip/zulip)
- zerver/lib/user_topics.py:265:68: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[RecipientTopicDict]`, found `QuerySet[UserTopic, dict[str, Any]] & ~AlwaysFalsy`
- zerver/lib/user_topics.py:303:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[RecipientTopicDict]`, found `QuerySet[UserTopic, dict[str, Any]] & ~AlwaysFalsy`
+ zerver/lib/user_topics.py:265:56: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(RecipientTopicDict | dict[str, Any], /) -> Unknown`, found `def topic_cond(row: RecipientTopicDict) -> Unknown`
+ zerver/lib/user_topics.py:303:22: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(RecipientTopicDict | dict[str, Any], /) -> Unknown`, found `def topic_cond(row: RecipientTopicDict) -> Unknown`
- zerver/models/custom_profile_fields.py:46:48: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Buffer]`, found `list[int] & ~AlwaysFalsy`
- Found 4740 diagnostics
+ Found 4739 diagnostics

static-frame (https://github.com/static-frame/static-frame)
- static_frame/core/metadata.py:119:68: warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- Found 1870 diagnostics
+ Found 1869 diagnostics

materialize (https://github.com/MaterializeInc/materialize)
+ misc/python/materialize/feature_benchmark/report.py:39:13: error[invalid-assignment] Object of type `int | float` is not assignable to attribute `mean` of type `T@ReportMeasurement | None`
- misc/python/materialize/mzexplore/extract.py:468:40: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Buffer]`, found `list[ExplainOption] & ~AlwaysFalsy`

scikit-learn (https://github.com/scikit-learn/scikit-learn)
+ sklearn/metrics/tests/test_pairwise.py:743:12: error[unresolved-attribute] Object of type `object` has no attribute `dtype`
+ sklearn/metrics/tests/test_pairwise.py:746:21: error[no-matching-overload] No overload of function `vstack` matches arguments
+ sklearn/metrics/tests/test_pairwise.py:840:23: error[unresolved-attribute] Object of type `object` has no attribute `nbytes`
+ sklearn/metrics/tests/test_pairwise.py:843:27: error[no-matching-overload] No overload of function `vstack` matches arguments
+ sklearn/utils/validation.py:2515:13: error[invalid-argument-type] Argument to bound method `sort` is incorrect: Argument type `object` does not satisfy upper bound `SupportsDunderLT[Any] | SupportsDunderGT[Any]` of type variable `SupportsRichComparisonT`
- Found 2542 diagnostics
+ Found 2547 diagnostics

jax (https://github.com/google/jax)
+ jax/_src/array.py:1106:12: error[invalid-assignment] Object of type `list[object] | (Sequence[Array] & ~tuple[object, ...])` is not assignable to `Sequence[Array]`
- jax/_src/pallas/hlo_interpreter.py:415:50: warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- jax/_src/pallas/mosaic/interpret/interpret_pallas_call.py:1971:60: warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- jax/_src/pallas/pallas_call.py:837:50: warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
+ jax/_src/pallas/primitives.py:407:45: error[unresolved-attribute] Attribute `shape` is not defined on `int & ~Slice` in union `(int & ~Slice) | (Array & ~Slice)`
+ jax/_src/pallas/primitives.py:1188:21: error[invalid-argument-type] Method `__getitem__` of type `bound method dict[str, int].__getitem__(key: str, /) -> int` cannot be called with key of type `object` on object of type `dict[str, int]`
+ jax/_src/pallas/primitives.py:1202:35: error[invalid-argument-type] Method `__getitem__` of type `bound method dict[str, int].__getitem__(key: str, /) -> int` cannot be called with key of type `object` on object of type `dict[str, int]`
- Found 2168 diagnostics
+ Found 2169 diagnostics

pandas (https://github.com/pandas-dev/pandas)
- pandas/core/frame.py:14680:20: error[invalid-return-type] Return type does not match returned value: expected `DataFrame`, found `DataFrame | Series | Unknown`
+ pandas/core/frame.py:14680:20: error[invalid-return-type] Return type does not match returned value: expected `DataFrame`, found `DataFrame | Series`
+ pandas/core/indexes/multi.py:4631:49: error[invalid-argument-type] Argument to bound method `from_tuples` is incorrect: Expected `Iterable[tuple[Hashable, ...]]`, found `(Unknown & ~Generator[object, None, None] & ~MultiIndex) | (list[object] & ~MultiIndex)`
+ pandas/core/indexing.py:2982:30: error[no-matching-overload] No overload of bound method `reshape` matches arguments
- pandas/core/reshape/concat.py:807:12: error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `Iterable[Series | DataFrame] | Mapping[HashableT@_clean_keys_and_objs, Series | DataFrame] | list[Unknown]`
+ pandas/core/reshape/concat.py:807:12: error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `Iterable[Series | DataFrame] | Mapping[HashableT@_clean_keys_and_objs, Series | DataFrame]`
- pandas/core/reshape/concat.py:813:29: error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `Iterable[Series | DataFrame] | Mapping[HashableT@_clean_keys_and_objs, Series | DataFrame] | list[Unknown]`
+ pandas/core/reshape/concat.py:813:29: error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `Iterable[Series | DataFrame] | Mapping[HashableT@_clean_keys_and_objs, Series | DataFrame]`
- pandas/core/reshape/concat.py:817:66: error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `Iterable[Series | DataFrame] | Mapping[HashableT@_clean_keys_and_objs, Series | DataFrame] | list[Unknown]`
+ pandas/core/reshape/concat.py:817:66: error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `Iterable[Series | DataFrame] | Mapping[HashableT@_clean_keys_and_objs, Series | DataFrame]`
- pandas/io/parsers/python_parser.py:991:26: warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- Found 4584 diagnostics
+ Found 4585 diagnostics

core (https://github.com/home-assistant/core)
+ homeassistant/components/bayesian/binary_sensor.py:340:69: error[invalid-assignment] Object of type `OrderedDict[UUID | Unknown | str, Observation]` is not assignable to `OrderedDict[UUID, Observation]`: Incompatible value of type `OrderedDict[UUID | Unknown | str, Observation]`
+ homeassistant/components/bayesian/binary_sensor.py:464:62: error[invalid-assignment] Object of type `OrderedDict[UUID | Unknown | str, Observation]` is not assignable to `OrderedDict[UUID, Observation]`
+ homeassistant/components/bayesian/binary_sensor.py:472:62: error[invalid-assignment] Object of type `OrderedDict[UUID | Unknown | str, Observation]` is not assignable to `OrderedDict[UUID, Observation]`
- homeassistant/components/fyta/coordinator.py:95:70: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Buffer]`, found `set[int] & ~AlwaysFalsy`
+ homeassistant/components/google_assistant/http.py:413:12: error[invalid-return-type] Return type does not match returned value: expected `list[str]`, found `list[object]`
+ homeassistant/components/isy994/helpers.py:237:24: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(object, /) -> object`, found `Overload[(self: LiteralString) -> LiteralString, (self) -> str]`
+ homeassistant/components/onvif/device.py:430:21: error[unresolved-attribute] Object of type `object` has no attribute `VideoEncoderConfiguration`
+ homeassistant/components/onvif/device.py:431:20: error[unresolved-attribute] Object of type `object` has no attribute `VideoEncoderConfiguration`
+ homeassistant/components/onvif/device.py:437:17: error[unresolved-attribute] Object of type `object` has no attribute `token`
+ homeassistant/components/onvif/device.py:438:17: error[unresolved-attribute] Object of type `object` has no attribute `Name`
+ homeassistant/components/onvif/device.py:440:21: error[unresolved-attribute] Object of type `object` has no attribute `VideoEncoderConfiguration`
+ homeassistant/components/onvif/device.py:442:25: error[unresolved-attribute] Object of type `object` has no attribute `VideoEncoderConfiguration`
+ homeassistant/components/onvif/device.py:443:25: error[unresolved-attribute] Object of type `object` has no attribute `VideoEncoderConfiguration`
+ homeassistant/components/onvif/device.py:449:42: error[unresolved-attribute] Object of type `object` has no attribute `PTZConfiguration`
+ homeassistant/components/onvif/device.py:451:21: error[unresolved-attribute] Object of type `object` has no attribute `PTZConfiguration`
+ homeassistant/components/onvif/device.py:453:21: error[unresolved-attribute] Object of type `object` has no attribute `PTZConfiguration`
+ homeassistant/components/onvif/device.py:455:21: error[unresolved-attribute] Object of type `object` has no attribute `PTZConfiguration`
+ homeassistant/components/onvif/device.py:468:46: error[unresolved-attribute] Object of type `object` has no attribute `VideoSourceConfiguration`
+ homeassistant/components/onvif/device.py:470:21: error[unresolved-attribute] Object of type `object` has no attribute `VideoSourceConfiguration`
- homeassistant/components/solarlog/coordinator.py:182:70: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Buffer]`, found `set[tuple[int, str]] & ~AlwaysFalsy`
- homeassistant/components/solarlog/coordinator.py:207:72: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Buffer]`, found `set[tuple[int, Unknown]] & ~AlwaysFalsy`
- homeassistant/components/tedee/coordinator.py:147:67: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Buffer]`, found `set[int] & ~AlwaysFalsy`
- homeassistant/config_entries.py:1810:74: warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
+ homeassistant/helpers/selector.py:34:26: error[invalid-assignment] Object of type `object` is not assignable to `str`
+ homeassistant/util/hass_dict.pyi:146:5: error[type-assertion-failure] Type `dict[str, int | Unknown]` does not match asserted type `dict[str, int]`
+ homeassistant/util/hass_dict.pyi:147:5: error[type-assertion-failure] Type `int | Unknown` does not match asserted type `int`
+ homeassistant/util/hass_dict.pyi:155:62: warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- Found 12076 diagnostics
+ Found 12093 diagnostics

pandas-stubs (https://github.com/pandas-dev/pandas-stubs)
- tests/test_io.py:943:9: error[type-assertion-failure] Type `dict[Unknown, DataFrame]` does not match asserted type `dict[str, DataFrame]`
- tests/test_io.py:953:9: error[type-assertion-failure] Type `dict[Unknown, DataFrame]` does not match asserted type `dict[int, DataFrame]`
- tests/test_io.py:1069:9: error[type-assertion-failure] Type `dict[Unknown, DataFrame]` does not match asserted type `dict[str, DataFrame]`
- tests/test_io.py:1072:11: error[type-assertion-failure] Type `dict[Unknown, DataFrame]` does not match asserted type `dict[int, DataFrame]`
- Found 4763 diagnostics
+ Found 4759 diagnostics

scipy (https://github.com/scipy/scipy)
+ scipy/_lib/_util.py:1035:21: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `(object, /) -> int`, found `def len(obj: Sized, /) -> int`
+ scipy/special/_multiufuncs.py:367:21: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `_IntegralLike`
- Found 7989 diagnostics
+ Found 7991 diagnostics

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 53b61ecd90

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +2231 to +2232
for positive in actual_intersection.iter_positive(self.db) {
self.infer_map_impl(constraints, formal, positive, polarity, f, seen)?;

Choose a reason for hiding this comment

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

P2 Badge Skip failing positives when inferring actual intersections

This loop propagates Err from the first positive element that fails inference, but for (_, Type::Intersection(..)) a single failing positive does not imply the whole intersection is incompatible with formal. In bounded/constrained TypeVar cases, one positive can raise MismatchedBound/MismatchedConstraint while another positive would infer a valid mapping, so returning early here can produce false specialization errors (for example, intersected sequence element types where only one branch satisfies the TypeVar bound). This branch should mirror the union logic by trying all positives and only surfacing an error if none produce usable inference.

Useful? React with 👍 / 👎.

Copy link
Contributor

Choose a reason for hiding this comment

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

This comment looks accurate to me? It seems like we are missing test coverage for an intersection with multiple positive elements, at least one of which matches the formal parameter and some of which do not.

I suspect we may already have handling for a similar case, where we handle matching a union formal parameter? That's another case where it's OK for any element of the union to match, rather than requiring that all do. (In some sense, that case is a closer parallel to this one than the intersection-formal-parameter case.)

Copy link
Member

Choose a reason for hiding this comment

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

Yes this is correct. This is showing the duality of the lhs vs rhs of an intersection. This should only return an error if every positive element raises an error. In the constraint set world, this clause will use when_any, like is done here in has_relation_to (note that reversed parameter order).

The intersection formal case, otoh, would use when_all, like here (and note that the has_relation_to version also checks the negative elements for disjointness).

I suspect we may already have handling for a similar case, where we handle matching a union formal parameter?

We do have that, just above! It has a special case return for when precisely one element matches, and implements the "only error if no element succeeds" logic. We can probably extract that into a helper method or closure and call it in both places.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok I've pushed a new version based on our conversation this morning/afternoon.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 5, 2026

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-argument-type 36 16 8
unresolved-attribute 30 0 2
invalid-assignment 8 0 7
no-matching-overload 12 2 0
invalid-return-type 8 0 4
unsupported-operator 10 0 0
unused-type-ignore-comment 1 6 0
type-assertion-failure 2 4 0
division-by-zero 0 2 0
not-iterable 2 0 0
call-non-callable 1 0 0
Total 110 30 21

Full report with detailed diff (timing results)

@carljm carljm removed their request for review March 5, 2026 05:25
@dcreager
Copy link
Member

dcreager commented Mar 5, 2026

@dcreager are you the best reviewer for this? This is my first time in this area of the code so please don't hesitate to ELI5.

I am! Taking a look now

@oconnor663 oconnor663 force-pushed the jack/infer_map_impl_intersections branch from 53b61ec to d549858 Compare March 7, 2026 01:18

# An intersection where both positive elements satisfy the bound.
def _(x: Intersection[Sequence[Sub1], Sequence[Sub2]]) -> None:
reveal_type(first(x)) # revealed: Sub1 | Sub2
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dcreager we talked about the union Sub1 | Sub2 being the correct answer here, but now that I look at it it feels wrong. Should this be have a TODO: should be Sub1 & Sub2 or similar? Or have I maybe done something wrong in the implementation?

Copy link
Member

Choose a reason for hiding this comment

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

No I think this is right. As you mention above, "inference can fail for some elements but succeed for others". If this were Sub1 & Sub2, that would mean that inference had to succeed for all elements.


# An intersection where both positive elements satisfy the bound.
def _(x: Intersection[Sequence[Sub1], Sequence[Sub2]]) -> None:
reveal_type(first(x)) # revealed: Sub1 | Sub2
Copy link
Member

Choose a reason for hiding this comment

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

No I think this is right. As you mention above, "inference can fail for some elements but succeed for others". If this were Sub1 & Sub2, that would mean that inference had to succeed for all elements.

Comment on lines +981 to +982
def _(x: Intersection[Sequence[Sub1], Sequence[Unrelated1]]) -> None:
reveal_type(first(x)) # revealed: Sub1
Copy link
Member

Choose a reason for hiding this comment

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

This a good example for understanding why union is correct. Unrelated1 does not satisfy T's upper bound, so it's not a valid solution. I think you technically end up with T = Never as the only solution. But then you want union so that simplifies T = Sub1 | Never = Sub1. If you used intersection you'd get T = Sub1 & Never = Never.

Comment on lines +988 to +991
# An intersection with two positive elements, neither of which satisfies the bound. In this case,
# only the error related to the first element is reported.
def _(x: Intersection[Sequence[Unrelated1], Sequence[Unrelated2]]) -> None:
# error: [invalid-argument-type] "Argument to function `first` is incorrect: Argument type `Unrelated1` does not satisfy upper bound `Base` of type variable `T`"
Copy link
Member

Choose a reason for hiding this comment

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

This does describe the current behavior, but we might consider a TODO to show all of the failures.

Comment on lines +2239 to +2240
// If the typevar in this case is upper-bounded or constrained, it's sufficient for
// one intersection element to satisfy the constraint. They don't all have to.
Copy link
Member

Choose a reason for hiding this comment

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

This is true, though upper bounds / constraints are not the only way that the intersection element might not satisfy the constraint. So I'd remove that bit from the comment:

// It's sufficient for only one intersection element to satisfy the constraint.
// They don't all have to.

(You'll probably have to reflow that to pass lint)

@AlexWaygood AlexWaygood removed their request for review March 9, 2026 17:40
@oconnor663
Copy link
Contributor Author

oconnor663 commented Mar 9, 2026

Looking at the ecosystem results for apprise, I believe the change minimizes to this, which makes it a true positive (edit: Carl points out below that it's really a false positive):

from ty_extensions import Unknown

def f(s: str) -> None: ...

def test(maybe_list: Unknown) -> None:
    if isinstance(maybe_list, list):
        # both: revealed: Unknown & Top[list[Unknown]]
        reveal_type(maybe_list)

        # main: revealed: Unknown
        # pr: revealed: Iterator[object]
        reveal_type(iter(maybe_list))

        for elem in iter(maybe_list):
            # main: revealed: Unknown
            # pr: revealed: object
            reveal_type(elem)

            # main: no error
            # pr: error: [invalid-argument-type]
            f(elem)

@carljm
Copy link
Contributor

carljm commented Mar 9, 2026

I would expect iter(maybe_list) to reveal as Unknown & Iterator[object], and elem to reveal as Unknown (simplified from Unknown & object). So I'd call this a false positive of sorts -- not one that's definitely wrong, but just one where we should be more forgiving given the original gradual type. Unknown may be an iterator of some narrower type. We shouldn't "erase" this possibility when we call iter on Unknown & Top[list[Unknown]].

(I haven't looked at why this is happening in the implementation or how to fix it.)

@oconnor663
Copy link
Contributor Author

@carljm I think the cause there might be described by this TODO in generics.rs:

    // TODO special-casing Unknown to mean "no mapping" is not right here, and can give
    // confusing/wrong results in cases where there was a mapping found for a typevar, and it
    // was of type Unknown. We should probably add a bitset or similar to Specialization that
    // explicitly tells us which typevars are mapped.

@carljm
Copy link
Contributor

carljm commented Mar 9, 2026

Looks likely! Seems like that could just be filed as a separate issue, if it doesn't look widespread.

@oconnor663 oconnor663 force-pushed the jack/infer_map_impl_intersections branch from d549858 to 537a67d Compare March 9, 2026 22:36
@oconnor663
Copy link
Contributor Author

Another set of ecosystem hits seems to boil down to the following effect:

from typing import overload

@overload
def f[T](_: list[T], /) -> list[T]: ...
@overload
def f(_: list[str], /) -> list[str]: ...
def f(_): ...

# main: revealed: list[Unknown]
# pr: revealed: list[str | Unknown]
reveal_type(f([]))

I think this change to how overloads are handled is responsible for the new invalid-assignment errors in homeassistant but also for the removed errors in pandas-stubs.

What's happening here is that we intersect the overloaded argument types, and that somehow (I haven't followed all the steps) interacts with the changes in intersection handling in this PR. It's pretty surprising to me that we'd do an intersection here, but there's a TODO that suggests this might be a known but kind of unintended behavior:

// TODO: intersecting the inferred argument types is correct for unions of
// callables, since the argument must satisfy each callable, but it's not clear
// that it's correct for an intersection of callables, or for a case where
// different overloads provide different type context; unioning may be more
// correct in those cases.

Claude breaks down the sequence of events like this:

Step 1 — Infer [] with no type context (types/infer/builder.rs:9469):

step1: infer arg with no tcx -> list[Unknown]

Step 2a — Re-infer [] with overload 1's parameter type (types/infer/builder.rs:9491):

step2: infer arg with tcx=list[UnspecializedTypeVar]
step2: inferred_ty=list[Unknown]
step2: intersected list[Unknown] & list[Unknown] -> list[Unknown]

Step 2b — Re-infer [] with overload 2's parameter type (types/infer/builder.rs:9491):

step2: infer arg with tcx=list[str]
step2: inferred_ty=list[str]
step2: intersected list[str] & list[Unknown] -> list[str] & list[Unknown]

Step 3 — Overload 1 selected, generic inference resolves T@f from the intersected argument (types/generics.rs:2226):

actual-intersection arm: formal=list[T@f], actual=list[str] & list[Unknown]
-> formal=list[T@f], actual=list[str] -> add_type_mapping: T@f = str (first)
-> formal=list[T@f], actual=list[Unknown] -> add_type_mapping: T@f = str | Unknown (unioned)

Result — T@f = str | Unknown, so f([]) returns list[str | Unknown].

Without this PR, step 3 there infers nothing, and T defaults to Unknown.

@oconnor663
Copy link
Contributor Author

astral-sh/ty#3001 aims to address the TODO I linked above.

@oconnor663
Copy link
Contributor Author

oconnor663 commented Mar 10, 2026

Seems like that could just be filed as a separate issue, if it doesn't look widespread.

Opened astral-sh/ty#3009.

@oconnor663 oconnor663 enabled auto-merge (squash) March 10, 2026 00:27
@oconnor663 oconnor663 merged commit df3b260 into main Mar 10, 2026
50 checks passed
@oconnor663 oconnor663 deleted the jack/infer_map_impl_intersections branch March 10, 2026 00:32
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.

map(str, cmd) fails with Sequence[str] & ~str, succeeds with Sequence[str]

4 participants