cinderx 2026.1.16.2__cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- __static__/__init__.py +641 -0
- __static__/compiler_flags.py +8 -0
- __static__/enum.py +160 -0
- __static__/native_utils.py +77 -0
- __static__/type_code.py +48 -0
- __strict__/__init__.py +39 -0
- _cinderx.so +0 -0
- cinderx/__init__.py +577 -0
- cinderx/__pycache__/__init__.cpython-314.pyc +0 -0
- cinderx/_asyncio.py +156 -0
- cinderx/compileall.py +710 -0
- cinderx/compiler/__init__.py +40 -0
- cinderx/compiler/__main__.py +137 -0
- cinderx/compiler/config.py +7 -0
- cinderx/compiler/consts.py +72 -0
- cinderx/compiler/debug.py +70 -0
- cinderx/compiler/dis_stable.py +283 -0
- cinderx/compiler/errors.py +151 -0
- cinderx/compiler/flow_graph_optimizer.py +1287 -0
- cinderx/compiler/future.py +91 -0
- cinderx/compiler/misc.py +32 -0
- cinderx/compiler/opcode_cinder.py +18 -0
- cinderx/compiler/opcode_static.py +100 -0
- cinderx/compiler/opcodebase.py +158 -0
- cinderx/compiler/opcodes.py +991 -0
- cinderx/compiler/optimizer.py +547 -0
- cinderx/compiler/pyassem.py +3711 -0
- cinderx/compiler/pycodegen.py +7660 -0
- cinderx/compiler/pysourceloader.py +62 -0
- cinderx/compiler/static/__init__.py +1404 -0
- cinderx/compiler/static/compiler.py +629 -0
- cinderx/compiler/static/declaration_visitor.py +335 -0
- cinderx/compiler/static/definite_assignment_checker.py +280 -0
- cinderx/compiler/static/effects.py +160 -0
- cinderx/compiler/static/module_table.py +666 -0
- cinderx/compiler/static/type_binder.py +2176 -0
- cinderx/compiler/static/types.py +10580 -0
- cinderx/compiler/static/util.py +81 -0
- cinderx/compiler/static/visitor.py +91 -0
- cinderx/compiler/strict/__init__.py +69 -0
- cinderx/compiler/strict/class_conflict_checker.py +249 -0
- cinderx/compiler/strict/code_gen_base.py +409 -0
- cinderx/compiler/strict/common.py +507 -0
- cinderx/compiler/strict/compiler.py +352 -0
- cinderx/compiler/strict/feature_extractor.py +130 -0
- cinderx/compiler/strict/flag_extractor.py +97 -0
- cinderx/compiler/strict/loader.py +827 -0
- cinderx/compiler/strict/preprocessor.py +11 -0
- cinderx/compiler/strict/rewriter/__init__.py +5 -0
- cinderx/compiler/strict/rewriter/remove_annotations.py +84 -0
- cinderx/compiler/strict/rewriter/rewriter.py +975 -0
- cinderx/compiler/strict/runtime.py +77 -0
- cinderx/compiler/symbols.py +1754 -0
- cinderx/compiler/unparse.py +414 -0
- cinderx/compiler/visitor.py +194 -0
- cinderx/jit.py +230 -0
- cinderx/opcode.py +202 -0
- cinderx/static.py +113 -0
- cinderx/strictmodule.py +6 -0
- cinderx/test_support.py +341 -0
- cinderx-2026.1.16.2.dist-info/METADATA +15 -0
- cinderx-2026.1.16.2.dist-info/RECORD +68 -0
- cinderx-2026.1.16.2.dist-info/WHEEL +6 -0
- cinderx-2026.1.16.2.dist-info/licenses/LICENSE +21 -0
- cinderx-2026.1.16.2.dist-info/top_level.txt +5 -0
- opcodes/__init__.py +0 -0
- opcodes/assign_opcode_numbers.py +272 -0
- opcodes/cinderx_opcodes.py +121 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
# pyre-strict
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import ast
|
|
7
|
+
import sys
|
|
8
|
+
from typing import Callable, Mapping
|
|
9
|
+
|
|
10
|
+
COMPARE_OPS: Mapping[type[ast.cmpop], Callable[[object, object], bool]] = {
|
|
11
|
+
ast.Gt: lambda a, b: a > b,
|
|
12
|
+
ast.GtE: lambda a, b: a >= b,
|
|
13
|
+
ast.Lt: lambda a, b: a < b,
|
|
14
|
+
ast.LtE: lambda a, b: a <= b,
|
|
15
|
+
ast.Eq: lambda a, b: a == b,
|
|
16
|
+
ast.NotEq: lambda a, b: a != b,
|
|
17
|
+
ast.In: lambda a, b: a in b,
|
|
18
|
+
ast.Is: lambda a, b: a is b,
|
|
19
|
+
ast.IsNot: lambda a, b: a is not b,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def make_qualname(parent_qualname: str | None, name: str) -> str:
|
|
24
|
+
if parent_qualname is None:
|
|
25
|
+
return name
|
|
26
|
+
return f"{parent_qualname}.{name}"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _is_sys_hexversion_attr_load(node: ast.expr) -> bool:
|
|
30
|
+
if isinstance(node, ast.Attribute):
|
|
31
|
+
container = node.value
|
|
32
|
+
if (
|
|
33
|
+
isinstance(container, ast.Name)
|
|
34
|
+
and container.id == "sys"
|
|
35
|
+
and isinstance(node.ctx, ast.Load)
|
|
36
|
+
and node.attr == "hexversion"
|
|
37
|
+
):
|
|
38
|
+
return True
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _get_const_int(node: ast.expr) -> int | None:
|
|
43
|
+
if isinstance(node, ast.Constant):
|
|
44
|
+
value = node.value
|
|
45
|
+
return value if isinstance(value, int) else None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def sys_hexversion_check(
|
|
49
|
+
node: ast.If,
|
|
50
|
+
) -> bool | None:
|
|
51
|
+
"""
|
|
52
|
+
A helper function, the result of this is used to determine whether
|
|
53
|
+
we need to skip visiting dead code gated by sys.hexversion checks.
|
|
54
|
+
"""
|
|
55
|
+
test_node = node.test
|
|
56
|
+
if isinstance(test_node, ast.Compare):
|
|
57
|
+
if len(test_node.comparators) != 1:
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
assert len(test_node.ops) == 1
|
|
61
|
+
|
|
62
|
+
left = test_node.left
|
|
63
|
+
right = test_node.comparators[0]
|
|
64
|
+
op = test_node.ops[0]
|
|
65
|
+
|
|
66
|
+
if type(op) in (ast.In, ast.Is, ast.IsNot):
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
if _is_sys_hexversion_attr_load(left):
|
|
70
|
+
left_value = sys.hexversion
|
|
71
|
+
right_value = _get_const_int(right)
|
|
72
|
+
elif _is_sys_hexversion_attr_load(right):
|
|
73
|
+
left_value = _get_const_int(left)
|
|
74
|
+
right_value = sys.hexversion
|
|
75
|
+
else:
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
if left_value is None or right_value is None:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
return COMPARE_OPS[type(op)](left_value, right_value)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
# pyre-strict
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from ast import AST
|
|
7
|
+
from contextlib import contextmanager, nullcontext
|
|
8
|
+
from typing import ContextManager, Generator, Generic, Sequence, TYPE_CHECKING, TypeVar
|
|
9
|
+
|
|
10
|
+
from ..visitor import ASTVisitor
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from ..errors import ErrorSink
|
|
14
|
+
from .compiler import Compiler
|
|
15
|
+
from .module_table import ModuleTable
|
|
16
|
+
from .types import TypeEnvironment
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
TVisitRet = TypeVar("TVisitRet", covariant=True)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class GenericVisitor(ASTVisitor, Generic[TVisitRet]):
|
|
23
|
+
def __init__(self, module: ModuleTable) -> None:
|
|
24
|
+
super().__init__()
|
|
25
|
+
self.module = module
|
|
26
|
+
self.module_name: str = module.name
|
|
27
|
+
self.filename: str = module.filename
|
|
28
|
+
self.compiler: Compiler = module.compiler
|
|
29
|
+
self.error_sink: ErrorSink = module.compiler.error_sink
|
|
30
|
+
self.type_env: TypeEnvironment = module.compiler.type_env
|
|
31
|
+
# the qualname that should be the "requester" of types used (for dep tracking)
|
|
32
|
+
self._context_qualname: str = ""
|
|
33
|
+
# if true, all deps tracked in visiting should be considered decl deps
|
|
34
|
+
self.force_decl_deps: bool = False
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def context_qualname(self) -> str:
|
|
38
|
+
return self._context_qualname
|
|
39
|
+
|
|
40
|
+
@contextmanager
|
|
41
|
+
def temporary_context_qualname(
|
|
42
|
+
self, qualname: str | None, force_decl: bool = False
|
|
43
|
+
) -> Generator[None, None, None]:
|
|
44
|
+
old_qualname = self._context_qualname
|
|
45
|
+
self._context_qualname = qualname or ""
|
|
46
|
+
old_decl = self.force_decl_deps
|
|
47
|
+
self.force_decl_deps = force_decl
|
|
48
|
+
try:
|
|
49
|
+
yield
|
|
50
|
+
finally:
|
|
51
|
+
self._context_qualname = old_qualname
|
|
52
|
+
self.force_decl_deps = old_decl
|
|
53
|
+
|
|
54
|
+
def record_dependency(self, source: tuple[str, str]) -> None:
|
|
55
|
+
self.module.record_dependency(
|
|
56
|
+
self.context_qualname, source, force_decl=self.force_decl_deps
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def visit(self, node: AST, *args: object) -> TVisitRet:
|
|
60
|
+
# if we have a sequence of nodes, don't catch TypedSyntaxError here;
|
|
61
|
+
# walk_list will call us back with each individual node in turn and we
|
|
62
|
+
# can catch errors and add node info then.
|
|
63
|
+
ctx = self.error_context(node) if isinstance(node, AST) else nullcontext()
|
|
64
|
+
with ctx:
|
|
65
|
+
if not args:
|
|
66
|
+
# pyre-ignore: ASTVisitor is not generic yet, can't assert the result is
|
|
67
|
+
# TVisitRet.
|
|
68
|
+
return super().visit(node)
|
|
69
|
+
# pyre-ignore: ASTVisitor is not generic yet, can't assert the result is
|
|
70
|
+
# TVisitRet.
|
|
71
|
+
return super().visit(node, *args)
|
|
72
|
+
|
|
73
|
+
def syntax_error(self, msg: str, node: AST) -> None:
|
|
74
|
+
return self.error_sink.syntax_error(msg, self.filename, node)
|
|
75
|
+
|
|
76
|
+
def perf_warning(self, msg: str, node: AST) -> None:
|
|
77
|
+
return self.error_sink.perf_warning(msg, self.filename, node)
|
|
78
|
+
|
|
79
|
+
def error_context(self, node: AST | None) -> ContextManager[None]:
|
|
80
|
+
if node is None:
|
|
81
|
+
return nullcontext()
|
|
82
|
+
return self.error_sink.error_context(self.filename, node)
|
|
83
|
+
|
|
84
|
+
@contextmanager
|
|
85
|
+
def temporary_error_sink(self, sink: ErrorSink) -> Generator[None, None, None]:
|
|
86
|
+
orig_sink = self.error_sink
|
|
87
|
+
self.error_sink = sink
|
|
88
|
+
try:
|
|
89
|
+
yield
|
|
90
|
+
finally:
|
|
91
|
+
self.error_sink = orig_sink
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
# pyre-strict
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import ast
|
|
8
|
+
import builtins
|
|
9
|
+
import sys
|
|
10
|
+
from types import CodeType
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from ..pyassem import (
|
|
14
|
+
PyFlowGraph312,
|
|
15
|
+
PyFlowGraph314,
|
|
16
|
+
PyFlowGraph315,
|
|
17
|
+
PyFlowGraphCinder310,
|
|
18
|
+
)
|
|
19
|
+
from ..pycodegen import (
|
|
20
|
+
CinderCodeGenerator310,
|
|
21
|
+
CinderCodeGenerator312,
|
|
22
|
+
CinderCodeGenerator314,
|
|
23
|
+
CinderCodeGenerator315,
|
|
24
|
+
)
|
|
25
|
+
from .code_gen_base import StrictCodeGenBase
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# Unused but still present until we remove it from IGSRV
|
|
29
|
+
enable_strict_features: bool = True
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class StrictCodeGenerator310(StrictCodeGenBase, CinderCodeGenerator310):
|
|
33
|
+
flow_graph = PyFlowGraphCinder310
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class StrictCodeGenerator312(StrictCodeGenBase, CinderCodeGenerator312):
|
|
37
|
+
flow_graph = PyFlowGraph312
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class StrictCodeGenerator314(StrictCodeGenerator312, CinderCodeGenerator314):
|
|
41
|
+
flow_graph = PyFlowGraph314
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class StrictCodeGenerator315(StrictCodeGenerator312, CinderCodeGenerator315):
|
|
45
|
+
flow_graph = PyFlowGraph315
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def strict_compile(
|
|
49
|
+
name: str,
|
|
50
|
+
filename: str,
|
|
51
|
+
tree: ast.Module,
|
|
52
|
+
source: str | bytes,
|
|
53
|
+
optimize: int = 0,
|
|
54
|
+
builtins: dict[str, Any] = builtins.__dict__,
|
|
55
|
+
) -> CodeType:
|
|
56
|
+
code_gen = StrictCodeGenerator.make_code_gen(
|
|
57
|
+
name, tree, filename, source, flags=0, optimize=optimize, builtins=builtins
|
|
58
|
+
)
|
|
59
|
+
return code_gen.getCode()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if sys.version_info >= (3, 15):
|
|
63
|
+
StrictCodeGenerator = StrictCodeGenerator315
|
|
64
|
+
elif sys.version_info >= (3, 14):
|
|
65
|
+
StrictCodeGenerator = StrictCodeGenerator314
|
|
66
|
+
elif sys.version_info >= (3, 12):
|
|
67
|
+
StrictCodeGenerator = StrictCodeGenerator312
|
|
68
|
+
else:
|
|
69
|
+
StrictCodeGenerator = StrictCodeGenerator310
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
# pyre-strict
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import ast
|
|
8
|
+
from ast import (
|
|
9
|
+
AnnAssign,
|
|
10
|
+
Assign,
|
|
11
|
+
AST,
|
|
12
|
+
AsyncFunctionDef,
|
|
13
|
+
Attribute,
|
|
14
|
+
ClassDef,
|
|
15
|
+
Delete,
|
|
16
|
+
ExceptHandler,
|
|
17
|
+
FunctionDef,
|
|
18
|
+
Global,
|
|
19
|
+
Import,
|
|
20
|
+
ImportFrom,
|
|
21
|
+
Module,
|
|
22
|
+
Name,
|
|
23
|
+
)
|
|
24
|
+
from symtable import SymbolTable
|
|
25
|
+
from typing import final, MutableMapping
|
|
26
|
+
|
|
27
|
+
from ..consts import CO_FUTURE_ANNOTATIONS
|
|
28
|
+
from ..pycodegen import find_futures
|
|
29
|
+
from .common import (
|
|
30
|
+
get_symbol_map,
|
|
31
|
+
imported_name,
|
|
32
|
+
ScopeStack,
|
|
33
|
+
StrictModuleError,
|
|
34
|
+
SymbolMap,
|
|
35
|
+
SymbolScope,
|
|
36
|
+
)
|
|
37
|
+
from .rewriter.rewriter import SymbolVisitor
|
|
38
|
+
|
|
39
|
+
CLASS_ATTR_CONFLICT_EXCEPTION = "ClassAttributesConflictException"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TransformerScope:
|
|
43
|
+
def visit_Assign(self, node: Assign) -> None:
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
def visit_AnnAssign(self, node: AnnAssign) -> None:
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
def loaded(self, name: str) -> None:
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
def stored(self, name: str) -> None:
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@final
|
|
57
|
+
class ClassScope(TransformerScope):
|
|
58
|
+
def __init__(self) -> None:
|
|
59
|
+
self.instance_fields: set[str] = set()
|
|
60
|
+
self.class_fields: set[str] = set()
|
|
61
|
+
|
|
62
|
+
def visit_AnnAssign(self, node: AnnAssign) -> None:
|
|
63
|
+
target = node.target
|
|
64
|
+
if isinstance(target, Name):
|
|
65
|
+
if node.value is None:
|
|
66
|
+
self.instance_fields.add(target.id)
|
|
67
|
+
else:
|
|
68
|
+
self.class_fields.add(target.id)
|
|
69
|
+
|
|
70
|
+
def stored(self, name: str) -> None:
|
|
71
|
+
self.class_fields.add(name)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@final
|
|
75
|
+
class FunctionScope(TransformerScope):
|
|
76
|
+
def __init__(self, node: FunctionDef, parent: TransformerScope) -> None:
|
|
77
|
+
self.node = node
|
|
78
|
+
self.parent = parent
|
|
79
|
+
|
|
80
|
+
def visit_AnnAssign(self, node: AnnAssign) -> None:
|
|
81
|
+
parent = self.parent
|
|
82
|
+
target = node.target
|
|
83
|
+
if (
|
|
84
|
+
isinstance(self.node, FunctionDef)
|
|
85
|
+
and self.node.name == "__init__"
|
|
86
|
+
and self.node.args.args
|
|
87
|
+
and isinstance(parent, ClassScope)
|
|
88
|
+
and isinstance(target, Attribute)
|
|
89
|
+
):
|
|
90
|
+
self.add_attr_name(target, parent)
|
|
91
|
+
|
|
92
|
+
def add_attr_name(self, target: Attribute, parent: ClassScope) -> None:
|
|
93
|
+
"""records self.name = ... when salf matches the 1st parameter"""
|
|
94
|
+
value = target.value
|
|
95
|
+
node = self.node
|
|
96
|
+
if (
|
|
97
|
+
isinstance(node, FunctionDef)
|
|
98
|
+
and isinstance(value, Name)
|
|
99
|
+
and value.id == node.args.args[0].arg
|
|
100
|
+
):
|
|
101
|
+
parent.instance_fields.add(target.attr)
|
|
102
|
+
|
|
103
|
+
def visit_Assign(self, node: Assign) -> None:
|
|
104
|
+
parent = self.parent
|
|
105
|
+
if (
|
|
106
|
+
isinstance(self.node, FunctionDef)
|
|
107
|
+
and self.node.name == "__init__"
|
|
108
|
+
and isinstance(parent, ClassScope)
|
|
109
|
+
and self.node.args.args
|
|
110
|
+
):
|
|
111
|
+
for target in node.targets:
|
|
112
|
+
if not isinstance(target, Attribute):
|
|
113
|
+
continue
|
|
114
|
+
self.add_attr_name(target, parent)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@final
|
|
118
|
+
class ClassConflictChecker(SymbolVisitor[object, TransformerScope]):
|
|
119
|
+
def __init__(
|
|
120
|
+
self,
|
|
121
|
+
symbols: SymbolTable,
|
|
122
|
+
symbol_map: SymbolMap,
|
|
123
|
+
filename: str,
|
|
124
|
+
flags: int,
|
|
125
|
+
) -> None:
|
|
126
|
+
super().__init__(
|
|
127
|
+
ScopeStack(
|
|
128
|
+
self.make_scope(symbols, None),
|
|
129
|
+
symbol_map=symbol_map,
|
|
130
|
+
scope_factory=self.make_scope,
|
|
131
|
+
),
|
|
132
|
+
)
|
|
133
|
+
self.filename = filename
|
|
134
|
+
self.flags = flags
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def skip_annotations(self) -> bool:
|
|
138
|
+
return bool(self.flags & CO_FUTURE_ANNOTATIONS)
|
|
139
|
+
|
|
140
|
+
def error(self, names: list[str], lineno: int, col: int, filename: str) -> None:
|
|
141
|
+
MSG: str = "Class member conflicts with instance member: {names}"
|
|
142
|
+
raise StrictModuleError(MSG.format(names=names), filename, lineno, col)
|
|
143
|
+
|
|
144
|
+
def make_scope(
|
|
145
|
+
self,
|
|
146
|
+
symtable: SymbolTable,
|
|
147
|
+
node: AST | None,
|
|
148
|
+
vars: MutableMapping[str, object] | None = None,
|
|
149
|
+
) -> SymbolScope[object, TransformerScope]:
|
|
150
|
+
if isinstance(node, FunctionDef):
|
|
151
|
+
data = FunctionScope(node, self.scopes.scopes[-1].scope_data)
|
|
152
|
+
elif isinstance(node, ClassDef):
|
|
153
|
+
data = ClassScope()
|
|
154
|
+
else:
|
|
155
|
+
data = TransformerScope()
|
|
156
|
+
return SymbolScope(symtable, data)
|
|
157
|
+
|
|
158
|
+
def visit_Name(self, node: Name) -> None:
|
|
159
|
+
scope = self.scope_for(node.id).scope_data
|
|
160
|
+
if isinstance(node.ctx, ast.Load):
|
|
161
|
+
scope.loaded(node.id)
|
|
162
|
+
else:
|
|
163
|
+
scope.stored(node.id)
|
|
164
|
+
|
|
165
|
+
def visit_ExceptHandler(self, node: ExceptHandler) -> None:
|
|
166
|
+
self.generic_visit(node)
|
|
167
|
+
name = node.name
|
|
168
|
+
if name is not None:
|
|
169
|
+
self.scope_for(name).scope_data.stored(name)
|
|
170
|
+
|
|
171
|
+
def visit_Delete(self, node: Delete) -> None:
|
|
172
|
+
for target in node.targets:
|
|
173
|
+
if isinstance(target, ast.Name):
|
|
174
|
+
self.scope_for(target.id).scope_data.stored(target.id)
|
|
175
|
+
|
|
176
|
+
def visit_Global(self, node: Global) -> None:
|
|
177
|
+
if self.scopes.in_class_scope:
|
|
178
|
+
for name in node.names:
|
|
179
|
+
if name == "__annotations__":
|
|
180
|
+
self.error(
|
|
181
|
+
["__annotations__"], node.lineno, node.col_offset, self.filename
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
def visit_ClassDef(self, node: ClassDef) -> None:
|
|
185
|
+
self.visit_Class_Outer(node)
|
|
186
|
+
class_scope = self.visit_Class_Inner(node).scope_data
|
|
187
|
+
assert isinstance(class_scope, ClassScope)
|
|
188
|
+
|
|
189
|
+
overlap = class_scope.instance_fields.intersection(class_scope.class_fields)
|
|
190
|
+
if overlap:
|
|
191
|
+
self.error(list(overlap), node.lineno, node.col_offset, self.filename)
|
|
192
|
+
|
|
193
|
+
self.scope_for(node.name).scope_data.stored(node.name)
|
|
194
|
+
|
|
195
|
+
def visit_FunctionDef(self, node: FunctionDef) -> None:
|
|
196
|
+
self.visit_Func_Outer(node)
|
|
197
|
+
|
|
198
|
+
func_scope = self.visit_Func_Inner(node)
|
|
199
|
+
|
|
200
|
+
self.scopes.current[node.name] = func_scope.scope_data
|
|
201
|
+
|
|
202
|
+
self.scope_for(node.name).scope_data.stored(node.name)
|
|
203
|
+
|
|
204
|
+
def visit_AsyncFunctionDef(self, node: AsyncFunctionDef) -> None:
|
|
205
|
+
self.visit_Func_Outer(node)
|
|
206
|
+
|
|
207
|
+
self.visit_Func_Inner(node)
|
|
208
|
+
|
|
209
|
+
self.scope_for(node.name).scope_data.stored(node.name)
|
|
210
|
+
|
|
211
|
+
def visit_Import(self, node: Import) -> None:
|
|
212
|
+
for name in node.names:
|
|
213
|
+
self.scope_for(imported_name(name)).scope_data.stored(imported_name(name))
|
|
214
|
+
return self.generic_visit(node)
|
|
215
|
+
|
|
216
|
+
def visit_ImportFrom(self, node: ImportFrom) -> None:
|
|
217
|
+
if node.level == 0 and node.module is not None:
|
|
218
|
+
for name in node.names:
|
|
219
|
+
self.scope_for(name.asname or name.name).scope_data.stored(
|
|
220
|
+
name.asname or name.name
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
def visit_Assign(self, node: Assign) -> None:
|
|
224
|
+
self.scopes.scopes[-1].scope_data.visit_Assign(node)
|
|
225
|
+
self.generic_visit(node)
|
|
226
|
+
|
|
227
|
+
def visit_AnnAssign(self, node: AnnAssign) -> None:
|
|
228
|
+
self.scopes.scopes[-1].scope_data.visit_AnnAssign(node)
|
|
229
|
+
value = node.value
|
|
230
|
+
if value is not None:
|
|
231
|
+
self.visit(node.target)
|
|
232
|
+
self.visit(value)
|
|
233
|
+
if not self.skip_annotations:
|
|
234
|
+
self.visit(node.annotation)
|
|
235
|
+
|
|
236
|
+
def visit_arg(self, node: ast.arg) -> None:
|
|
237
|
+
if not self.skip_annotations:
|
|
238
|
+
self.generic_visit(node)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def check_class_conflict(
|
|
242
|
+
node: Module,
|
|
243
|
+
filename: str,
|
|
244
|
+
symbols: SymbolTable,
|
|
245
|
+
) -> None:
|
|
246
|
+
symbol_map = get_symbol_map(node, symbols)
|
|
247
|
+
flags = find_futures(0, node)
|
|
248
|
+
visitor = ClassConflictChecker(symbols, symbol_map, filename=filename, flags=flags)
|
|
249
|
+
visitor.visit(node)
|