diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 08d7345452fb..22f4b05b7ad4 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -5805,6 +5805,12 @@ def visit_conditional_expr(self, e: ConditionalExpr, allow_none_return: bool = F context=if_type_fallback, allow_none_return=allow_none_return, ) + + # In most cases using if_type as a context for right branch gives better inferred types. + # This is however not the case for literal types, so use the full context instead. + if is_literal_type_like(full_context_else_type) and not is_literal_type_like(else_type): + else_type = full_context_else_type + res: Type = make_simplified_union([if_type, else_type]) if has_uninhabited_component(res) and not isinstance( get_proper_type(self.type_context[-1]), UnionType diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index 6d76ce176aaf..2f94b5df0f83 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -2960,3 +2960,27 @@ class C(B[Literal["word"]]): reveal_type(C().collection) # N: Revealed type is "builtins.list[Literal['word']]" reveal_type(C().word) # N: Revealed type is "Literal['word']" [builtins fixtures/tuple.pyi] + +[case testLiteralTernaryUnionNarrowing] +from typing_extensions import Literal +from typing import Optional + +SEP = Literal["a", "b"] + +class Base: + def feed_data( + self, + sep: SEP, + ) -> int: + return 0 + +class C(Base): + def feed_data( + self, + sep: Optional[SEP] = None, + ) -> int: + if sep is None: + sep = "a" if int() else "b" + reveal_type(sep) # N: Revealed type is "Union[Literal['a'], Literal['b']]" + return super().feed_data(sep) +[builtins fixtures/tuple.pyi]