Skip to content

Commit 0313ed6

Browse files
committed
Use dedicated tags for most common instances
1 parent 6a88c21 commit 0313ed6

File tree

4 files changed

+99
-23
lines changed

4 files changed

+99
-23
lines changed

mypy/build.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
from mypy.renaming import LimitedVariableRenameVisitor, VariableRenameVisitor
9292
from mypy.stats import dump_type_stats
9393
from mypy.stubinfo import is_module_from_legacy_bundled_package, stub_distribution_name
94-
from mypy.types import Type
94+
from mypy.types import Type, instance_cache
9595
from mypy.typestate import reset_global_state, type_state
9696
from mypy.util import json_dumps, json_loads
9797
from mypy.version import __version__
@@ -180,6 +180,9 @@ def build(
180180
# fields for callers that want the traditional API.
181181
messages = []
182182

183+
# This is mostly for the benefit of tests that use builtins fixtures.
184+
instance_cache.reset()
185+
183186
def default_flush_errors(
184187
filename: str | None, new_messages: list[str], is_serious: bool
185188
) -> None:

mypy/checker.py

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@
227227
flatten_nested_unions,
228228
get_proper_type,
229229
get_proper_types,
230+
instance_cache,
230231
is_literal_type,
231232
is_named_instance,
232233
)
@@ -465,12 +466,6 @@ def __init__(
465466
self, self.msg, self.plugin, per_line_checking_time_ns
466467
)
467468

468-
self._str_type: Instance | None = None
469-
self._function_type: Instance | None = None
470-
self._int_type: Instance | None = None
471-
self._bool_type: Instance | None = None
472-
self._object_type: Instance | None = None
473-
474469
self.pattern_checker = PatternChecker(self, self.msg, self.plugin, options)
475470
self._unique_id = 0
476471

@@ -7415,25 +7410,25 @@ def named_type(self, name: str) -> Instance:
74157410
For example, named_type('builtins.object') produces the 'object' type.
74167411
"""
74177412
if name == "builtins.str":
7418-
if self._str_type is None:
7419-
self._str_type = self._named_type(name)
7420-
return self._str_type
7413+
if instance_cache.str_type is None:
7414+
instance_cache.str_type = self._named_type(name)
7415+
return instance_cache.str_type
74217416
if name == "builtins.function":
7422-
if self._function_type is None:
7423-
self._function_type = self._named_type(name)
7424-
return self._function_type
7417+
if instance_cache.function_type is None:
7418+
instance_cache.function_type = self._named_type(name)
7419+
return instance_cache.function_type
74257420
if name == "builtins.int":
7426-
if self._int_type is None:
7427-
self._int_type = self._named_type(name)
7428-
return self._int_type
7421+
if instance_cache.int_type is None:
7422+
instance_cache.int_type = self._named_type(name)
7423+
return instance_cache.int_type
74297424
if name == "builtins.bool":
7430-
if self._bool_type is None:
7431-
self._bool_type = self._named_type(name)
7432-
return self._bool_type
7425+
if instance_cache.bool_type is None:
7426+
instance_cache.bool_type = self._named_type(name)
7427+
return instance_cache.bool_type
74337428
if name == "builtins.object":
7434-
if self._object_type is None:
7435-
self._object_type = self._named_type(name)
7436-
return self._object_type
7429+
if instance_cache.object_type is None:
7430+
instance_cache.object_type = self._named_type(name)
7431+
return instance_cache.object_type
74377432
return self._named_type(name)
74387433

74397434
def _named_type(self, name: str) -> Instance:

mypy/checkexpr.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,8 @@ def module_type(self, node: MypyFile) -> Instance:
496496
# In test cases might 'types' may not be available.
497497
# Fall back to a dummy 'object' type instead to
498498
# avoid a crash.
499-
result = self.named_type("builtins.object")
499+
# Make a copy so that we don't set extra_attrs (below) on a shared instance.
500+
result = self.named_type("builtins.object").copy_modified()
500501
module_attrs: dict[str, Type] = {}
501502
immutable = set()
502503
for name, n in node.names.items():

mypy/types.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,6 +1708,23 @@ def deserialize(cls, data: JsonDict | str) -> Instance:
17081708

17091709
def write(self, data: Buffer) -> None:
17101710
write_tag(data, INSTANCE)
1711+
if not self.args and not self.last_known_value and not self.extra_attrs:
1712+
type_ref = self.type.fullname
1713+
if type_ref == "builtins.str":
1714+
write_tag(data, INSTANCE_STR)
1715+
elif type_ref == "builtins.function":
1716+
write_tag(data, INSTANCE_FUNCTION)
1717+
elif type_ref == "builtins.int":
1718+
write_tag(data, INSTANCE_INT)
1719+
elif type_ref == "builtins.bool":
1720+
write_tag(data, INSTANCE_BOOL)
1721+
elif type_ref == "builtins.object":
1722+
write_tag(data, INSTANCE_OBJECT)
1723+
else:
1724+
write_tag(data, INSTANCE_SIMPLE)
1725+
write_str(data, type_ref)
1726+
return
1727+
write_tag(data, INSTANCE_GENERIC)
17111728
write_str(data, self.type.fullname)
17121729
write_type_list(data, self.args)
17131730
write_type_opt(data, self.last_known_value)
@@ -1719,6 +1736,39 @@ def write(self, data: Buffer) -> None:
17191736

17201737
@classmethod
17211738
def read(cls, data: Buffer) -> Instance:
1739+
tag = read_tag(data)
1740+
# This is quite verbose, but this is very hot code, so we are not
1741+
# using dictionary lookups here.
1742+
if tag == INSTANCE_STR:
1743+
if instance_cache.str_type is None:
1744+
instance_cache.str_type = Instance(NOT_READY, [])
1745+
instance_cache.str_type.type_ref = "builtins.str"
1746+
return instance_cache.str_type
1747+
if tag == INSTANCE_FUNCTION:
1748+
if instance_cache.function_type is None:
1749+
instance_cache.function_type = Instance(NOT_READY, [])
1750+
instance_cache.function_type.type_ref = "builtins.function"
1751+
return instance_cache.function_type
1752+
if tag == INSTANCE_INT:
1753+
if instance_cache.int_type is None:
1754+
instance_cache.int_type = Instance(NOT_READY, [])
1755+
instance_cache.int_type.type_ref = "builtins.int"
1756+
return instance_cache.int_type
1757+
if tag == INSTANCE_BOOL:
1758+
if instance_cache.bool_type is None:
1759+
instance_cache.bool_type = Instance(NOT_READY, [])
1760+
instance_cache.bool_type.type_ref = "builtins.bool"
1761+
return instance_cache.bool_type
1762+
if tag == INSTANCE_OBJECT:
1763+
if instance_cache.object_type is None:
1764+
instance_cache.object_type = Instance(NOT_READY, [])
1765+
instance_cache.object_type.type_ref = "builtins.object"
1766+
return instance_cache.object_type
1767+
if tag == INSTANCE_SIMPLE:
1768+
inst = Instance(NOT_READY, [])
1769+
inst.type_ref = read_str(data)
1770+
return inst
1771+
assert tag == INSTANCE_GENERIC
17221772
type_ref = read_str(data)
17231773
inst = Instance(NOT_READY, read_type_list(data))
17241774
inst.type_ref = type_ref
@@ -1769,6 +1819,25 @@ def is_singleton_type(self) -> bool:
17691819
)
17701820

17711821

1822+
class InstanceCache:
1823+
def __init__(self) -> None:
1824+
self.str_type: Instance | None = None
1825+
self.function_type: Instance | None = None
1826+
self.int_type: Instance | None = None
1827+
self.bool_type: Instance | None = None
1828+
self.object_type: Instance | None = None
1829+
1830+
def reset(self) -> None:
1831+
self.str_type = None
1832+
self.function_type = None
1833+
self.int_type = None
1834+
self.bool_type = None
1835+
self.object_type = None
1836+
1837+
1838+
instance_cache: Final = InstanceCache()
1839+
1840+
17721841
class FunctionLike(ProperType):
17731842
"""Abstract base class for function types."""
17741843

@@ -4140,6 +4209,14 @@ def type_vars_as_args(type_vars: Sequence[TypeVarLikeType]) -> tuple[Type, ...]:
41404209
TYPE_TYPE: Final[Tag] = 18
41414210
PARAMETERS: Final[Tag] = 19
41424211

4212+
INSTANCE_STR: Final[Tag] = 101
4213+
INSTANCE_FUNCTION: Final[Tag] = 102
4214+
INSTANCE_INT: Final[Tag] = 103
4215+
INSTANCE_BOOL: Final[Tag] = 104
4216+
INSTANCE_OBJECT: Final[Tag] = 105
4217+
INSTANCE_SIMPLE: Final[Tag] = 106
4218+
INSTANCE_GENERIC: Final[Tag] = 107
4219+
41434220

41444221
def read_type(data: Buffer) -> Type:
41454222
tag = read_tag(data)

0 commit comments

Comments
 (0)