Skip to content

Commit 2ff391c

Browse files
hugues-affJukkaL
authored andcommitted
make_simplified_union: simpler and faster (#12630)
Recent attempts at speedup introduced some convoluted logic that both reduced accuracy and caused performance regressions. Fix this and add more comments to clarify the reasoning behind the optimization.
1 parent 963e4ae commit 2ff391c

File tree

1 file changed

+22
-25
lines changed

1 file changed

+22
-25
lines changed

mypy/typeops.py

+22-25
Original file line numberDiff line numberDiff line change
@@ -410,26 +410,29 @@ def _remove_redundant_union_items(items: List[ProperType], keep_erased: bool) ->
410410

411411
# Keep track of the truishness info for deleted subtypes which can be relevant
412412
cbt = cbf = False
413-
num_items = len(items)
414413
for j, tj in enumerate(items):
415-
if i != j:
416-
# NB: The first check below is an optimization to
417-
# avoid very expensive computations with large
418-
# unions involving literals. We approximate the
419-
# results for unions with many items. This is
420-
# "fine" since simplifying these union items is
421-
# (almost) always optional.
422-
if (
423-
(num_items < 5
424-
or is_likely_literal_supertype(item)
425-
or not is_simple_literal(tj))
426-
and is_proper_subtype(tj, item, keep_erased_types=keep_erased)
427-
and is_redundant_literal_instance(item, tj) # XXX?
428-
):
429-
# We found a redundant item in the union.
430-
removed.add(j)
431-
cbt = cbt or tj.can_be_true
432-
cbf = cbf or tj.can_be_false
414+
if (
415+
i == j
416+
# avoid further checks if this item was already marked redundant.
417+
or j in removed
418+
# if the current item is a simple literal then this simplification loop can
419+
# safely skip all other simple literals as two literals will only ever be
420+
# subtypes of each other if they are equal, which is already handled above.
421+
# However, if the current item is not a literal, it might plausibly be a
422+
# supertype of other literals in the union, so we must check them again.
423+
# This is an important optimization as is_proper_subtype is pretty expensive.
424+
or (k is not None and is_simple_literal(tj))
425+
):
426+
continue
427+
# actual redundancy checks
428+
if (
429+
is_redundant_literal_instance(item, tj) # XXX?
430+
and is_proper_subtype(tj, item, keep_erased_types=keep_erased)
431+
):
432+
# We found a redundant item in the union.
433+
removed.add(j)
434+
cbt = cbt or tj.can_be_true
435+
cbf = cbf or tj.can_be_false
433436
# if deleted subtypes had more general truthiness, use that
434437
if not item.can_be_true and cbt:
435438
items[i] = true_or_false(item)
@@ -439,12 +442,6 @@ def _remove_redundant_union_items(items: List[ProperType], keep_erased: bool) ->
439442
return [items[i] for i in range(len(items)) if i not in removed]
440443

441444

442-
def is_likely_literal_supertype(t: ProperType) -> bool:
443-
"""Is the type likely to cause simplification of literal types in unions?"""
444-
return isinstance(t, Instance) and t.type.fullname in ('builtins.object',
445-
'builtins.str')
446-
447-
448445
def _get_type_special_method_bool_ret_type(t: Type) -> Optional[Type]:
449446
t = get_proper_type(t)
450447

0 commit comments

Comments
 (0)