Skip to content

Commit 024cf49

Browse files
added fast path for tuple[Any, ...] comparison
1 parent 16061cf commit 024cf49

3 files changed

Lines changed: 37 additions & 5 deletions

File tree

mypy/subtypes.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
UnpackType,
7070
flatten_nested_unions,
7171
get_proper_type,
72+
is_any_tuple,
7273
is_named_instance,
7374
split_with_prefix_and_suffix,
7475
)
@@ -797,6 +798,9 @@ def visit_tuple_type(self, left: TupleType) -> bool:
797798
return True
798799
return False
799800
elif isinstance(right, TupleType):
801+
# fast path: left or right is equivalent to tuple[Any, ...]
802+
if is_any_tuple(left) or is_any_tuple(right):
803+
return True
800804
# If right has a variadic unpack this needs special handling. If there is a TypeVarTuple
801805
# unpack, item count must coincide. If the left has variadic unpack but right
802806
# doesn't have one, we will fall through to False down the line.
@@ -844,11 +848,6 @@ def variadic_tuple_subtype(self, left: TupleType, right: TupleType) -> bool:
844848
tuple[X, ...] <: tuple[*tuple[X, ...], X]
845849
then result is False if proper_subtype is True, otherwise True.
846850
847-
X <: AnyOf[U1, U2, ...] iff X <: Ui for some i
848-
AnyOf[T1, T2, ...] <: X iff X <: Ui for some i
849-
X <: Union[U1, U2, ...] iff X <: Ui for some i
850-
Union[T1, T2, ...] <: X iff X <: Ui for all i
851-
852851
Note: the cases where right is fixed or has *Ts unpack should be handled
853852
by the caller.
854853
"""
@@ -862,6 +861,7 @@ def variadic_tuple_subtype(self, left: TupleType, right: TupleType) -> bool:
862861
right_unpacked = get_proper_type(right_unpack.type)
863862
if not isinstance(right_unpacked, Instance):
864863
# This case should be handled by the caller.
864+
# TODO: actually handle it here.
865865
return False
866866
assert right_unpacked.type.fullname == "builtins.tuple"
867867
right_item = right_unpacked.args[0]

mypy/types.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3044,6 +3044,26 @@ def simplify(self) -> TupleType | TupleInstanceType | ParamSpecType:
30443044
return self
30453045

30463046

3047+
def is_any_tuple(t: Type) -> bool:
3048+
"""Is this `tuple[Any, ...]`?"""
3049+
t = get_proper_type(t)
3050+
3051+
if isinstance(t, Instance):
3052+
assert len(t.args) == 1
3053+
return t.type.fullname == "builtins.tuple" and isinstance(
3054+
get_proper_type(t.args[0]), AnyType
3055+
)
3056+
3057+
if isinstance(t, TupleType):
3058+
return (
3059+
len(items := t.flattened_items) == 1
3060+
and isinstance(item := items[0], UnpackType)
3061+
and is_any_tuple(item.type)
3062+
)
3063+
3064+
return False
3065+
3066+
30473067
class TypedDictType(ProperType):
30483068
"""Type of TypedDict object {'k1': v1, ..., 'kn': vn}.
30493069

test-data/unit/check-varargs.test

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,3 +1858,15 @@ def test_takes_exactly_3(
18581858
takes_exactly_3(*x3)
18591859
takes_exactly_3(*x4) # E: Too many positional arguments for "takes_exactly_3"
18601860
[builtins fixtures/tuple.pyi]
1861+
1862+
[case testAnyTupleAssignableToParamSpecVarArgs]
1863+
from typing import Callable, Any, ParamSpec, TypeVar
1864+
1865+
R = TypeVar('R')
1866+
P = ParamSpec('P')
1867+
1868+
def decorator(func: Callable[P, R]) -> Callable[P, R]:
1869+
def wrapper(*args: Any, **kwargs: Any) -> R:
1870+
return func(*args, **kwargs)
1871+
return wrapper
1872+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)