Skip to content

Commit 4e32da8

Browse files
authored
Refactor TypeState into a singleton class (#14327)
This helps mypyc, since accessing mutable attributes of singleton instances is faster than accessing class variables. The implementation is also arguably a bit cleaner. This seems performance-neutral or a very minor optimization, but if we continue to add attributes to TypeState, this can help.
1 parent 2d5108b commit 4e32da8

File tree

12 files changed

+108
-109
lines changed

12 files changed

+108
-109
lines changed

mypy/build.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
stub_package_name,
101101
)
102102
from mypy.types import Type
103-
from mypy.typestate import TypeState, reset_global_state
103+
from mypy.typestate import reset_global_state, type_state
104104
from mypy.version import __version__
105105

106106
# Switch to True to produce debug output related to fine-grained incremental
@@ -276,7 +276,7 @@ def _build(
276276
try:
277277
graph = dispatch(sources, manager, stdout)
278278
if not options.fine_grained_incremental:
279-
TypeState.reset_all_subtype_caches()
279+
type_state.reset_all_subtype_caches()
280280
if options.timing_stats is not None:
281281
dump_timing_stats(options.timing_stats, graph)
282282
if options.line_checking_stats is not None:
@@ -2459,7 +2459,7 @@ def update_fine_grained_deps(self, deps: dict[str, set[str]]) -> None:
24592459
from mypy.server.deps import merge_dependencies # Lazy import to speed up startup
24602460

24612461
merge_dependencies(self.compute_fine_grained_deps(), deps)
2462-
TypeState.update_protocol_deps(deps)
2462+
type_state.update_protocol_deps(deps)
24632463

24642464
def valid_references(self) -> set[str]:
24652465
assert self.ancestors is not None
@@ -2926,7 +2926,7 @@ def dispatch(sources: list[BuildSource], manager: BuildManager, stdout: TextIO)
29262926
# then we need to collect fine grained protocol dependencies.
29272927
# Since these are a global property of the program, they are calculated after we
29282928
# processed the whole graph.
2929-
TypeState.add_all_protocol_deps(manager.fg_deps)
2929+
type_state.add_all_protocol_deps(manager.fg_deps)
29302930
if not manager.options.fine_grained_incremental:
29312931
rdeps = generate_deps_for_cache(manager, graph)
29322932
write_deps_cache(rdeps, manager, graph)

mypy/checkexpr.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@
162162
is_self_type_like,
163163
remove_optional,
164164
)
165-
from mypy.typestate import TypeState
165+
from mypy.typestate import type_state
166166
from mypy.typevars import fill_typevars
167167
from mypy.util import split_module_names
168168
from mypy.visitor import ExpressionVisitor
@@ -1591,13 +1591,13 @@ def allow_unions(self, type_context: Type) -> Iterator[None]:
15911591
# of joins. This is a bit arbitrary, but in practice it works for most
15921592
# cases. A cleaner alternative would be to switch to single bin type
15931593
# inference, but this is a lot of work.
1594-
old = TypeState.infer_unions
1594+
old = type_state.infer_unions
15951595
if has_recursive_types(type_context):
1596-
TypeState.infer_unions = True
1596+
type_state.infer_unions = True
15971597
try:
15981598
yield
15991599
finally:
1600-
TypeState.infer_unions = old
1600+
type_state.infer_unions = old
16011601

16021602
def infer_arg_types_in_context(
16031603
self,

mypy/constraints.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
is_named_instance,
4949
is_union_with_any,
5050
)
51-
from mypy.typestate import TypeState
51+
from mypy.typestate import type_state
5252
from mypy.typevartuples import (
5353
extract_unpack,
5454
find_unpack_in_list,
@@ -198,7 +198,7 @@ def infer_constraints(template: Type, actual: Type, direction: int) -> list[Cons
198198
if any(
199199
get_proper_type(template) == get_proper_type(t)
200200
and get_proper_type(actual) == get_proper_type(a)
201-
for (t, a) in reversed(TypeState.inferring)
201+
for (t, a) in reversed(type_state.inferring)
202202
):
203203
return []
204204
if has_recursive_types(template) or isinstance(get_proper_type(template), Instance):
@@ -207,9 +207,9 @@ def infer_constraints(template: Type, actual: Type, direction: int) -> list[Cons
207207
if not has_type_vars(template):
208208
# Return early on an empty branch.
209209
return []
210-
TypeState.inferring.append((template, actual))
210+
type_state.inferring.append((template, actual))
211211
res = _infer_constraints(template, actual, direction)
212-
TypeState.inferring.pop()
212+
type_state.inferring.pop()
213213
return res
214214
return _infer_constraints(template, actual, direction)
215215

mypy/mro.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from mypy.nodes import TypeInfo
66
from mypy.types import Instance
7-
from mypy.typestate import TypeState
7+
from mypy.typestate import type_state
88

99

1010
def calculate_mro(info: TypeInfo, obj_type: Callable[[], Instance] | None = None) -> None:
@@ -17,7 +17,7 @@ def calculate_mro(info: TypeInfo, obj_type: Callable[[], Instance] | None = None
1717
info.mro = mro
1818
# The property of falling back to Any is inherited.
1919
info.fallback_to_any = any(baseinfo.fallback_to_any for baseinfo in info.mro)
20-
TypeState.reset_all_subtype_caches_for(info)
20+
type_state.reset_all_subtype_caches_for(info)
2121

2222

2323
class MroError(Exception):

mypy/server/astmerge.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
UnionType,
111111
UnpackType,
112112
)
113-
from mypy.typestate import TypeState
113+
from mypy.typestate import type_state
114114
from mypy.util import get_prefix, replace_object_state
115115

116116

@@ -360,7 +360,7 @@ def fixup_and_reset_typeinfo(self, node: TypeInfo) -> TypeInfo:
360360
# The subclass relationships may change, so reset all caches relevant to the
361361
# old MRO.
362362
new = cast(TypeInfo, self.replacements[node])
363-
TypeState.reset_all_subtype_caches_for(new)
363+
type_state.reset_all_subtype_caches_for(new)
364364
return self.fixup(node)
365365

366366
def fixup_type(self, typ: Type | None) -> None:

mypy/server/aststrip.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
)
6767
from mypy.traverser import TraverserVisitor
6868
from mypy.types import CallableType
69-
from mypy.typestate import TypeState
69+
from mypy.typestate import type_state
7070

7171
SavedAttributes: _TypeAlias = Dict[Tuple[ClassDef, str], SymbolTableNode]
7272

@@ -143,7 +143,7 @@ def visit_class_def(self, node: ClassDef) -> None:
143143
super().visit_class_def(node)
144144
node.defs.body.extend(node.removed_statements)
145145
node.removed_statements = []
146-
TypeState.reset_subtype_caches_for(node.info)
146+
type_state.reset_subtype_caches_for(node.info)
147147
# Kill the TypeInfo, since there is none before semantic analysis.
148148
node.info = CLASSDEF_NO_INFO
149149
node.analyzed = None

mypy/server/deps.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ class 'mod.Cls'. This can also refer to an attribute inherited from a
172172
UnpackType,
173173
get_proper_type,
174174
)
175-
from mypy.typestate import TypeState
175+
from mypy.typestate import type_state
176176
from mypy.util import correct_relative_import
177177

178178

@@ -344,7 +344,7 @@ def process_type_info(self, info: TypeInfo) -> None:
344344
self.add_dependency(
345345
make_wildcard_trigger(base_info.fullname), target=make_trigger(target)
346346
)
347-
# More protocol dependencies are collected in TypeState._snapshot_protocol_deps
347+
# More protocol dependencies are collected in type_state._snapshot_protocol_deps
348348
# after a full run or update is finished.
349349

350350
self.add_type_alias_deps(self.scope.current_target())
@@ -1123,7 +1123,7 @@ def dump_all_dependencies(
11231123
deps = get_dependencies(node, type_map, python_version, options)
11241124
for trigger, targets in deps.items():
11251125
all_deps.setdefault(trigger, set()).update(targets)
1126-
TypeState.add_all_protocol_deps(all_deps)
1126+
type_state.add_all_protocol_deps(all_deps)
11271127

11281128
for trigger, targets in sorted(all_deps.items(), key=lambda x: x[0]):
11291129
print(trigger)

mypy/server/update.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@
157157
from mypy.server.deps import get_dependencies_of_target, merge_dependencies
158158
from mypy.server.target import trigger_to_target
159159
from mypy.server.trigger import WILDCARD_TAG, make_trigger
160-
from mypy.typestate import TypeState
160+
from mypy.typestate import type_state
161161
from mypy.util import module_prefix, split_target
162162

163163
MAX_ITER: Final = 1000
@@ -869,7 +869,7 @@ def propagate_changes_using_dependencies(
869869
# We need to do this to avoid false negatives if the protocol itself is
870870
# unchanged, but was marked stale because its sub- (or super-) type changed.
871871
for info in stale_protos:
872-
TypeState.reset_subtype_caches_for(info)
872+
type_state.reset_subtype_caches_for(info)
873873
# Then fully reprocess all targets.
874874
# TODO: Preserve order (set is not optimal)
875875
for id, nodes in sorted(todo.items(), key=lambda x: x[0]):
@@ -1081,7 +1081,7 @@ def update_deps(
10811081
for trigger, targets in new_deps.items():
10821082
deps.setdefault(trigger, set()).update(targets)
10831083
# Merge also the newly added protocol deps (if any).
1084-
TypeState.update_protocol_deps(deps)
1084+
type_state.update_protocol_deps(deps)
10851085

10861086

10871087
def lookup_target(

mypy/solve.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
UnionType,
1919
get_proper_type,
2020
)
21-
from mypy.typestate import TypeState
21+
from mypy.typestate import type_state
2222

2323

2424
def solve_constraints(
@@ -54,7 +54,7 @@ def solve_constraints(
5454
if bottom is None:
5555
bottom = c.target
5656
else:
57-
if TypeState.infer_unions:
57+
if type_state.infer_unions:
5858
# This deviates from the general mypy semantics because
5959
# recursive types are union-heavy in 95% of cases.
6060
bottom = UnionType.make_union([bottom, c.target])

mypy/subtypes.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
get_proper_type,
6161
is_named_instance,
6262
)
63-
from mypy.typestate import SubtypeKind, TypeState
63+
from mypy.typestate import SubtypeKind, type_state
6464
from mypy.typevars import fill_typevars_with_any
6565
from mypy.typevartuples import extract_unpack, fully_split_with_mapped_and_template
6666

@@ -154,7 +154,7 @@ def is_subtype(
154154
options,
155155
}
156156
), "Don't pass both context and individual flags"
157-
if TypeState.is_assumed_subtype(left, right):
157+
if type_state.is_assumed_subtype(left, right):
158158
return True
159159
if mypy.typeops.is_recursive_pair(left, right):
160160
# This case requires special care because it may cause infinite recursion.
@@ -174,7 +174,7 @@ def is_subtype(
174174
# B = Union[int, Tuple[B, ...]]
175175
# When checking if A <: B we push pair (A, B) onto 'assuming' stack, then when after few
176176
# steps we come back to initial call is_subtype(A, B) and immediately return True.
177-
with pop_on_exit(TypeState.get_assumptions(is_proper=False), left, right):
177+
with pop_on_exit(type_state.get_assumptions(is_proper=False), left, right):
178178
return _is_subtype(left, right, subtype_context, proper_subtype=False)
179179
return _is_subtype(left, right, subtype_context, proper_subtype=False)
180180

@@ -215,11 +215,11 @@ def is_proper_subtype(
215215
ignore_uninhabited,
216216
}
217217
), "Don't pass both context and individual flags"
218-
if TypeState.is_assumed_proper_subtype(left, right):
218+
if type_state.is_assumed_proper_subtype(left, right):
219219
return True
220220
if mypy.typeops.is_recursive_pair(left, right):
221221
# Same as for non-proper subtype, see detailed comment there for explanation.
222-
with pop_on_exit(TypeState.get_assumptions(is_proper=True), left, right):
222+
with pop_on_exit(type_state.get_assumptions(is_proper=True), left, right):
223223
return _is_subtype(left, right, subtype_context, proper_subtype=True)
224224
return _is_subtype(left, right, subtype_context, proper_subtype=True)
225225

@@ -445,14 +445,14 @@ def visit_instance(self, left: Instance) -> bool:
445445
if isinstance(right, TupleType) and mypy.typeops.tuple_fallback(right).type.is_enum:
446446
return self._is_subtype(left, mypy.typeops.tuple_fallback(right))
447447
if isinstance(right, Instance):
448-
if TypeState.is_cached_subtype_check(self._subtype_kind, left, right):
448+
if type_state.is_cached_subtype_check(self._subtype_kind, left, right):
449449
return True
450450
if not self.subtype_context.ignore_promotions:
451451
for base in left.type.mro:
452452
if base._promote and any(
453453
self._is_subtype(p, self.right) for p in base._promote
454454
):
455-
TypeState.record_subtype_cache_entry(self._subtype_kind, left, right)
455+
type_state.record_subtype_cache_entry(self._subtype_kind, left, right)
456456
return True
457457
# Special case: Low-level integer types are compatible with 'int'. We can't
458458
# use promotions, since 'int' is already promoted to low-level integer types,
@@ -589,7 +589,7 @@ def check_mixed(
589589
):
590590
nominal = False
591591
if nominal:
592-
TypeState.record_subtype_cache_entry(self._subtype_kind, left, right)
592+
type_state.record_subtype_cache_entry(self._subtype_kind, left, right)
593593
return nominal
594594
if right.type.is_protocol and is_protocol_implementation(
595595
left, right, proper_subtype=self.proper_subtype
@@ -978,7 +978,7 @@ def f(self) -> A: ...
978978
if skip is None:
979979
skip = []
980980
# We need to record this check to generate protocol fine-grained dependencies.
981-
TypeState.record_protocol_subtype_check(left.type, right.type)
981+
type_state.record_protocol_subtype_check(left.type, right.type)
982982
# nominal subtyping currently ignores '__init__' and '__new__' signatures
983983
members_not_to_check = {"__init__", "__new__"}
984984
members_not_to_check.update(skip)
@@ -1078,7 +1078,7 @@ def named_type(fullname: str) -> Instance:
10781078
subtype_context=SubtypeContext(ignore_pos_arg_names=ignore_names),
10791079
proper_subtype=proper_subtype,
10801080
)
1081-
TypeState.record_subtype_cache_entry(subtype_kind, left, right)
1081+
type_state.record_subtype_cache_entry(subtype_kind, left, right)
10821082
return True
10831083

10841084

0 commit comments

Comments
 (0)