From a19f6ba3128590d1298e54df726adf8519e873e2 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 3 Oct 2017 19:24:13 +0200 Subject: [PATCH 1/3] Never put None in TupleType items --- mypy/checker.py | 5 ++++- mypy/checkexpr.py | 15 ++++++++++++++- test-data/unit/check-inference.test | 15 +++++++++++++++ test-data/unit/pythoneval.test | 15 +++++++++++++++ 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index c773a029cb8e..05a5e91552e0 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -1769,7 +1769,10 @@ def check_lvalue(self, lvalue: Lvalue) -> Tuple[Optional[Type], lvalue_type = self.expr_checker.analyze_ref_expr(lvalue, lvalue=True) self.store_type(lvalue, lvalue_type) elif isinstance(lvalue, TupleExpr) or isinstance(lvalue, ListExpr): - types = [self.check_lvalue(sub_expr)[0] for sub_expr in lvalue.items] + types = [self.check_lvalue(sub_expr)[0] or + # This type will be used as a context for further inference of rvalue, + # we put Uninhabited if there is no information available from lvalue. + UninhabitedType() for sub_expr in lvalue.items] lvalue_type = TupleType(types, self.named_type('builtins.tuple')) else: lvalue_type = self.expr_checker.accept(lvalue) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 8ca806bf3af0..6674de30efef 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -769,7 +769,7 @@ def infer_function_type_arguments_using_context( # Only substitute non-Uninhabited and non-erased types. new_args = [] # type: List[Optional[Type]] for arg in args: - if isinstance(arg, UninhabitedType) or has_erased_component(arg): + if has_uninhabited_component(arg) or has_erased_component(arg): new_args.append(None) else: new_args.append(arg) @@ -2768,6 +2768,19 @@ def visit_erased_type(self, t: ErasedType) -> bool: return True +def has_uninhabited_component(t: Optional[Type]) -> bool: + return t is not None and t.accept(HasUninhabitedComponentsQuery()) + + +class HasUninhabitedComponentsQuery(types.TypeQuery[bool]): + """Visitor for querying whether a type has an erased component.""" + def __init__(self) -> None: + super().__init__(any) + + def visit_uninhabited_type(self, t: UninhabitedType) -> bool: + return True + + def overload_arg_similarity(actual: Type, formal: Type) -> int: """Return if caller argument (actual) is compatible with overloaded signature arg (formal). diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 3549a27716a2..5aad7f8535b1 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1927,3 +1927,18 @@ x = None (x, x) = f('') reveal_type(x) # E: Revealed type is 'builtins.str' [out] + +[case testInferenceNestedTuplesFromGenericIterable] +from typing import Tuple, TypeVar + +T = TypeVar('T') + +def make_tuple(elem: T) -> Tuple[T]: + return (elem,) + +def main() -> None: + ((a, b),) = make_tuple((1, 2)) + reveal_type(a) # E: Revealed type is 'builtins.int' + reveal_type(b) # E: Revealed type is 'builtins.int' +[builtins fixtures/tuple.pyi] +[out] \ No newline at end of file diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 80bbaeeb0c94..5f817fac66d9 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -1402,3 +1402,18 @@ o: object = p it2: Iterable[int] = p [out] _testCanConvertTypedDictToAnySuperclassOfMapping.py:11: error: Incompatible types in assignment (expression has type "Point", variable has type "Iterable[int]") + +[case testAsyncioGatherPreciseType] +import asyncio +from typing import Tuple + +async def get_location(arg: str) -> Tuple[str, str]: + return arg, arg + +async def main() -> None: + ((a_x, a_y),) = await asyncio.gather(get_location('start')) + reveal_type(a_x) + reveal_type(a_y) +[out] +_testAsyncioGatherPreciseType.py:9: error: Revealed type is 'builtins.str' +_testAsyncioGatherPreciseType.py:10: error: Revealed type is 'builtins.str' From 65a29a327be180f2bc1ca4c9e6907dedfab2221c Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 3 Oct 2017 20:25:47 +0200 Subject: [PATCH 2/3] Fix docstring --- mypy/checkexpr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 6674de30efef..54d5f19d164e 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -2773,7 +2773,7 @@ def has_uninhabited_component(t: Optional[Type]) -> bool: class HasUninhabitedComponentsQuery(types.TypeQuery[bool]): - """Visitor for querying whether a type has an erased component.""" + """Visitor for querying whether a type has an UninhabitedType component.""" def __init__(self) -> None: super().__init__(any) From c6f73df41df8d114f43ba67c7c007c654df2b288 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 3 Oct 2017 20:27:01 +0200 Subject: [PATCH 3/3] Add missing newline --- test-data/unit/check-inference.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 5aad7f8535b1..18814539db6c 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1941,4 +1941,4 @@ def main() -> None: reveal_type(a) # E: Revealed type is 'builtins.int' reveal_type(b) # E: Revealed type is 'builtins.int' [builtins fixtures/tuple.pyi] -[out] \ No newline at end of file +[out]