Skip to content

Conversation

@randolf-scholz
Copy link
Contributor

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

Option ① from #19561 (comment) which does not allow MemberExpr elements to the nested binder, hence ternaries like f(x.attr) if x.attr else g(x.attr) will not consider the narrowed type of x.attr

Option ②: #19562

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 1) Aug 1, 2025
@github-actions

This comment has been minimized.

1 similar comment
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@randolf-scholz
Copy link
Contributor Author

Repro of pyodide-build:

uv_bin: str | None

install_prefix = (
    [uv_bin, "pip", "install"]
    if bool()
    else ["/bin/python", "-m", "pip", "install", "--no-user"]
)
reveal_type(install_prefix)     # master: list[str | None], PR: list[str | None] | list[str]
reveal_type([*install_prefix])  # master: list[str | None], PR: list[Any]

It seems like this is due to some overly aggressive join operation, [*install_prefix] should get inferred as list[str | None] regardless whether install_prefix is just list[str | None] or list[str | None] | list[str].

@hauntsaninja
Copy link
Collaborator

Joins don't typically result in Any's. Looks like this was some other missing case: #19650

@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:

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

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]

colour (https://github.com/colour-science/colour)
+ colour/io/luts/lut.py:1418: 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:1432: 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:1432: note: Possible overload variants:
- colour/io/luts/lut.py:1432: 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:1432: 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:1432: 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:1432: 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]]

mypy (https://github.com/python/mypy)
+ mypyc/irbuild/statement.py:602: error: Argument 1 to "accept" of "IRBuilder" has incompatible type "Optional[Block]"; expected "Statement"  [arg-type]

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]

discord.py (https://github.com/Rapptz/discord.py)
+ discord/utils.py:485: error: Unused "type: ignore" comment  [unused-ignore]
+ discord/utils.py:599: error: Unused "type: ignore" comment  [unused-ignore]

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

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]

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

Labels

None yet

Projects

None yet

2 participants