Skip to content

Commit 442d8c5

Browse files
Merge pull request #4 from VallinZ/DistributeTuple
Attempt to fix distribute Tuple issue
2 parents 35cf276 + 6949731 commit 442d8c5

File tree

1 file changed

+41
-1
lines changed

1 file changed

+41
-1
lines changed

mypy/subtypes.py

+41-1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ def is_subtype(
185185
# steps we come back to initial call is_subtype(A, B) and immediately return True.
186186
with pop_on_exit(type_state.get_assumptions(is_proper=False), left, right):
187187
return _is_subtype(left, right, subtype_context, proper_subtype=False)
188+
left = get_proper_type(left)
189+
right = get_proper_type(right)
188190
return _is_subtype(left, right, subtype_context, proper_subtype=False)
189191

190192

@@ -282,6 +284,21 @@ def is_same_type(
282284
)
283285

284286

287+
# This is a helper function used to check for recursive type of distributed tuple
288+
def is_structurally_recursive(typ: Type, seen: set[Type] | None = None) -> bool:
289+
if seen is None:
290+
seen = set()
291+
typ = get_proper_type(typ)
292+
if typ in seen:
293+
return True
294+
seen.add(typ)
295+
if isinstance(typ, UnionType):
296+
return any(is_structurally_recursive(item, seen.copy()) for item in typ.items)
297+
if isinstance(typ, TupleType):
298+
return any(is_structurally_recursive(item, seen.copy()) for item in typ.items)
299+
return False
300+
301+
285302
# This is a common entry point for subtyping checks (both proper and non-proper).
286303
# Never call this private function directly, use the public versions.
287304
def _is_subtype(
@@ -303,7 +320,30 @@ def _is_subtype(
303320
# TODO: should we consider all types proper subtypes of UnboundType and/or
304321
# ErasedType as we do for non-proper subtyping.
305322
return True
306-
323+
if isinstance(left, TupleType) and isinstance(right, UnionType):
324+
# check only if not recursive type because if recursive type,
325+
# test run into maximum recursive depth reached
326+
if not is_structurally_recursive(left) and not is_structurally_recursive(right):
327+
fallback = left.partial_fallback
328+
tuple_items = left.items
329+
if hasattr(left, "fallback") and left.fallback is not None:
330+
fallback = left.fallback
331+
for i in range(len(tuple_items)):
332+
uitems = tuple_items[i]
333+
uitems_type = get_proper_type(uitems)
334+
if isinstance(uitems_type, UnionType):
335+
new_tuples = [
336+
TupleType(
337+
tuple_items[:i] + [uitem] + tuple_items[i + 1 :], fallback=fallback
338+
)
339+
for uitem in uitems_type.items
340+
]
341+
result = [
342+
_is_subtype(t, right, subtype_context, proper_subtype=False)
343+
for t in new_tuples
344+
]
345+
inverted_list = [not item for item in result]
346+
return not any(inverted_list)
307347
if isinstance(right, UnionType) and not isinstance(left, UnionType):
308348
# Normally, when 'left' is not itself a union, the only way
309349
# 'left' can be a subtype of the union 'right' is if it is a

0 commit comments

Comments
 (0)