Skip to content

Conversation

@hauntsaninja
Copy link
Collaborator

@hauntsaninja hauntsaninja commented Jan 28, 2026

By decoupling if_map's and else_map's we don't have to make up empty dictionaries to make them zip well, which enables us to preserve the None's that indicate a lack of reachability better.

This also prevents us from losing narrowing constraints in some cases, see e.g. the new testNarrowingConstrainedTypeVarType test which we previously errored on

Improves #17372
Fixes #17045
Improves #14965
Fixes this comment #9003 (comment)

def __ge__(self, x: i64) -> bool: ...
def __gt__(self, x: i64) -> bool: ...
def __index__(self) -> int: ...
def __eq__(self, x: object) -> bool: ...
Copy link
Collaborator Author

@hauntsaninja hauntsaninja Jan 28, 2026

Choose a reason for hiding this comment

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

Without (correctly) annotating the custom equality here, we would consider otherwise reachable code to be unreachable. Specifically the right side of this or clause:

if meta[0] != cache_version() or meta[1] != CACHE_VERSION:

@hauntsaninja
Copy link
Collaborator Author

hauntsaninja commented Jan 28, 2026

@p-sawicki I'm getting AssertionError: Cannot add a traceback entry with a negative line number for op on this PR, seems like this is new to your PR, any advice? If I revert your PR, things pass

https://github.com/python/mypy/actions/runs/21421020108/job/61680277800?pr=20660

@github-actions

This comment has been minimized.

@hauntsaninja hauntsaninja changed the title Improve reachability in narrowing logic Improve reachability in narrowing logic, avoid losing narrowing constraints Jan 28, 2026
@hauntsaninja hauntsaninja marked this pull request as draft January 28, 2026 01:32
@github-actions

This comment has been minimized.

@hauntsaninja
Copy link
Collaborator Author

Primer needs some work, specifically I need to handle promotions better

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@hauntsaninja hauntsaninja changed the title Improve reachability in narrowing logic, avoid losing narrowing constraints [wip] Improve reachability in narrowing logic, avoid losing narrowing constraints Jan 28, 2026
@github-actions

This comment has been minimized.

@github-actions
Copy link
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/server/api/server.py:664: error: Invalid index type "tuple[str, bool, bool]" for "dict[tuple[Settings, bool], Any]"; expected type "tuple[Settings, bool]"  [index]

pydantic (https://github.com/pydantic/pydantic)
+ pydantic/v1/typing.py:236: error: Unused "type: ignore" comment  [unused-ignore]

mypy (https://github.com/python/mypy)
+ mypy/server/aststrip.py:140: error: If condition in comprehension is always true  [redundant-expr]
+ mypy/server/aststrip.py:140: note: Error code "redundant-expr" not covered by "type: ignore" comment
+ mypy/server/aststrip.py:140: note: See https://mypy.rtfd.io/en/stable/_refs.html#code-redundant-expr for more info
+ mypy/stubutil.py:76: error: Statement is unreachable  [unreachable]
+ mypy/stubutil.py:76: note: See https://mypy.rtfd.io/en/stable/_refs.html#code-unreachable for more info

schemathesis (https://github.com/schemathesis/schemathesis)
+ src/schemathesis/specs/openapi/extra_data_source.py: note: In member "weighted_select" of class "VariantUsageTracker":
+ src/schemathesis/specs/openapi/extra_data_source.py:85: error: Statement is unreachable  [unreachable]

operator (https://github.com/canonical/operator)
- ops/_private/harness.py:2563: error: Invalid index type "str" for "dict[int, dict[str, Any]]"; expected type "int"  [index]

core (https://github.com/home-assistant/core)
+ homeassistant/components/homekit/__init__.py:982: error: Right operand of "or" is never evaluated  [unreachable]
+ homeassistant/components/firefly_iii/sensor.py:190: error: Statement is unreachable  [unreachable]

pytest (https://github.com/pytest-dev/pytest)
+ testing/test_capture.py:923: error: Statement is unreachable  [unreachable]

hydra-zen (https://github.com/mit-ll-responsible-ai/hydra-zen)
+ src/hydra_zen/structured_configs/_implementations.py:1075: error: Unused "type: ignore" comment  [unused-ignore]
+ src/hydra_zen/structured_configs/_implementations.py:1322: error: Unused "type: ignore" comment  [unused-ignore]

pandas (https://github.com/pandas-dev/pandas)
+ pandas/core/arrays/datetimes.py:2997: error: Unused "type: ignore" comment  [unused-ignore]
+ pandas/core/arrays/datetimes.py:3009: error: Unused "type: ignore" comment  [unused-ignore]
+ pandas/core/arrays/datetimes.py:3011: error: Redundant cast to "Timestamp"  [redundant-cast]
+ pandas/core/arrays/datetimes.py:3012: error: Redundant cast to "Timestamp"  [redundant-cast]

discord.py (https://github.com/Rapptz/discord.py)
+ discord/http.py:274: error: Unused "type: ignore" comment  [unused-ignore]
- discord/http.py:190: error: Incompatible types in assignment (expression has type "str", target has type "list[Embed]")  [assignment]
- discord/http.py:192: error: Incompatible types in assignment (expression has type "None", target has type "list[Embed]")  [assignment]
- discord/http.py:196: error: Incompatible types in assignment (expression has type "list[dict[str, Any]]", target has type "list[Embed]")  [assignment]
- discord/http.py:207: error: Incompatible types in assignment (expression has type "str", target has type "list[Embed]")  [assignment]
- discord/http.py:208: error: Incompatible types in assignment (expression has type "bool", target has type "list[Embed]")  [assignment]
- discord/http.py:211: error: Incompatible types in assignment (expression has type "MessageReference | None", target has type "list[Embed]")  [assignment]
- discord/http.py:215: error: Incompatible types in assignment (expression has type "list[str | int]", target has type "list[Embed]")  [assignment]
- discord/http.py:219: error: Incompatible types in assignment (expression has type "bool", target has type "list[Embed]")  [assignment]
- discord/http.py:221: error: Incompatible types in assignment (expression has type "str", target has type "list[Embed]")  [assignment]
- discord/http.py:223: error: Incompatible types in assignment (expression has type "str", target has type "list[Embed]")  [assignment]
- discord/http.py:226: error: Incompatible types in assignment (expression has type "int", target has type "list[Embed]")  [assignment]
- discord/http.py:229: error: Incompatible types in assignment (expression has type "str", target has type "list[Embed]")  [assignment]
- discord/http.py:233: error: Incompatible types in assignment (expression has type "AllowedMentions", target has type "list[Embed]")  [assignment]
- discord/http.py:235: error: Incompatible types in assignment (expression has type "AllowedMentions", target has type "list[Embed]")  [assignment]
- discord/http.py:237: error: Incompatible types in assignment (expression has type "AllowedMentions", target has type "list[Embed]")  [assignment]
- discord/http.py:241: error: Incompatible types in assignment (expression has type "AllowedMentions", target has type "list[Embed]")  [assignment]
- discord/http.py:242: error: No overload variant of "__setitem__" of "list" matches argument types "str", "bool"  [call-overload]
- discord/http.py:242: note: Possible overload variants:
- discord/http.py:242: note:     def __setitem__(self, SupportsIndex, Embed, /) -> None
- discord/http.py:242: note:     def __setitem__(self, slice[Any, Any, Any], Iterable[Embed], /) -> None
- discord/http.py:257: error: Argument 1 to "append" of "list" has incompatible type "Attachment"; expected "dict[str, Any]"  [arg-type]
- discord/http.py:259: error: Incompatible types in assignment (expression has type "list[dict[str, Any]]", target has type "list[Embed]")  [assignment]
- discord/http.py:263: error: Incompatible types in assignment (expression has type "list[str | int]", target has type "list[Embed]")  [assignment]
- discord/http.py:269: error: Dict entry 0 has incompatible type "str": "dict[str, list[Embed]]"; expected "str": "list[Embed]"  [dict-item]
- discord/http.py:279: error: Incompatible types in assignment (expression has type "None", variable has type "dict[str, list[Embed]]")  [assignment]
- discord/http.py:284: error: Dict entry 1 has incompatible type "str": "BufferedIOBase"; expected "str": "str"  [dict-item]
- discord/webhook/sync.py:1105: error: Argument "applied_tags" to "handle_message_parameters" has incompatible type "str | Snowflake"; expected "list[str | int] | None"  [arg-type]
+ discord/webhook/sync.py:1105: error: Cannot determine type of "applied_tag_ids"  [has-type]
- discord/webhook/async_.py:578: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:582: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:584: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:588: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:590: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:594: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:603: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:606: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:610: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:612: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:614: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:629: error: Argument 1 to "append" of "list" has incompatible type "Attachment"; expected "dict[str, Any]"  [arg-type]
- discord/webhook/async_.py:631: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:634: error: Unsupported target for indexed assignment ("dict[str, Any] | None")  [index]
- discord/webhook/async_.py:645: error: Dict entry 1 has incompatible type "str": "BufferedIOBase"; expected "str": "str"  [dict-item]
- discord/webhook/async_.py:1892: error: Argument "applied_tags" to "handle_message_parameters" has incompatible type "str | Snowflake"; expected "list[str | int] | None"  [arg-type]
+ discord/webhook/async_.py:1892: error: Cannot determine type of "applied_tag_ids"  [has-type]

trio (https://github.com/python-trio/trio)
+ src/trio/_core/_tests/test_run.py:2457: error: Unused "type: ignore" comment  [unused-ignore]

Expression (https://github.com/cognitedata/Expression)
- README.py:460: error: Incompatible types in assignment (expression has type "Result[int, Exception]", variable has type "Seq[int]")  [assignment]

pyodide (https://github.com/pyodide/pyodide)
+ pyodide-build/pyodide_build/tests/test_xbuildenv.py:88: error: Statement is unreachable  [unreachable]

rotki (https://github.com/rotki/rotki)
+ rotkehlchen/exchanges/binance.py:391: error: Statement is unreachable  [unreachable]
+ rotkehlchen/tests/api/test_evmlike.py:212: error: Statement is unreachable  [unreachable]
+ rotkehlchen/tests/api/test_history_base_entry.py:1263: error: Need type annotation for "ids_per_subtype"  [var-annotated]

static-frame (https://github.com/static-frame/static-frame)
+ static_frame/core/type_blocks.py:1633: error: Unused "type: ignore" comment  [unused-ignore]
+ static_frame/core/type_blocks.py:1634: error: Unused "type: ignore" comment  [unused-ignore]
+ static_frame/core/type_blocks.py:1759: error: Unused "type: ignore" comment  [unused-ignore]
+ static_frame/core/type_blocks.py:1760: error: Unused "type: ignore" comment  [unused-ignore]
+ static_frame/core/archive_npy.py:231: error: Statement is unreachable  [unreachable]
+ static_frame/core/interface.py:1041: error: Statement is unreachable  [unreachable]
+ static_frame/core/interface.py:1043: error: Statement is unreachable  [unreachable]
+ static_frame/core/interface.py:1066: error: Item "type" of "type[InterfaceValues[TVContainer_co@InterfaceValues]] | type[InterfaceString[TVContainer_co@InterfaceString]] | type[InterfaceDatetime[TVContainer_co@InterfaceDatetime]] | type[InterfaceTranspose[TVContainer_co@InterfaceTranspose]] | type[InterfaceFillValue[TVContainer_co@InterfaceFillValue]] | type[InterfaceRe[TVContainer_co@InterfaceRe]] | type[ReduceDispatch] | type[<subclass of "static_frame.core.node_selector.Interface" and "typing.Mapping[Any, Any]">]" has no attribute "CLS_DELEGATE"  [union-attr]

cloud-init (https://github.com/canonical/cloud-init)
+ tests/unittests/sources/test_maas.py:269: error: Statement is unreachable  [unreachable]
+ tests/unittests/cmd/test_status.py:260: error: Statement is unreachable  [unreachable]

xarray (https://github.com/pydata/xarray)
+ xarray/core/extension_array.py: note: In function "union_unordered_categorical_and_scalar":
+ xarray/core/extension_array.py:163: error: If condition in comprehension is always true  [redundant-expr]

@p-sawicki
Copy link
Collaborator

@p-sawicki I'm getting AssertionError: Cannot add a traceback entry with a negative line number for op on this PR, seems like this is new to your PR, any advice? If I revert your PR, things pass

https://github.com/python/mypy/actions/runs/21421020108/job/61680277800?pr=20660

the assertions are meant to catch mistakes when modifying mypyc so it's unfortunate that changes in mypy triggered them. are tests still failing because of them? if they block unrelated PRs then i think we would have to disable them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrect "redundant cast" for linked TypeVar T and type[T] variables

2 participants