From 3253c3372b6ea3ac977e0fa13cbbe7e92698e13d Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 1 Oct 2021 01:04:24 +0300 Subject: [PATCH 1/3] Checks `Instance` and `Literal` subtypes correctly, refs #11232 --- mypy/subtypes.py | 2 ++ test-data/unit/check-literal.test | 32 ++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 63cebc8aa483..52d03282494f 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -287,6 +287,8 @@ def visit_instance(self, left: Instance) -> bool: return True if isinstance(item, Instance): return is_named_instance(item, 'builtins.object') + if isinstance(right, LiteralType) and left.last_known_value is not None: + return self._is_subtype(left.last_known_value, right) if isinstance(right, CallableType): # Special case: Instance can be a subtype of Callable. call = find_member('__call__', left, left, is_operator=True) diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index e96d72c7358b..fb55e256b713 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -2687,11 +2687,8 @@ def force2(x: Tuple[Literal[1], Literal[2]]) -> None: pass reveal_type(a) # N: Revealed type is "Literal[1]?" reveal_type(b) # N: Revealed type is "Tuple[Literal[1]?, Literal[2]?]" -# TODO: This test seems somewhat broken and might need a rewrite (and a fix somewhere in mypy). -# See https://github.com/python/mypy/issues/7399#issuecomment-554188073 for more context. -force1(reveal_type(a)) # N: Revealed type is "Literal[1]" -force2(reveal_type(b)) # E: Argument 1 to "force2" has incompatible type "Tuple[int, int]"; expected "Tuple[Literal[1], Literal[2]]" \ - # N: Revealed type is "Tuple[Literal[1]?, Literal[2]?]" +force1(a) # ok +force2(b) # ok [builtins fixtures/tuple.pyi] [out] @@ -3304,3 +3301,28 @@ else: reveal_type(w) # E: Statement is unreachable [builtins fixtures/bool.pyi] + +[case testLiteralAndInstanceSubtyping] +# https://github.com/python/mypy/issues/7399 +# https://github.com/python/mypy/issues/11232 +from typing import Tuple, Union +from typing_extensions import Literal, Final + +x: bool + +def f() -> Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]: + if x: + return (True, 5) + else: + return (False, 'oops') + +reveal_type(f()) # N: Revealed type is "Union[Tuple[Literal[True], builtins.int], Tuple[Literal[False], builtins.str]]" + +def does_work() -> Tuple[Literal[1]]: + x: Final = (1,) + return x + +def also_works() -> Tuple[Literal[1]]: + x: Tuple[Literal[1]] = (1,) + return x +[builtins fixtures/bool.pyi] From dc9525fb1b51dd05fdda046baaead69cdb095b00 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 1 Oct 2021 01:12:34 +0300 Subject: [PATCH 2/3] Adds more tests --- test-data/unit/check-literal.test | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index fb55e256b713..9eb98425c0dc 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -3325,4 +3325,16 @@ def does_work() -> Tuple[Literal[1]]: def also_works() -> Tuple[Literal[1]]: x: Tuple[Literal[1]] = (1,) return x + +def incorrect_return1() -> Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]: + if x: + return (False, 5) # E: Incompatible return value type (got "Tuple[bool, int]", expected "Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]") + else: + return (True, 'oops') # E: Incompatible return value type (got "Tuple[bool, str]", expected "Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]") + +def incorrect_return2() -> Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]: + if x: + return (bool(), 5) # E: Incompatible return value type (got "Tuple[bool, int]", expected "Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]") + else: + return (bool(), 'oops') # E: Incompatible return value type (got "Tuple[bool, str]", expected "Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]") [builtins fixtures/bool.pyi] From 3b532e15fa1169af85140a6ff5be6eddaf552884 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 1 Oct 2021 10:33:05 +0300 Subject: [PATCH 3/3] Adds more tests --- test-data/unit/check-literal.test | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index 9eb98425c0dc..37ae12419151 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -3326,6 +3326,14 @@ def also_works() -> Tuple[Literal[1]]: x: Tuple[Literal[1]] = (1,) return x +def invalid_literal_value() -> Tuple[Literal[1]]: + x: Final = (2,) + return x # E: Incompatible return value type (got "Tuple[int]", expected "Tuple[Literal[1]]") + +def invalid_literal_type() -> Tuple[Literal[1]]: + x: Final = (True,) + return x # E: Incompatible return value type (got "Tuple[bool]", expected "Tuple[Literal[1]]") + def incorrect_return1() -> Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]: if x: return (False, 5) # E: Incompatible return value type (got "Tuple[bool, int]", expected "Union[Tuple[Literal[True], int], Tuple[Literal[False], str]]")