Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions mypy/typeops.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ def erase_to_bound(t: Type) -> Type:
def callable_corresponding_argument(
typ: NormalizedCallableType | Parameters, model: FormalArgument
) -> FormalArgument | None:
"""Return the argument a function that corresponds to `model`"""
"""Return the argument of a function that corresponds to `model`"""

by_name = typ.argument_by_name(model.name)
by_pos = typ.argument_by_position(model.pos)
Expand All @@ -522,17 +522,23 @@ def callable_corresponding_argument(
# taking both *args and **args, or a pair of functions like so:

# def right(a: int = ...) -> None: ...
# def left(__a: int = ..., *, a: int = ...) -> None: ...
# def left(x: int = ..., /, *, a: int = ...) -> None: ...
from mypy.meet import meet_types

if (
not (by_name.required or by_pos.required)
and by_pos.name is None
and by_name.pos is None
# This is not principled, but prevents a crash. It's weird to have a FormalArgument
# that has an UnpackType.
and not isinstance(by_name.typ, UnpackType)
and not isinstance(by_pos.typ, UnpackType)
):
return FormalArgument(
by_name.name, by_pos.pos, meet_types(by_name.typ, by_pos.typ), False
)
return by_name

return by_name if by_name is not None else by_pos


Expand Down
13 changes: 13 additions & 0 deletions test-data/unit/check-overloading.test
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,19 @@ def foo(*args: int | str, **kw: int | Foo) -> None:
pass
[builtins fixtures/tuple.pyi]


[case testTypeCheckOverloadImplOverlapVarArgsAndKwargsNever]
from __future__ import annotations
from typing import overload

@overload # E: Single overload definition, multiple required
def foo(x: int) -> None: ...

def foo(*args: int, **kw: str) -> None: # E: Overloaded function implementation does not accept all possible arguments of signature 1
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really related to this PR, just adds #19619 (comment)

pass
[builtins fixtures/tuple.pyi]


[case testTypeCheckOverloadWithImplTooSpecificRetType]
from typing import overload, Any

Expand Down
23 changes: 23 additions & 0 deletions test-data/unit/check-typevar-tuple.test
Original file line number Diff line number Diff line change
Expand Up @@ -2716,3 +2716,26 @@ class MyTuple(tuple[Unpack[Union[int, str]]], Generic[Unpack[Ts]]): # E: "Union
x: MyTuple[int, str]
reveal_type(x[0]) # N: Revealed type is "Any"
[builtins fixtures/tuple.pyi]

[case testHigherOrderFunctionUnpackTypeVarTupleViaParamSpec]
from typing import Callable, ParamSpec, TypeVar, TypeVarTuple, Unpack

P = ParamSpec("P")
T = TypeVar("T")
Ts = TypeVarTuple("Ts")

def call(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T:
return func(*args, **kwargs)


def run(func: Callable[[Unpack[Ts]], T], *args: Unpack[Ts], some_kwarg: str = "asdf") -> T:
raise


def foo() -> str:
return "hello"


# this is a false positive, but it no longer crashes
call(run, foo, some_kwarg="a") # E: Argument 1 to "call" has incompatible type "def [Ts`-1, T] run(func: def (*Unpack[Ts]) -> T, *args: Unpack[Ts], some_kwarg: str = ...) -> T"; expected "Callable[[Callable[[], str], str], str]"
[builtins fixtures/tuple.pyi]
Loading