diff --git a/mypy/typeanal.py b/mypy/typeanal.py index 31dac8b24e146..4b3278049fdbc 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -1026,8 +1026,10 @@ def analyze_callable_args_for_paramspec( def analyze_callable_args_for_concatenate( self, callable_args: Type, ret_type: Type, fallback: Instance ) -> CallableType | None: - """Construct a 'Callable[C, RET]', where C is Concatenate[..., P], returning None if we - cannot. + """Construct a 'Callable[C, RET]', where C is Concatenate[..., P] + + Return `None` if we cannot. + Return `AnyType` if we only can do it partially. """ if not isinstance(callable_args, UnboundType): return None @@ -1039,7 +1041,17 @@ def analyze_callable_args_for_concatenate( if sym.node.fullname not in ("typing_extensions.Concatenate", "typing.Concatenate"): return None - tvar_def = self.anal_type(callable_args, allow_param_spec=True) + tvar_def = get_proper_type(self.anal_type(callable_args, allow_param_spec=True)) + if isinstance(tvar_def, AnyType) and tvar_def.type_of_any == TypeOfAny.from_error: + # Some error happened, we won't be able to construct a proper type anyway. + # So, instead return a callable that accepts anything. + return CallableType( + arg_names=[None] * 2, + arg_types=[AnyType(TypeOfAny.from_error)] * 2, + arg_kinds=[ARG_STAR, ARG_STAR2], + ret_type=AnyType(TypeOfAny.from_error), + fallback=fallback, + ) if not isinstance(tvar_def, ParamSpecType): return None diff --git a/test-data/unit/check-parameter-specification.test b/test-data/unit/check-parameter-specification.test index a561acba693c7..4da2a55eebd0d 100644 --- a/test-data/unit/check-parameter-specification.test +++ b/test-data/unit/check-parameter-specification.test @@ -680,6 +680,17 @@ def f(x: int) -> None: ... n.foo(f) [builtins fixtures/paramspec.pyi] +[case testLastParameterToConcatenateAndInvalidCallable] +# See https://github.com/python/mypy/issues/13518 +from typing_extensions import Concatenate, ParamSpec +from typing import Callable, TypeVar, Any + +P = ParamSpec("P") + +def f(fn: Callable[Concatenate[P, int], None]): ... # E: The last parameter to Concatenate needs to be a ParamSpec +reveal_type(f) # N: Revealed type is "def [P] (fn: def (*Any, **Any) -> Any) -> Any" +[builtins fixtures/paramspec.pyi] + [case testParamSpecLiteralsTypeApplication] from typing_extensions import ParamSpec from typing import Generic, Callable