Skip to content

Commit a32d2f4

Browse files
authored
Speed up make_simplified_union for Literal[string]s (issue #9169) (#9192)
make_simplified_union no longer runs for 0.5 seconds every time it's called with a Union containing 270 literals of strings. Like I explained in #9169, this only fixes half of the problem and I'm not capable of fixing the other half. This function is still called 1098 times for the "reduced" example code, and IMO it should be called only once.
1 parent cc46692 commit a32d2f4

File tree

1 file changed

+29
-15
lines changed

1 file changed

+29
-15
lines changed

mypy/typeops.py

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -344,21 +344,35 @@ def make_simplified_union(items: Sequence[Type],
344344
from mypy.subtypes import is_proper_subtype
345345

346346
removed = set() # type: Set[int]
347-
for i, ti in enumerate(items):
348-
if i in removed: continue
349-
# Keep track of the truishness info for deleted subtypes which can be relevant
350-
cbt = cbf = False
351-
for j, tj in enumerate(items):
352-
if i != j and is_proper_subtype(tj, ti, keep_erased_types=keep_erased):
353-
# We found a redundant item in the union.
354-
removed.add(j)
355-
cbt = cbt or tj.can_be_true
356-
cbf = cbf or tj.can_be_false
357-
# if deleted subtypes had more general truthiness, use that
358-
if not ti.can_be_true and cbt:
359-
items[i] = true_or_false(ti)
360-
elif not ti.can_be_false and cbf:
361-
items[i] = true_or_false(ti)
347+
348+
# Avoid slow nested for loop for Union of Literal of strings (issue #9169)
349+
if all((isinstance(item, LiteralType) and
350+
item.fallback.type.fullname == 'builtins.str')
351+
for item in items):
352+
seen = set() # type: Set[str]
353+
for index, item in enumerate(items):
354+
assert isinstance(item, LiteralType)
355+
assert isinstance(item.value, str)
356+
if item.value in seen:
357+
removed.add(index)
358+
seen.add(item.value)
359+
360+
else:
361+
for i, ti in enumerate(items):
362+
if i in removed: continue
363+
# Keep track of the truishness info for deleted subtypes which can be relevant
364+
cbt = cbf = False
365+
for j, tj in enumerate(items):
366+
if i != j and is_proper_subtype(tj, ti, keep_erased_types=keep_erased):
367+
# We found a redundant item in the union.
368+
removed.add(j)
369+
cbt = cbt or tj.can_be_true
370+
cbf = cbf or tj.can_be_false
371+
# if deleted subtypes had more general truthiness, use that
372+
if not ti.can_be_true and cbt:
373+
items[i] = true_or_false(ti)
374+
elif not ti.can_be_false and cbf:
375+
items[i] = true_or_false(ti)
362376

363377
simplified_set = [items[i] for i in range(len(items)) if i not in removed]
364378
return UnionType.make_union(simplified_set, line, column)

0 commit comments

Comments
 (0)