Skip to content

Commit 861a307

Browse files
committed
Add shared checker interface to break import cycle
1 parent 1214a74 commit 861a307

File tree

7 files changed

+350
-120
lines changed

7 files changed

+350
-120
lines changed

mypy/checker.py

Lines changed: 3 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import mypy.checkexpr
1313
from mypy import errorcodes as codes, join, message_registry, nodes, operators
1414
from mypy.binder import ConditionalTypeBinder, Frame, get_declaration
15+
from mypy.checker_shared import CheckerScope, TypeCheckerSharedApi, TypeRange
1516
from mypy.checkmember import (
1617
MemberContext,
1718
analyze_class_attribute_access,
@@ -126,7 +127,7 @@
126127
from mypy.operators import flip_ops, int_op_to_method, neg_ops
127128
from mypy.options import PRECISE_TUPLE_TYPES, Options
128129
from mypy.patterns import AsPattern, StarredPattern
129-
from mypy.plugin import CheckerPluginInterface, Plugin
130+
from mypy.plugin import Plugin
130131
from mypy.plugins import dataclasses as dataclasses_plugin
131132
from mypy.scope import Scope
132133
from mypy.semanal import is_trivial_body, refers_to_fullname, set_callable_name
@@ -259,13 +260,6 @@ class FineGrainedDeferredNode(NamedTuple):
259260
TypeMap: _TypeAlias = Optional[dict[Expression, Type]]
260261

261262

262-
# An object that represents either a precise type or a type with an upper bound;
263-
# it is important for correct type inference with isinstance.
264-
class TypeRange(NamedTuple):
265-
item: Type
266-
is_upper_bound: bool # False => precise type
267-
268-
269263
# Keeps track of partial types in a single scope. In fine-grained incremental
270264
# mode partial types initially defined at the top level cannot be completed in
271265
# a function, and we use the 'is_function' attribute to enforce this.
@@ -275,7 +269,7 @@ class PartialTypeScope(NamedTuple):
275269
is_local: bool
276270

277271

278-
class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
272+
class TypeChecker(NodeVisitor[None], TypeCheckerSharedApi):
279273
"""Mypy type checker.
280274
281275
Type check mypy source files that have been semantically analyzed.
@@ -8572,75 +8566,6 @@ def is_node_static(node: Node | None) -> bool | None:
85728566
return None
85738567

85748568

8575-
class CheckerScope:
8576-
# We keep two stacks combined, to maintain the relative order
8577-
stack: list[TypeInfo | FuncItem | MypyFile]
8578-
8579-
def __init__(self, module: MypyFile) -> None:
8580-
self.stack = [module]
8581-
8582-
def current_function(self) -> FuncItem | None:
8583-
for e in reversed(self.stack):
8584-
if isinstance(e, FuncItem):
8585-
return e
8586-
return None
8587-
8588-
def top_level_function(self) -> FuncItem | None:
8589-
"""Return top-level non-lambda function."""
8590-
for e in self.stack:
8591-
if isinstance(e, FuncItem) and not isinstance(e, LambdaExpr):
8592-
return e
8593-
return None
8594-
8595-
def active_class(self) -> TypeInfo | None:
8596-
if isinstance(self.stack[-1], TypeInfo):
8597-
return self.stack[-1]
8598-
return None
8599-
8600-
def enclosing_class(self, func: FuncItem | None = None) -> TypeInfo | None:
8601-
"""Is there a class *directly* enclosing this function?"""
8602-
func = func or self.current_function()
8603-
assert func, "This method must be called from inside a function"
8604-
index = self.stack.index(func)
8605-
assert index, "CheckerScope stack must always start with a module"
8606-
enclosing = self.stack[index - 1]
8607-
if isinstance(enclosing, TypeInfo):
8608-
return enclosing
8609-
return None
8610-
8611-
def active_self_type(self) -> Instance | TupleType | None:
8612-
"""An instance or tuple type representing the current class.
8613-
8614-
This returns None unless we are in class body or in a method.
8615-
In particular, inside a function nested in method this returns None.
8616-
"""
8617-
info = self.active_class()
8618-
if not info and self.current_function():
8619-
info = self.enclosing_class()
8620-
if info:
8621-
return fill_typevars(info)
8622-
return None
8623-
8624-
def current_self_type(self) -> Instance | TupleType | None:
8625-
"""Same as active_self_type() but handle functions nested in methods."""
8626-
for item in reversed(self.stack):
8627-
if isinstance(item, TypeInfo):
8628-
return fill_typevars(item)
8629-
return None
8630-
8631-
@contextmanager
8632-
def push_function(self, item: FuncItem) -> Iterator[None]:
8633-
self.stack.append(item)
8634-
yield
8635-
self.stack.pop()
8636-
8637-
@contextmanager
8638-
def push_class(self, info: TypeInfo) -> Iterator[None]:
8639-
self.stack.append(info)
8640-
yield
8641-
self.stack.pop()
8642-
8643-
86448569
TKey = TypeVar("TKey")
86458570
TValue = TypeVar("TValue")
86468571

0 commit comments

Comments
 (0)