Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimization: Remove expensive context manager in type analyzer #14357

Merged
merged 1 commit into from
Dec 28, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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