Skip to content

Commit ef409d2

Browse files
change join behavior between literal and last_known_value
1 parent ba9490a commit ef409d2

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

@@ -642,8 +642,8 @@ def visit_literal_type(self, t: LiteralType) -> ProperType:
642642
return mypy.typeops.make_simplified_union([self.s, t])
643643
return join_types(self.s.fallback, t.fallback)
644644
elif isinstance(self.s, Instance) and self.s.last_known_value == t:
645-
# E.g. Literal["x"], Literal["x"]? -> Literal["x"]
646-
return t
645+
# E.g. Literal["x"], Literal["x"]? -> Literal["x"]?
646+
return self.s
647647
else:
648648
# E.g. Literal["x"], Literal["y"]? -> str
649649
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
@@ -1056,11 +1056,11 @@ def test_mixed_literal_types(self) -> None:
10561056

10571057
# other operand is the same literal
10581058
# "x" , "x" -> "x"
1059-
# "x" , "x"? -> "x"
1060-
# "x"?, "x" -> "x"
1059+
# "x" , "x"? -> "x"?
1060+
# "x"?, "x" -> "x"?
10611061
# "x"?, "x"? -> "x"?
10621062
self.assert_join(str1, str1, str1)
1063-
self.assert_join(str1, str1_inst, str1)
1063+
self.assert_join(str1, str1_inst, str1_inst)
10641064
self.assert_join(str1_inst, str1_inst, str1_inst)
10651065

10661066
# 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
@@ -3092,18 +3092,29 @@ z: Type[Literal[1, 2]] # E: Type[...] can't contain "Union[Literal[...], Litera
30923092
[case testJoinLiteralAndInstance]
30933093
from typing import Generic, TypeVar, Literal
30943094

3095-
T = TypeVar("T")
3095+
T_co = TypeVar("T_co", covariant=True)
3096+
T = TypeVar("T", covariant=False, contravariant=False)
3097+
S = TypeVar("S", covariant=False, contravariant=False)
30963098

3097-
class A(Generic[T]): ...
3099+
class A_inv(Generic[T]): ...
3100+
class A_co(Generic[T_co]): ...
30983101

3099-
def f(a: A[T], t: T) -> T: ...
3100-
def g(a: T, t: A[T]) -> T: ...
3102+
def check_inv(obj: A_inv[Literal[1]]) -> None:
3103+
def f(a: A_inv[S], t: S) -> S: ...
3104+
def g(a: S, t: A_inv[S]) -> S: ...
31013105

3102-
def check(obj: A[Literal[1]]) -> None:
31033106
reveal_type(f(obj, 1)) # N: Revealed type is "Literal[1]"
3104-
reveal_type(f(obj, '')) # E: Cannot infer value of type parameter "T" of "f" \
3105-
# N: Revealed type is "Any"
3107+
reveal_type(f(obj, '')) # E: Cannot infer value of type parameter "S" of "f" \
3108+
# N: Revealed type is "Any"
31063109
reveal_type(g(1, obj)) # N: Revealed type is "Literal[1]"
3107-
reveal_type(g('', obj)) # E: Cannot infer value of type parameter "T" of "g" \
3108-
# N: Revealed type is "Any"
3109-
[builtins fixtures/tuple.pyi]
3110+
reveal_type(g('', obj)) # E: Cannot infer value of type parameter "S" of "g" \
3111+
# N: Revealed type is "Any"
3112+
3113+
def check_co(obj: A_co[Literal[1]]) -> None:
3114+
def f(a: A_co[S], t: S) -> S: ...
3115+
def g(a: S, t: A_co[S]) -> S: ...
3116+
3117+
reveal_type(f(obj, 1)) # N: Revealed type is "builtins.int"
3118+
reveal_type(f(obj, '')) # N: Revealed type is "builtins.object"
3119+
reveal_type(g(1, obj)) # N: Revealed type is "builtins.int"
3120+
reveal_type(g('', obj)) # N: Revealed type is "builtins.object"

0 commit comments

Comments
 (0)