forked from python/mypy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsemanal_shared.py
214 lines (168 loc) · 6.99 KB
/
semanal_shared.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
"""Shared definitions used by different parts of semantic analysis."""
from abc import abstractmethod
from typing import Optional, List, Callable
from typing_extensions import Final
from mypy_extensions import trait
from mypy.nodes import (
Context, SymbolTableNode, FuncDef, Node, TypeInfo, Expression,
SymbolNode, SymbolTable
)
from mypy.types import (
Type, FunctionLike, Instance, TupleType, TPDICT_FB_NAMES, ProperType, get_proper_type
)
from mypy.tvar_scope import TypeVarLikeScope
from mypy.errorcodes import ErrorCode
from mypy import join
# Priorities for ordering of patches within the "patch" phase of semantic analysis
# (after the main pass):
# Fix fallbacks (does joins)
PRIORITY_FALLBACKS: Final = 1
@trait
class SemanticAnalyzerCoreInterface:
"""A core abstract interface to generic semantic analyzer functionality.
This is implemented by both semantic analyzer passes 2 and 3.
"""
@abstractmethod
def lookup_qualified(self, name: str, ctx: Context,
suppress_errors: bool = False) -> Optional[SymbolTableNode]:
raise NotImplementedError
@abstractmethod
def lookup_fully_qualified(self, name: str) -> SymbolTableNode:
raise NotImplementedError
@abstractmethod
def lookup_fully_qualified_or_none(self, name: str) -> Optional[SymbolTableNode]:
raise NotImplementedError
@abstractmethod
def fail(self, msg: str, ctx: Context, serious: bool = False, *,
blocker: bool = False, code: Optional[ErrorCode] = None) -> None:
raise NotImplementedError
@abstractmethod
def note(self, msg: str, ctx: Context, *, code: Optional[ErrorCode] = None) -> None:
raise NotImplementedError
@abstractmethod
def record_incomplete_ref(self) -> None:
raise NotImplementedError
@abstractmethod
def defer(self) -> None:
raise NotImplementedError
@abstractmethod
def is_incomplete_namespace(self, fullname: str) -> bool:
"""Is a module or class namespace potentially missing some definitions?"""
raise NotImplementedError
@property
@abstractmethod
def final_iteration(self) -> bool:
"""Is this the final iteration of semantic analysis?"""
raise NotImplementedError
@abstractmethod
def is_future_flag_set(self, flag: str) -> bool:
"""Is the specific __future__ feature imported"""
raise NotImplementedError
@property
@abstractmethod
def is_stub_file(self) -> bool:
raise NotImplementedError
@trait
class SemanticAnalyzerInterface(SemanticAnalyzerCoreInterface):
"""A limited abstract interface to some generic semantic analyzer pass 2 functionality.
We use this interface for various reasons:
* Looser coupling
* Cleaner import graph
* Less need to pass around callback functions
"""
@abstractmethod
def lookup(self, name: str, ctx: Context,
suppress_errors: bool = False) -> Optional[SymbolTableNode]:
raise NotImplementedError
@abstractmethod
def named_type(self, fullname: str,
args: Optional[List[Type]] = None) -> Instance:
raise NotImplementedError
@abstractmethod
def named_type_or_none(self, fullname: str,
args: Optional[List[Type]] = None) -> Optional[Instance]:
raise NotImplementedError
@abstractmethod
def accept(self, node: Node) -> None:
raise NotImplementedError
@abstractmethod
def anal_type(self, t: Type, *,
tvar_scope: Optional[TypeVarLikeScope] = None,
allow_tuple_literal: bool = False,
allow_unbound_tvars: bool = False,
allow_required: bool = False,
report_invalid_types: bool = True) -> Optional[Type]:
raise NotImplementedError
@abstractmethod
def basic_new_typeinfo(self, name: str, basetype_or_fallback: Instance, line: int) -> TypeInfo:
raise NotImplementedError
@abstractmethod
def schedule_patch(self, priority: int, fn: Callable[[], None]) -> None:
raise NotImplementedError
@abstractmethod
def add_symbol_table_node(self, name: str, stnode: SymbolTableNode) -> bool:
"""Add node to the current symbol table."""
raise NotImplementedError
@abstractmethod
def current_symbol_table(self) -> SymbolTable:
"""Get currently active symbol table.
May be module, class, or local namespace.
"""
raise NotImplementedError
@abstractmethod
def add_symbol(self, name: str, node: SymbolNode, context: Context,
module_public: bool = True, module_hidden: bool = False,
can_defer: bool = True) -> bool:
"""Add symbol to the current symbol table."""
raise NotImplementedError
@abstractmethod
def add_symbol_skip_local(self, name: str, node: SymbolNode) -> None:
"""Add symbol to the current symbol table, skipping locals.
This is used to store symbol nodes in a symbol table that
is going to be serialized (local namespaces are not serialized).
See implementation docstring for more details.
"""
raise NotImplementedError
@abstractmethod
def parse_bool(self, expr: Expression) -> Optional[bool]:
raise NotImplementedError
@abstractmethod
def qualified_name(self, n: str) -> str:
raise NotImplementedError
@property
@abstractmethod
def is_typeshed_stub_file(self) -> bool:
raise NotImplementedError
@abstractmethod
def is_func_scope(self) -> bool:
raise NotImplementedError
def set_callable_name(sig: Type, fdef: FuncDef) -> ProperType:
sig = get_proper_type(sig)
if isinstance(sig, FunctionLike):
if fdef.info:
if fdef.info.fullname in TPDICT_FB_NAMES:
# Avoid exposing the internal _TypedDict name.
class_name = 'TypedDict'
else:
class_name = fdef.info.name
return sig.with_name(
'{} of {}'.format(fdef.name, class_name))
else:
return sig.with_name(fdef.name)
else:
return sig
def calculate_tuple_fallback(typ: TupleType) -> None:
"""Calculate a precise item type for the fallback of a tuple type.
This must be called only after the main semantic analysis pass, since joins
aren't available before that.
Note that there is an apparent chicken and egg problem with respect
to verifying type arguments against bounds. Verifying bounds might
require fallbacks, but we might use the bounds to calculate the
fallbacks. In practice this is not a problem, since the worst that
can happen is that we have invalid type argument values, and these
can happen in later stages as well (they will generate errors, but
we don't prevent their existence).
"""
fallback = typ.partial_fallback
assert fallback.type.fullname == 'builtins.tuple'
fallback.args = (join.join_type_list(list(typ.items)),) + fallback.args[1:]