Skip to content

Commit d23fc47

Browse files
ilevkivskyigvanrossum
authored andcommitted
Never put None in TupleType items (#4051)
Fixes #4046 The root cause for the crash is that None was put in TupleType items if the corresponding lvalue is a definition. Then the crash happens when this TupleType is used as a context for rvalue type inference. The solution is to put UninhabitedType in such cases, so that inference will fall back on using argument types instead.
1 parent f6a74b5 commit d23fc47

File tree

4 files changed

+48
-2
lines changed

4 files changed

+48
-2
lines changed

mypy/checker.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -1769,7 +1769,10 @@ def check_lvalue(self, lvalue: Lvalue) -> Tuple[Optional[Type],
17691769
lvalue_type = self.expr_checker.analyze_ref_expr(lvalue, lvalue=True)
17701770
self.store_type(lvalue, lvalue_type)
17711771
elif isinstance(lvalue, TupleExpr) or isinstance(lvalue, ListExpr):
1772-
types = [self.check_lvalue(sub_expr)[0] for sub_expr in lvalue.items]
1772+
types = [self.check_lvalue(sub_expr)[0] or
1773+
# This type will be used as a context for further inference of rvalue,
1774+
# we put Uninhabited if there is no information available from lvalue.
1775+
UninhabitedType() for sub_expr in lvalue.items]
17731776
lvalue_type = TupleType(types, self.named_type('builtins.tuple'))
17741777
else:
17751778
lvalue_type = self.expr_checker.accept(lvalue)

mypy/checkexpr.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ def infer_function_type_arguments_using_context(
769769
# Only substitute non-Uninhabited and non-erased types.
770770
new_args = [] # type: List[Optional[Type]]
771771
for arg in args:
772-
if isinstance(arg, UninhabitedType) or has_erased_component(arg):
772+
if has_uninhabited_component(arg) or has_erased_component(arg):
773773
new_args.append(None)
774774
else:
775775
new_args.append(arg)
@@ -2768,6 +2768,19 @@ def visit_erased_type(self, t: ErasedType) -> bool:
27682768
return True
27692769

27702770

2771+
def has_uninhabited_component(t: Optional[Type]) -> bool:
2772+
return t is not None and t.accept(HasUninhabitedComponentsQuery())
2773+
2774+
2775+
class HasUninhabitedComponentsQuery(types.TypeQuery[bool]):
2776+
"""Visitor for querying whether a type has an UninhabitedType component."""
2777+
def __init__(self) -> None:
2778+
super().__init__(any)
2779+
2780+
def visit_uninhabited_type(self, t: UninhabitedType) -> bool:
2781+
return True
2782+
2783+
27712784
def overload_arg_similarity(actual: Type, formal: Type) -> int:
27722785
"""Return if caller argument (actual) is compatible with overloaded signature arg (formal).
27732786

test-data/unit/check-inference.test

+15
Original file line numberDiff line numberDiff line change
@@ -1927,3 +1927,18 @@ x = None
19271927
(x, x) = f('')
19281928
reveal_type(x) # E: Revealed type is 'builtins.str'
19291929
[out]
1930+
1931+
[case testInferenceNestedTuplesFromGenericIterable]
1932+
from typing import Tuple, TypeVar
1933+
1934+
T = TypeVar('T')
1935+
1936+
def make_tuple(elem: T) -> Tuple[T]:
1937+
return (elem,)
1938+
1939+
def main() -> None:
1940+
((a, b),) = make_tuple((1, 2))
1941+
reveal_type(a) # E: Revealed type is 'builtins.int'
1942+
reveal_type(b) # E: Revealed type is 'builtins.int'
1943+
[builtins fixtures/tuple.pyi]
1944+
[out]

test-data/unit/pythoneval.test

+15
Original file line numberDiff line numberDiff line change
@@ -1402,3 +1402,18 @@ o: object = p
14021402
it2: Iterable[int] = p
14031403
[out]
14041404
_testCanConvertTypedDictToAnySuperclassOfMapping.py:11: error: Incompatible types in assignment (expression has type "Point", variable has type "Iterable[int]")
1405+
1406+
[case testAsyncioGatherPreciseType]
1407+
import asyncio
1408+
from typing import Tuple
1409+
1410+
async def get_location(arg: str) -> Tuple[str, str]:
1411+
return arg, arg
1412+
1413+
async def main() -> None:
1414+
((a_x, a_y),) = await asyncio.gather(get_location('start'))
1415+
reveal_type(a_x)
1416+
reveal_type(a_y)
1417+
[out]
1418+
_testAsyncioGatherPreciseType.py:9: error: Revealed type is 'builtins.str'
1419+
_testAsyncioGatherPreciseType.py:10: error: Revealed type is 'builtins.str'

0 commit comments

Comments
 (0)