Skip to content

Commit b5fc748

Browse files
authored
Optimize subtype checking by avoiding a nested function (#14325)
Mypyc isn't good at compiling nested functions, and this one was in one of the hottest code paths in all of mypy. The nested function wasn't even used that often, but mypyc would still construct a closure object every time. This adds some code duplication, but it's well worth it. Amazingly, this speeds up self-check by about 10%, if my measurements are to be trusted! This addresses some of the slowdown introduced in #13303. #14324 addresses another related slowdown.
1 parent d35e571 commit b5fc748

File tree

1 file changed

+20
-11
lines changed

1 file changed

+20
-11
lines changed

mypy/subtypes.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -289,18 +289,20 @@ def _is_subtype(
289289
# ErasedType as we do for non-proper subtyping.
290290
return True
291291

292-
def check_item(left: Type, right: Type, subtype_context: SubtypeContext) -> bool:
293-
if proper_subtype:
294-
return is_proper_subtype(left, right, subtype_context=subtype_context)
295-
return is_subtype(left, right, subtype_context=subtype_context)
296-
297292
if isinstance(right, UnionType) and not isinstance(left, UnionType):
298293
# Normally, when 'left' is not itself a union, the only way
299294
# 'left' can be a subtype of the union 'right' is if it is a
300295
# subtype of one of the items making up the union.
301-
is_subtype_of_item = any(
302-
check_item(orig_left, item, subtype_context) for item in right.items
303-
)
296+
if proper_subtype:
297+
is_subtype_of_item = any(
298+
is_proper_subtype(orig_left, item, subtype_context=subtype_context)
299+
for item in right.items
300+
)
301+
else:
302+
is_subtype_of_item = any(
303+
is_subtype(orig_left, item, subtype_context=subtype_context)
304+
for item in right.items
305+
)
304306
# Recombine rhs literal types, to make an enum type a subtype
305307
# of a union of all enum items as literal types. Only do it if
306308
# the previous check didn't succeed, since recombining can be
@@ -312,9 +314,16 @@ def check_item(left: Type, right: Type, subtype_context: SubtypeContext) -> bool
312314
and (left.type.is_enum or left.type.fullname == "builtins.bool")
313315
):
314316
right = UnionType(mypy.typeops.try_contracting_literals_in_union(right.items))
315-
is_subtype_of_item = any(
316-
check_item(orig_left, item, subtype_context) for item in right.items
317-
)
317+
if proper_subtype:
318+
is_subtype_of_item = any(
319+
is_proper_subtype(orig_left, item, subtype_context=subtype_context)
320+
for item in right.items
321+
)
322+
else:
323+
is_subtype_of_item = any(
324+
is_subtype(orig_left, item, subtype_context=subtype_context)
325+
for item in right.items
326+
)
318327
# However, if 'left' is a type variable T, T might also have
319328
# an upper bound which is itself a union. This case will be
320329
# handled below by the SubtypeVisitor. We have to check both

0 commit comments

Comments
 (0)