Fix crash with type alias to `Callable[[Unpack[Tuple[Any, ...]]], Any]` (#16541)
Fixes #16533
diff --git a/mypy/expandtype.py b/mypy/expandtype.py
index 3acec4b..f6aa74a 100644
--- a/mypy/expandtype.py
+++ b/mypy/expandtype.py
@@ -307,18 +307,24 @@
suffix = self.expand_types(t.arg_types[star_index + 1 :])
var_arg_type = get_proper_type(var_arg.type)
- # We have something like Unpack[Tuple[Unpack[Ts], X1, X2]]
- if isinstance(var_arg_type, TupleType):
- expanded_tuple = var_arg_type.accept(self)
- assert isinstance(expanded_tuple, ProperType) and isinstance(expanded_tuple, TupleType)
- expanded_items = expanded_tuple.items
- fallback = var_arg_type.partial_fallback
+ if isinstance(var_arg_type, Instance):
+ # we have something like Unpack[Tuple[Any, ...]]
+ new_unpack = var_arg
else:
- # We have plain Unpack[Ts]
- assert isinstance(var_arg_type, TypeVarTupleType)
- fallback = var_arg_type.tuple_fallback
- expanded_items = self.expand_unpack(var_arg)
- new_unpack = UnpackType(TupleType(expanded_items, fallback))
+ if isinstance(var_arg_type, TupleType):
+ # We have something like Unpack[Tuple[Unpack[Ts], X1, X2]]
+ expanded_tuple = var_arg_type.accept(self)
+ assert isinstance(expanded_tuple, ProperType) and isinstance(
+ expanded_tuple, TupleType
+ )
+ expanded_items = expanded_tuple.items
+ fallback = var_arg_type.partial_fallback
+ else:
+ # We have plain Unpack[Ts]
+ assert isinstance(var_arg_type, TypeVarTupleType), type(var_arg_type)
+ fallback = var_arg_type.tuple_fallback
+ expanded_items = self.expand_unpack(var_arg)
+ new_unpack = UnpackType(TupleType(expanded_items, fallback))
return prefix + [new_unpack] + suffix
def visit_callable_type(self, t: CallableType) -> CallableType:
diff --git a/test-data/unit/check-typevar-tuple.test b/test-data/unit/check-typevar-tuple.test
index 487f226..9c8d211 100644
--- a/test-data/unit/check-typevar-tuple.test
+++ b/test-data/unit/check-typevar-tuple.test
@@ -2235,3 +2235,45 @@
w: Tuple[int, Unpack[Tuple[int, ...]]] = (1, *[2, 3, 4])
t: Tuple[int, Unpack[Tuple[int, ...]]] = (1, *(2, 3, 4))
[builtins fixtures/tuple.pyi]
+
+[case testAliasToCallableWithUnpack]
+from typing import Any, Callable, Tuple, Unpack
+
+_CallableValue = Callable[[Unpack[Tuple[Any, ...]]], Any]
+def higher_order(f: _CallableValue) -> None: ...
+
+def good1(*args: int) -> None: ...
+def good2(*args: str) -> int: ...
+
+def bad1(a: str, b: int, /) -> None: ...
+def bad2(c: bytes, *args: int) -> str: ...
+def bad3(*, d: str) -> int: ...
+def bad4(**kwargs: None) -> None: ...
+
+higher_order(good1)
+higher_order(good2)
+
+higher_order(bad1) # E: Argument 1 to "higher_order" has incompatible type "Callable[[str, int], None]"; expected "Callable[[VarArg(Any)], Any]"
+higher_order(bad2) # E: Argument 1 to "higher_order" has incompatible type "Callable[[bytes, VarArg(int)], str]"; expected "Callable[[VarArg(Any)], Any]"
+higher_order(bad3) # E: Argument 1 to "higher_order" has incompatible type "Callable[[NamedArg(str, 'd')], int]"; expected "Callable[[VarArg(Any)], Any]"
+higher_order(bad4) # E: Argument 1 to "higher_order" has incompatible type "Callable[[KwArg(None)], None]"; expected "Callable[[VarArg(Any)], Any]"
+[builtins fixtures/tuple.pyi]
+
+[case testAliasToCallableWithUnpack2]
+from typing import Any, Callable, Tuple, Unpack
+
+_CallableValue = Callable[[int, str, Unpack[Tuple[Any, ...]], int], Any]
+def higher_order(f: _CallableValue) -> None: ...
+
+def good(a: int, b: str, *args: Unpack[Tuple[Unpack[Tuple[Any, ...]], int]]) -> int: ...
+def bad1(a: str, b: int, /) -> None: ...
+def bad2(c: bytes, *args: int) -> str: ...
+def bad3(*, d: str) -> int: ...
+def bad4(**kwargs: None) -> None: ...
+
+higher_order(good)
+higher_order(bad1) # E: Argument 1 to "higher_order" has incompatible type "Callable[[str, int], None]"; expected "Callable[[int, str, VarArg(Unpack[Tuple[Unpack[Tuple[Any, ...]], int]])], Any]"
+higher_order(bad2) # E: Argument 1 to "higher_order" has incompatible type "Callable[[bytes, VarArg(int)], str]"; expected "Callable[[int, str, VarArg(Unpack[Tuple[Unpack[Tuple[Any, ...]], int]])], Any]"
+higher_order(bad3) # E: Argument 1 to "higher_order" has incompatible type "Callable[[NamedArg(str, 'd')], int]"; expected "Callable[[int, str, VarArg(Unpack[Tuple[Unpack[Tuple[Any, ...]], int]])], Any]"
+higher_order(bad4) # E: Argument 1 to "higher_order" has incompatible type "Callable[[KwArg(None)], None]"; expected "Callable[[int, str, VarArg(Unpack[Tuple[Unpack[Tuple[Any, ...]], int]])], Any]"
+[builtins fixtures/tuple.pyi]