Skip to content

Conversation

@randolf-scholz
Copy link
Contributor

@randolf-scholz randolf-scholz commented Aug 1, 2025

Option ①: #19563

Option ② from #19561 (comment) which additionally copies MemberExpr elements to the nested binder, hence allows ternaries like f(x.attr) if x.attr else g(x.attr) to consider the bound type of x.attr.

The current implementation of visit_conditional_expr seemed to some rather complicated things, I found that if there is no context, we can simply use the union of the types produced when considering the branches context-free as an artificial context that leads to the desired behavior in the unification test cases.

@randolf-scholz randolf-scholz changed the title refactor visit_conditional_expr to fix ternary behavior refactor visit_conditional_expr to fix ternary behavior (option 2) Aug 1, 2025
@github-actions

This comment has been minimized.

@github-actions
Copy link
Contributor

github-actions bot commented Aug 1, 2025

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

colour (https://github.com/colour-science/colour)
+ colour/io/luts/lut.py:1366: error: Argument 1 to "tile" has incompatible type "Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] | None"; expected "_SupportsArray[dtype[signedinteger[_8Bit] | signedinteger[_16Bit] | signedinteger[_32Bit] | signedinteger[_64Bit] | unsignedinteger[_8Bit] | unsignedinteger[_16Bit] | unsignedinteger[_32Bit] | unsignedinteger[_64Bit] | Any]] | _NestedSequence[_SupportsArray[dtype[signedinteger[_8Bit] | signedinteger[_16Bit] | signedinteger[_32Bit] | signedinteger[_64Bit] | unsignedinteger[_8Bit] | unsignedinteger[_16Bit] | unsignedinteger[_32Bit] | unsignedinteger[_64Bit] | Any]]]"  [arg-type]
- colour/io/luts/lut.py:1380: error: No overload variant of "pad" matches argument types "ndarray[Any, Any]", "tuple[int, Any | signedinteger[_8Bit] | signedinteger[_16Bit] | signedinteger[_32Bit] | signedinteger[_64Bit] | unsignedinteger[_8Bit] | unsignedinteger[_16Bit] | unsignedinteger[_32Bit] | unsignedinteger[_64Bit]]", "str", "float"  [call-overload]
- colour/io/luts/lut.py:1380: note: Possible overload variants:
- colour/io/luts/lut.py:1380: note:     def [_ScalarT: generic[Any]] pad(array: _SupportsArray[dtype[_ScalarT]] | _NestedSequence[_SupportsArray[dtype[_ScalarT]]], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int], mode: Literal['constant', 'edge', 'linear_ramp', 'maximum', 'mean', 'median', 'minimum', 'reflect', 'symmetric', 'wrap', 'empty'] = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[Any, ...], dtype[_ScalarT]]
- colour/io/luts/lut.py:1380: note:     def pad(array: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int], mode: Literal['constant', 'edge', 'linear_ramp', 'maximum', 'mean', 'median', 'minimum', 'reflect', 'symmetric', 'wrap', 'empty'] = ..., *, stat_length: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int] | None = ..., constant_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., end_values: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str] = ..., reflect_type: Literal['odd', 'even'] = ...) -> ndarray[tuple[Any, ...], dtype[Any]]
- colour/io/luts/lut.py:1380: note:     def [_ScalarT: generic[Any]] pad(array: _SupportsArray[dtype[_ScalarT]] | _NestedSequence[_SupportsArray[dtype[_ScalarT]]], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int], mode: _ModeFunc, **kwargs: Any) -> ndarray[tuple[Any, ...], dtype[_ScalarT]]
- colour/io/luts/lut.py:1380: note:     def pad(array: Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | complex | bytes | str | _NestedSequence[complex | bytes | str], pad_width: _SupportsArray[dtype[integer[Any]]] | _NestedSequence[_SupportsArray[dtype[integer[Any]]]] | int | _NestedSequence[int], mode: _ModeFunc, **kwargs: Any) -> ndarray[tuple[Any, ...], dtype[Any]]

steam.py (https://github.com/Gobot1234/steam.py)
+ steam/utils.py:883: error: Unused "type: ignore" comment  [unused-ignore]
- steam/http.py:100: error: Dict entry 0 has incompatible type "str": "str | None"; expected "str": "str"  [dict-item]
- steam/gateway.py:830: error: No overload variant of "wait_for" of "SteamWebSocket" matches argument types "int", "Callable[[UnifiedMsgT], bool]"  [call-overload]
+ steam/gateway.py:830: error: No overload variant of "wait_for" of "SteamWebSocket" matches argument types "int", "Callable[[UnifiedMsgT], bool] | Callable[[Any], Any]"  [call-overload]

pyodide (https://github.com/pyodide/pyodide)
- pyodide-build/pyodide_build/xbuildenv.py:309: error: List item 0 has incompatible type "list[str | None]"; expected "str | bytes | PathLike[str] | PathLike[bytes]"  [list-item]

prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/runner/storage.py:178: error: Argument 1 to "deepcopy" has incompatible type "Union[GitCredentials, Block, dict[str, Any]]"; expected "dict[str, Any]"  [arg-type]
+ src/prefect/runner/storage.py:183: error: TypedDict key must be a string literal; expected one of ("username", "access_token")  [literal-required]
+ src/prefect/runner/storage.py:185: error: TypedDict key must be a string literal; expected one of ("username", "access_token")  [literal-required]

dd-trace-py (https://github.com/DataDog/dd-trace-py)
+ ddtrace/appsec/_iast/_taint_tracking/aspects.py:704: error: Unused "type: ignore" comment  [unused-ignore]

cwltool (https://github.com/common-workflow-language/cwltool)
+ cwltool/command_line_tool.py: note: In function "job":
+ cwltool/command_line_tool.py:1077:22: error: Redundant cast to "MutationManager"  [redundant-cast]
+ cwltool/command_line_tool.py:1082:22: error: Redundant cast to "MutationManager"  [redundant-cast]
+ cwltool/executors.py:156: error: Unused "type: ignore" comment  [unused-ignore]

discord.py (https://github.com/Rapptz/discord.py)
+ discord/utils.py:491: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/utils.py:607: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/message.py:2571: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/message.py:2575: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/message.py:2579: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/client.py:2916: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/client.py:2937: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/ext/commands/converter.py:1032: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/ext/commands/converter.py:1036: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/ext/commands/converter.py:1051: error: Unused "type: ignore" comment  [unused-ignore]

spark (https://github.com/apache/spark)
+ python/pyspark/sql/connect/client/reattach.py:183: error: Unused "type: ignore" comment  [unused-ignore]
+ python/pyspark/sql/connect/client/reattach.py:183: error: No overload variant of "next" matches argument type "None"  [call-overload]
+ python/pyspark/sql/connect/client/reattach.py:183: note: Error code "call-overload" not covered by "type: ignore" comment
+ python/pyspark/sql/connect/client/reattach.py:183: note: Possible overload variants:
+ python/pyspark/sql/connect/client/reattach.py:183: note:     def [_T] next(SupportsNext[_T], /) -> _T
+ python/pyspark/sql/connect/client/reattach.py:183: note:     def [_T, _VT] next(SupportsNext[_T], _VT, /) -> _T | _VT

optuna (https://github.com/optuna/optuna)
+ optuna/visualization/_intermediate_values.py:95: error: Unused "type: ignore" comment  [unused-ignore]

core (https://github.com/home-assistant/core)
+ homeassistant/components/withings/sensor.py:767: error: Statement is unreachable  [unreachable]
+ homeassistant/components/withings/sensor.py:796: error: Statement is unreachable  [unreachable]
+ homeassistant/components/withings/sensor.py:823: error: Statement is unreachable  [unreachable]
+ homeassistant/components/withings/calendar.py:48: error: Statement is unreachable  [unreachable]

@randolf-scholz
Copy link
Contributor Author

TODO: fix is_var_redefined_in_outer_context to also consider attribute assignment.

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.

Irregular inference with ternary based on attribute. Literal list ternary behave unexpected No TypeVar variable inference in ternary operators

1 participant