Skip to content

Commit

Permalink
Optimization: Remove expensive context manager in type analyzer (#14357)
Browse files Browse the repository at this point in the history
This makes mypy a bit faster and the implementation seems a little
cleaner as well.

(Various small optimizations, including this, together netted a 6%
performance improvement in self check.)
  • Loading branch information
JukkaL authored Dec 28, 2022
1 parent 20e9733 commit 45bed9c
Showing 1 changed file with 39 additions and 29 deletions.
68 changes: 39 additions & 29 deletions mypy/typeanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,13 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool)
self.api.record_incomplete_ref()
# Always allow ParamSpec for placeholders, if they are actually not valid,
# they will be reported later, after we resolve placeholders.
with self.set_allow_param_spec_literals(True):
return PlaceholderType(
node.fullname, self.anal_array(t.args, allow_param_spec=True), t.line
)
return PlaceholderType(
node.fullname,
self.anal_array(
t.args, allow_param_spec=True, allow_param_spec_literals=True
),
t.line,
)
else:
if self.api.final_iteration:
self.cannot_resolve_type(t)
Expand Down Expand Up @@ -382,10 +385,13 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool)
return special
if isinstance(node, TypeAlias):
self.aliases_used.add(fullname)
with self.set_allow_param_spec_literals(node.has_param_spec_type):
an_args = self.anal_array(t.args, allow_param_spec=True)
if node.has_param_spec_type and len(node.alias_tvars) == 1:
an_args = self.pack_paramspec_args(an_args)
an_args = self.anal_array(
t.args,
allow_param_spec=True,
allow_param_spec_literals=node.has_param_spec_type,
)
if node.has_param_spec_type and len(node.alias_tvars) == 1:
an_args = self.pack_paramspec_args(an_args)

disallow_any = self.options.disallow_any_generics and not self.is_typeshed_stub
res = expand_type_alias(
Expand Down Expand Up @@ -660,17 +666,22 @@ def analyze_type_with_type_info(
fallback = Instance(info, [AnyType(TypeOfAny.special_form)], ctx.line)
return TupleType(self.anal_array(args), fallback, ctx.line)

# This is a heuristic: it will be checked later anyways but the error
# message may be worse.
with self.set_allow_param_spec_literals(info.has_param_spec_type):
# Analyze arguments and (usually) construct Instance type. The
# number of type arguments and their values are
# checked only later, since we do not always know the
# valid count at this point. Thus we may construct an
# Instance with an invalid number of type arguments.
instance = Instance(
info, self.anal_array(args, allow_param_spec=True), ctx.line, ctx.column
)
# Analyze arguments and (usually) construct Instance type. The
# number of type arguments and their values are
# checked only later, since we do not always know the
# valid count at this point. Thus we may construct an
# Instance with an invalid number of type arguments.
#
# We allow ParamSpec literals based on a heuristic: it will be
# checked later anyways but the error message may be worse.
instance = Instance(
info,
self.anal_array(
args, allow_param_spec=True, allow_param_spec_literals=info.has_param_spec_type
),
ctx.line,
ctx.column,
)
if len(info.type_vars) == 1 and info.has_param_spec_type:
instance.args = tuple(self.pack_paramspec_args(instance.args))

Expand Down Expand Up @@ -1466,11 +1477,19 @@ def is_defined_type_var(self, tvar: str, context: Context) -> bool:
return self.tvar_scope.get_binding(tvar_node) is not None

def anal_array(
self, a: Iterable[Type], nested: bool = True, *, allow_param_spec: bool = False
self,
a: Iterable[Type],
nested: bool = True,
*,
allow_param_spec: bool = False,
allow_param_spec_literals: bool = False,
) -> list[Type]:
old_allow_param_spec_literals = self.allow_param_spec_literals
self.allow_param_spec_literals = allow_param_spec_literals
res: list[Type] = []
for t in a:
res.append(self.anal_type(t, nested, allow_param_spec=allow_param_spec))
self.allow_param_spec_literals = old_allow_param_spec_literals
return self.check_unpacks_in_list(res)

def anal_type(self, t: Type, nested: bool = True, *, allow_param_spec: bool = False) -> Type:
Expand Down Expand Up @@ -1558,15 +1577,6 @@ def tuple_type(self, items: list[Type]) -> TupleType:
any_type = AnyType(TypeOfAny.special_form)
return TupleType(items, fallback=self.named_type("builtins.tuple", [any_type]))

@contextmanager
def set_allow_param_spec_literals(self, to: bool) -> Iterator[None]:
old = self.allow_param_spec_literals
try:
self.allow_param_spec_literals = to
yield
finally:
self.allow_param_spec_literals = old


TypeVarLikeList = List[Tuple[str, TypeVarLikeExpr]]

Expand Down

0 comments on commit 45bed9c

Please sign in to comment.