Skip to content

Commit 3e40ab7

Browse files
added testContextFreeConcatInvariantType and testInContextConcatInvariantType
1 parent d7a5d08 commit 3e40ab7

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

mypy/checkexpr.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
from mypy.subtypes import (
122122
find_member,
123123
is_equivalent,
124+
is_proper_subtype,
124125
is_same_type,
125126
is_subtype,
126127
non_method_protocol_members,
@@ -2167,7 +2168,10 @@ def infer_function_type_arguments(
21672168
# joint constraints failed to produce a complete solution
21682169
None in joint_solution[0]
21692170
# If the outer solution is more concrete than the joint solution, prefer the outer solution.
2170-
or is_subtype(outer_ret_type, joint_ret_type)
2171+
or (
2172+
is_subtype(outer_ret_type, joint_ret_type)
2173+
and not is_proper_subtype(joint_ret_type, outer_ret_type)
2174+
)
21712175
):
21722176
use_joint = False
21732177
else:

test-data/unit/check-generics.test

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3657,3 +3657,43 @@ t2.foo = [B()]
36573657
t2.foo = [C()]
36583658
t2.foo = [1] # E: Value of type variable "T" of "foo" of "Test" cannot be "int"
36593659
[builtins fixtures/property.pyi]
3660+
3661+
[case testContextFreeConcatInvariantType]
3662+
from typing import Iterable, Iterator, TypeVar, Generic, Union
3663+
3664+
T = TypeVar("T")
3665+
S = TypeVar("S")
3666+
3667+
class Vec(Generic[T]):
3668+
def getitem(self, i: int) -> T: ... # ensure invariance of T
3669+
def setitem(self, i: int, v: T) -> None: ... # ensure invariance of T
3670+
def __iter__(self) -> Iterator[T]: ...
3671+
def __add__(self, other: "Vec[S]") -> "Vec[Union[T, S]]": ...
3672+
3673+
mix: Vec[Union[int, str]]
3674+
strings: Vec[str]
3675+
mix = mix + strings
3676+
mix = strings + mix
3677+
reveal_type(mix + strings) # N: Revealed type is "__main__.Vec[Union[builtins.int, builtins.str]]"
3678+
reveal_type(strings + mix) # N: Revealed type is "__main__.Vec[Union[builtins.str, builtins.int]]"
3679+
[builtins fixtures/list.pyi]
3680+
3681+
3682+
[case testInContextConcatInvariantType]
3683+
# https://github.com/python/mypy/issues/3933#issuecomment-2272804302
3684+
from typing import Iterable, Iterator, TypeVar, Generic, Union
3685+
3686+
T = TypeVar("T")
3687+
S = TypeVar("S")
3688+
3689+
class Vec(Generic[T]):
3690+
def getitem(self, i: int) -> T: ... # ensure invariance of T
3691+
def setitem(self, i: int, v: T) -> None: ... # ensure invariance of T
3692+
def __iter__(self) -> Iterator[T]: ...
3693+
def __add__(self, other: "Vec[S]") -> "Vec[Union[T, S]]": ...
3694+
3695+
def identity_on_iterable(arg: Iterable[T]) -> Iterable[T]: return arg
3696+
x: Vec[str]
3697+
y: Vec[None]
3698+
reveal_type( identity_on_iterable(y + x) ) # N: Revealed type is "typing.Iterable[Union[None, builtins.str]]"
3699+
reveal_type( identity_on_iterable(x + y) ) # N: Revealed type is "typing.Iterable[Union[builtins.str, None]]"

0 commit comments

Comments
 (0)