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

Speed up type argument checking #16353

Merged
merged 1 commit into from
Oct 29, 2023
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
19 changes: 13 additions & 6 deletions mypy/semanal_typeargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from __future__ import annotations

from typing import Callable, Sequence
from typing import Callable

from mypy import errorcodes as codes, message_registry
from mypy.errorcodes import ErrorCode
Expand Down Expand Up @@ -88,7 +88,7 @@ def visit_type_alias_type(self, t: TypeAliasType) -> None:
return
self.seen_aliases.add(t)
assert t.alias is not None, f"Unfixed type alias {t.type_ref}"
is_error = self.validate_args(t.alias.name, t.args, t.alias.alias_tvars, t)
is_error = self.validate_args(t.alias.name, tuple(t.args), t.alias.alias_tvars, t)
if not is_error:
# If there was already an error for the alias itself, there is no point in checking
# the expansion, most likely it will result in the same kind of error.
Expand Down Expand Up @@ -131,7 +131,7 @@ def visit_instance(self, t: Instance) -> None:
t.args = unpacked.args

def validate_args(
self, name: str, args: Sequence[Type], type_vars: list[TypeVarLikeType], ctx: Context
self, name: str, args: tuple[Type, ...], type_vars: list[TypeVarLikeType], ctx: Context
) -> bool:
if any(isinstance(v, TypeVarTupleType) for v in type_vars):
prefix = next(i for (i, v) in enumerate(type_vars) if isinstance(v, TypeVarTupleType))
Expand All @@ -140,7 +140,7 @@ def validate_args(
start, middle, end = split_with_prefix_and_suffix(
tuple(args), prefix, len(type_vars) - prefix - 1
)
args = list(start) + [TupleType(list(middle), tvt.tuple_fallback)] + list(end)
args = start + (TupleType(list(middle), tvt.tuple_fallback),) + end

is_error = False
for (i, arg), tvar in zip(enumerate(args), type_vars):
Expand Down Expand Up @@ -174,7 +174,14 @@ def validate_args(
arg_values = [arg]
if self.check_type_var_values(name, arg_values, tvar.name, tvar.values, ctx):
is_error = True
if not is_subtype(arg, tvar.upper_bound):
# Check against upper bound. Since it's object the vast majority of the time,
# add fast path to avoid a potentially slow subtype check.
upper_bound = tvar.upper_bound
object_upper_bound = (
type(upper_bound) is Instance
and upper_bound.type.fullname == "builtins.object"
)
if not object_upper_bound and not is_subtype(arg, upper_bound):
if self.in_type_alias_expr and isinstance(arg, TypeVarType):
# Type aliases are allowed to use unconstrained type variables
# error will be checked at substitution point.
Expand All @@ -184,7 +191,7 @@ def validate_args(
message_registry.INVALID_TYPEVAR_ARG_BOUND.format(
format_type(arg, self.options),
name,
format_type(tvar.upper_bound, self.options),
format_type(upper_bound, self.options),
),
ctx,
code=codes.TYPE_VAR,
Expand Down