Skip to content

Commit 1b9a5ec

Browse files
committed
Improve error message for callables with invalid Concatenate, refs #13518
1 parent da56c97 commit 1b9a5ec

File tree

2 files changed

+26
-3
lines changed

2 files changed

+26
-3
lines changed

mypy/typeanal.py

+15-3
Original file line numberDiff line numberDiff line change
@@ -1026,8 +1026,10 @@ def analyze_callable_args_for_paramspec(
10261026
def analyze_callable_args_for_concatenate(
10271027
self, callable_args: Type, ret_type: Type, fallback: Instance
10281028
) -> CallableType | None:
1029-
"""Construct a 'Callable[C, RET]', where C is Concatenate[..., P], returning None if we
1030-
cannot.
1029+
"""Construct a 'Callable[C, RET]', where C is Concatenate[..., P]
1030+
1031+
Return `None` if we cannot.
1032+
Return `AnyType` if we only can do it partially.
10311033
"""
10321034
if not isinstance(callable_args, UnboundType):
10331035
return None
@@ -1039,7 +1041,17 @@ def analyze_callable_args_for_concatenate(
10391041
if sym.node.fullname not in ("typing_extensions.Concatenate", "typing.Concatenate"):
10401042
return None
10411043

1042-
tvar_def = self.anal_type(callable_args, allow_param_spec=True)
1044+
tvar_def = get_proper_type(self.anal_type(callable_args, allow_param_spec=True))
1045+
if isinstance(tvar_def, AnyType) and tvar_def.type_of_any == TypeOfAny.from_error:
1046+
# Some error happened, we won't be able to construct a proper type anyway.
1047+
# So, instead return a callable that accepts anything.
1048+
return CallableType(
1049+
arg_names=[None] * 2,
1050+
arg_types=[AnyType(TypeOfAny.from_error)] * 2,
1051+
arg_kinds=[ARG_STAR, ARG_STAR2],
1052+
ret_type=AnyType(TypeOfAny.from_error),
1053+
fallback=fallback,
1054+
)
10431055
if not isinstance(tvar_def, ParamSpecType):
10441056
return None
10451057

test-data/unit/check-parameter-specification.test

+11
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,17 @@ def f(x: int) -> None: ...
680680
n.foo(f)
681681
[builtins fixtures/paramspec.pyi]
682682

683+
[case testLastParameterToConcatenateAndInvalidCallable]
684+
# See https://github.com/python/mypy/issues/13518
685+
from typing_extensions import Concatenate, ParamSpec
686+
from typing import Callable, TypeVar, Any
687+
688+
P = ParamSpec("P")
689+
690+
def f(fn: Callable[Concatenate[P, int], None]): ... # E: The last parameter to Concatenate needs to be a ParamSpec
691+
reveal_type(f) # N: Revealed type is "def [P] (fn: def (*Any, **Any) -> Any) -> Any"
692+
[builtins fixtures/paramspec.pyi]
693+
683694
[case testParamSpecLiteralsTypeApplication]
684695
from typing_extensions import ParamSpec
685696
from typing import Generic, Callable

0 commit comments

Comments
 (0)