Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2069,8 +2069,12 @@ def infer_function_type_arguments_using_context(
# in this case external context is almost everything we have.
if not is_generic_instance(ctx) and not is_literal_type_like(ctx):
return callable.copy_modified()

# GH#19304
# needs is_supertype=True since the purpose is to allow sound upcasting
# if the context requires it, such as e.g. `x: list[object] = [x for x in (1,2,3)]`
args = infer_type_arguments(
callable.variables, ret_type, erased_ctx, skip_unsatisfied=True
callable.variables, ret_type, erased_ctx, is_supertype=True, skip_unsatisfied=True
)
# Only substitute non-Uninhabited and non-erased types.
new_args: list[Type | None] = []
Expand Down
22 changes: 18 additions & 4 deletions test-data/unit/check-expressions.test
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,24 @@ main:5: error: Unsupported operand types for ^ ("A" and "A")
main:6: error: Unsupported operand types for << ("A" and "B")
main:7: error: Unsupported operand types for >> ("A" and "A")

[case testBinaryOperatorContext]
from typing import TypeVar, Generic, Iterable, Iterator, Union

T = TypeVar("T")
S = TypeVar("S")

class Vec(Generic[T]):
def __init__(self, iterable: Iterable[T], /) -> None: ...
def __iter__(self) -> Iterator[T]: yield from []
def __add__(self, value: "Vec[S]", /) -> "Vec[Union[S, T]]": return Vec([])

def fmt(arg: Iterable[Union[int, str]]) -> None: ...

l1: Vec[int] = Vec([1])
l2: Vec[int] = Vec([1])
fmt(l1 + l2)
[builtins fixtures/list.pyi]

[case testBooleanAndOr]
a: A
b: bool
Expand Down Expand Up @@ -460,10 +478,6 @@ class A:
def __contains__(self, x: 'A') -> str: pass
[builtins fixtures/bool.pyi]

[case testInWithInvalidArgs]
a = 1 in ([1] + ['x']) # E: List item 0 has incompatible type "str"; expected "int"
[builtins fixtures/list.pyi]

[case testEq]
a: A
b: bool
Expand Down
5 changes: 3 additions & 2 deletions test-data/unit/fixtures/list.pyi
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Builtins stub used in list-related test cases.

from typing import TypeVar, Generic, Iterable, Iterator, Sequence, overload
from typing import TypeVar, Generic, Iterable, Iterator, Sequence, overload, Union

T = TypeVar('T')
_S = TypeVar("_S")

class object:
def __init__(self) -> None: pass
Expand All @@ -19,7 +20,7 @@ class list(Sequence[T]):
def __iter__(self) -> Iterator[T]: pass
def __len__(self) -> int: pass
def __contains__(self, item: object) -> bool: pass
def __add__(self, x: list[T]) -> list[T]: pass
def __add__(self, x: list[_S]) -> list[Union[_S, T]]: pass
def __mul__(self, x: int) -> list[T]: pass
def __getitem__(self, x: int) -> T: pass
def __setitem__(self, x: int, v: T) -> None: pass
Expand Down
Loading