Skip to content

Commit

Permalink
Fix crash when inferring multiple assignment with overloaded function (
Browse files Browse the repository at this point in the history
…#10689)

When using lvalue context to re-infer call to an overloaded function,
the inferred tuple type can switch to Any. Defensively accept this. It
probably means that an Any component in argument types causes ambiguity.

Fixes #10653.
  • Loading branch information
JukkaL committed Jun 22, 2021
1 parent 96366d1 commit 46ce325
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 2 deletions.
9 changes: 7 additions & 2 deletions mypy/checker.py
Expand Up @@ -2695,8 +2695,13 @@ def check_multi_assignment_from_tuple(self, lvalues: List[Lvalue], rvalue: Expre
reinferred_rvalue_type, context,
infer_lvalue_type)
return
if isinstance(reinferred_rvalue_type, AnyType) and self.current_node_deferred:
# Doing more inference in deferred nodes can be hard, so give up for now.
if isinstance(reinferred_rvalue_type, AnyType):
# We can get Any if the current node is
# deferred. Doing more inference in deferred nodes
# is hard, so give up for now. We can also get
# here if reinferring types above changes the
# inferred return type for an overloaded function
# to be ambiguous.
return
assert isinstance(reinferred_rvalue_type, TupleType)
rvalue_type = reinferred_rvalue_type
Expand Down
41 changes: 41 additions & 0 deletions test-data/unit/check-async-await.test
Expand Up @@ -758,3 +758,44 @@ class Foo(Generic[T]):

[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

[case testAwaitOverloadSpecialCase]
from typing import Any, Awaitable, Iterable, overload, Tuple, List, TypeVar, Generic

T = TypeVar("T")
FT = TypeVar("FT", bound='Future[Any]')

class Future(Awaitable[T], Iterable[T]):
pass

class Task(Future[T]):
pass

@overload
def wait(fs: Iterable[FT]) -> Future[Tuple[List[FT], List[FT]]]: ... \
# E: Overloaded function signatures 1 and 2 overlap with incompatible return types
@overload
def wait(fs: Iterable[Awaitable[T]]) -> Future[Tuple[List[Task[T]], List[Task[T]]]]: ...
def wait(fs: Any) -> Any:
pass

async def imprecise1(futures: Iterable[Task[Any]]) -> None:
done: Any
pending: Any
done, pending = await wait(futures)
reveal_type(done) # N: Revealed type is "Any"

async def imprecise2(futures: Iterable[Awaitable[Any]]) -> None:
done, pending = await wait(futures)
reveal_type(done) # N: Revealed type is "builtins.list[__main__.Task[Any]]"

async def precise1(futures: Iterable[Future[int]]) -> None:
done, pending = await wait(futures)
reveal_type(done) # N: Revealed type is "builtins.list[__main__.Future[builtins.int]]"

async def precise2(futures: Iterable[Awaitable[int]]) -> None:
done, pending = await wait(futures)
reveal_type(done) # N: Revealed type is "builtins.list[__main__.Task[builtins.int]]"

[builtins fixtures/async_await.pyi]
[typing fixtures/typing-async.pyi]

0 comments on commit 46ce325

Please sign in to comment.