Skip to content

Commit 03726cf

Browse files
change join behavior between literal and last_known_value
1 parent 4a69e5f commit 03726cf

File tree

4 files changed

+29
-17
lines changed

4 files changed

+29
-17
lines changed

mypy/join.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ def visit_union_type(self, t: UnionType) -> ProperType:
277277
elif isinstance(self.s, LiteralType):
278278
# E.g. join("x", "y" | "z") -> "x" | "y" | "z"
279279
# and join(1, "y" | "z") -> object
280-
return mypy.typeops.make_simplified_union(join_types(self.s, x) for x in t.items)
280+
return mypy.typeops.make_simplified_union([join_types(self.s, x) for x in t.items])
281281
else:
282282
return mypy.typeops.make_simplified_union([self.s, t])
283283

@@ -637,8 +637,8 @@ def visit_literal_type(self, t: LiteralType) -> ProperType:
637637
return mypy.typeops.make_simplified_union([self.s, t])
638638
return join_types(self.s.fallback, t.fallback)
639639
elif isinstance(self.s, Instance) and self.s.last_known_value == t:
640-
# E.g. Literal["x"], Literal["x"]? -> Literal["x"]
641-
return t
640+
# E.g. Literal["x"], Literal["x"]? -> Literal["x"]?
641+
return self.s
642642
else:
643643
# E.g. Literal["x"], Literal["y"]? -> str
644644
return join_types(self.s, t.fallback)

mypy/solve.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,8 @@ def solve_one(lowers: Iterable[Type], uppers: Iterable[Type]) -> Type | None:
319319
elif top is None:
320320
candidate = bottom
321321
elif is_subtype(bottom, top):
322-
candidate = bottom
322+
# Need to meet in case like Literal["x"]? <: T <: Literal["x"]
323+
candidate = meet_types(bottom, top)
323324
else:
324325
candidate = None
325326
return candidate

mypy/test/testtypes.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,11 +1068,11 @@ def test_mixed_literal_types(self) -> None:
10681068

10691069
# other operand is the same literal
10701070
# "x" , "x" -> "x"
1071-
# "x" , "x"? -> "x"
1072-
# "x"?, "x" -> "x"
1071+
# "x" , "x"? -> "x"?
1072+
# "x"?, "x" -> "x"?
10731073
# "x"?, "x"? -> "x"?
10741074
self.assert_join(str1, str1, str1)
1075-
self.assert_join(str1, str1_inst, str1)
1075+
self.assert_join(str1, str1_inst, str1_inst)
10761076
self.assert_join(str1_inst, str1_inst, str1_inst)
10771077

10781078
# other operand is a different literal

test-data/unit/check-literal.test

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2980,18 +2980,29 @@ z: Type[Literal[1, 2]] # E: Type[...] can't contain "Union[Literal[...], Litera
29802980
[case testJoinLiteralAndInstance]
29812981
from typing import Generic, TypeVar, Literal
29822982

2983-
T = TypeVar("T")
2983+
T_co = TypeVar("T_co", covariant=True)
2984+
T = TypeVar("T", covariant=False, contravariant=False)
2985+
S = TypeVar("S", covariant=False, contravariant=False)
29842986

2985-
class A(Generic[T]): ...
2987+
class A_inv(Generic[T]): ...
2988+
class A_co(Generic[T_co]): ...
29862989

2987-
def f(a: A[T], t: T) -> T: ...
2988-
def g(a: T, t: A[T]) -> T: ...
2990+
def check_inv(obj: A_inv[Literal[1]]) -> None:
2991+
def f(a: A_inv[S], t: S) -> S: ...
2992+
def g(a: S, t: A_inv[S]) -> S: ...
29892993

2990-
def check(obj: A[Literal[1]]) -> None:
29912994
reveal_type(f(obj, 1)) # N: Revealed type is "Literal[1]"
2992-
reveal_type(f(obj, '')) # E: Cannot infer value of type parameter "T" of "f" \
2993-
# N: Revealed type is "Any"
2995+
reveal_type(f(obj, '')) # E: Cannot infer value of type parameter "S" of "f" \
2996+
# N: Revealed type is "Any"
29942997
reveal_type(g(1, obj)) # N: Revealed type is "Literal[1]"
2995-
reveal_type(g('', obj)) # E: Cannot infer value of type parameter "T" of "g" \
2996-
# N: Revealed type is "Any"
2997-
[builtins fixtures/tuple.pyi]
2998+
reveal_type(g('', obj)) # E: Cannot infer value of type parameter "S" of "g" \
2999+
# N: Revealed type is "Any"
3000+
3001+
def check_co(obj: A_co[Literal[1]]) -> None:
3002+
def f(a: A_co[S], t: S) -> S: ...
3003+
def g(a: S, t: A_co[S]) -> S: ...
3004+
3005+
reveal_type(f(obj, 1)) # N: Revealed type is "builtins.int"
3006+
reveal_type(f(obj, '')) # N: Revealed type is "builtins.object"
3007+
reveal_type(g(1, obj)) # N: Revealed type is "builtins.int"
3008+
reveal_type(g('', obj)) # N: Revealed type is "builtins.object"

0 commit comments

Comments
 (0)