Skip to content

Commit a56adc8

Browse files
authored
Optimize generic inference passes (#19501)
This gives around 5% perf boost for interpreted mypy (on self-check), but only 1.5-2% for compiled one. Note this is _not_ a no-op, this is a faster (and IMO actually more correct) inference passes logic. Btw, for more generics-rich code the savings may be bigger, e.g. `mypy -c "import colours"` becomes 30% faster (compiled).
1 parent 2e5d7ee commit a56adc8

File tree

1 file changed

+20
-21
lines changed

1 file changed

+20
-21
lines changed

mypy/checkexpr.py

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,14 +1755,6 @@ def check_callable_call(
17551755
return AnyType(TypeOfAny.from_error), callee
17561756
seen_unpack = True
17571757

1758-
formal_to_actual = map_actuals_to_formals(
1759-
arg_kinds,
1760-
arg_names,
1761-
callee.arg_kinds,
1762-
callee.arg_names,
1763-
lambda i: self.accept(args[i]),
1764-
)
1765-
17661758
# This is tricky: return type may contain its own type variables, like in
17671759
# def [S] (S) -> def [T] (T) -> tuple[S, T], so we need to update their ids
17681760
# to avoid possible id clashes if this call itself appears in a generic
@@ -1773,27 +1765,29 @@ def check_callable_call(
17731765
freeze_all_type_vars(fresh_ret_type)
17741766
callee = callee.copy_modified(ret_type=fresh_ret_type)
17751767

1768+
if callee.is_generic():
1769+
callee = freshen_function_type_vars(callee)
1770+
callee = self.infer_function_type_arguments_using_context(callee, context)
1771+
1772+
formal_to_actual = map_actuals_to_formals(
1773+
arg_kinds,
1774+
arg_names,
1775+
callee.arg_kinds,
1776+
callee.arg_names,
1777+
lambda i: self.accept(args[i]),
1778+
)
1779+
17761780
if callee.is_generic():
17771781
need_refresh = any(
17781782
isinstance(v, (ParamSpecType, TypeVarTupleType)) for v in callee.variables
17791783
)
1780-
callee = freshen_function_type_vars(callee)
1781-
callee = self.infer_function_type_arguments_using_context(callee, context)
1782-
if need_refresh:
1783-
# Argument kinds etc. may have changed due to
1784-
# ParamSpec or TypeVarTuple variables being replaced with an arbitrary
1785-
# number of arguments; recalculate actual-to-formal map
1786-
formal_to_actual = map_actuals_to_formals(
1787-
arg_kinds,
1788-
arg_names,
1789-
callee.arg_kinds,
1790-
callee.arg_names,
1791-
lambda i: self.accept(args[i]),
1792-
)
17931784
callee = self.infer_function_type_arguments(
17941785
callee, args, arg_kinds, arg_names, formal_to_actual, need_refresh, context
17951786
)
17961787
if need_refresh:
1788+
# Argument kinds etc. may have changed due to
1789+
# ParamSpec or TypeVarTuple variables being replaced with an arbitrary
1790+
# number of arguments; recalculate actual-to-formal map
17971791
formal_to_actual = map_actuals_to_formals(
17981792
arg_kinds,
17991793
arg_names,
@@ -2258,6 +2252,11 @@ def infer_function_type_arguments_pass2(
22582252
if isinstance(arg, (NoneType, UninhabitedType)) or has_erased_component(arg):
22592253
inferred_args[i] = None
22602254
callee_type = self.apply_generic_arguments(callee_type, inferred_args, context)
2255+
2256+
if not callee_type.is_generic():
2257+
# Fast path, second pass can't give new information.
2258+
return callee_type, []
2259+
22612260
if need_refresh:
22622261
formal_to_actual = map_actuals_to_formals(
22632262
arg_kinds,

0 commit comments

Comments
 (0)