Skip to content

Commit 08cdbb4

Browse files
initial commit
1 parent 5e9d657 commit 08cdbb4

File tree

3 files changed

+27
-4
lines changed

3 files changed

+27
-4
lines changed

mypy/checkexpr.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2069,8 +2069,12 @@ def infer_function_type_arguments_using_context(
20692069
# in this case external context is almost everything we have.
20702070
if not is_generic_instance(ctx) and not is_literal_type_like(ctx):
20712071
return callable.copy_modified()
2072+
2073+
# GH#19304
2074+
# needs is_supertype=True since the purpose is to allow sound upcasting
2075+
# if the context requires it, such as e.g. `x: list[object] = [x for x in (1,2,3)]`
20722076
args = infer_type_arguments(
2073-
callable.variables, ret_type, erased_ctx, skip_unsatisfied=True
2077+
callable.variables, ret_type, erased_ctx, is_supertype=True, skip_unsatisfied=True
20742078
)
20752079
# Only substitute non-Uninhabited and non-erased types.
20762080
new_args: list[Type | None] = []

test-data/unit/check-expressions.test

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,24 @@ main:5: error: Unsupported operand types for ^ ("A" and "A")
308308
main:6: error: Unsupported operand types for << ("A" and "B")
309309
main:7: error: Unsupported operand types for >> ("A" and "A")
310310

311+
[case testBinaryOperatorContext]
312+
from typing import TypeVar, Generic, Iterable, Iterator, Union
313+
314+
T = TypeVar("T")
315+
S = TypeVar("S")
316+
317+
class Vec(Generic[T]):
318+
def __init__(self, iterable: Iterable[T], /) -> None: ...
319+
def __iter__(self) -> Iterator[T]: yield from []
320+
def __add__(self, value: "Vec[S]", /) -> "Vec[Union[S, T]]": return Vec([])
321+
322+
def fmt(arg: Iterable[Union[int, str]]) -> None: ...
323+
324+
l1: Vec[int] = Vec([1])
325+
l2: Vec[int] = Vec([1])
326+
fmt(l1 + l2)
327+
[builtins fixtures/list.pyi]
328+
311329
[case testBooleanAndOr]
312330
a: A
313331
b: bool
@@ -461,7 +479,7 @@ class A:
461479
[builtins fixtures/bool.pyi]
462480

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

467485
[case testEq]

test-data/unit/fixtures/list.pyi

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# Builtins stub used in list-related test cases.
22

3-
from typing import TypeVar, Generic, Iterable, Iterator, Sequence, overload
3+
from typing import TypeVar, Generic, Iterable, Iterator, Sequence, overload, Union
44

55
T = TypeVar('T')
6+
_S = TypeVar("_S")
67

78
class object:
89
def __init__(self) -> None: pass
@@ -19,7 +20,7 @@ class list(Sequence[T]):
1920
def __iter__(self) -> Iterator[T]: pass
2021
def __len__(self) -> int: pass
2122
def __contains__(self, item: object) -> bool: pass
22-
def __add__(self, x: list[T]) -> list[T]: pass
23+
def __add__(self, x: list[_S]) -> list[Union[_S, T]]: pass
2324
def __mul__(self, x: int) -> list[T]: pass
2425
def __getitem__(self, x: int) -> T: pass
2526
def __setitem__(self, x: int, v: T) -> None: pass

0 commit comments

Comments
 (0)