Skip to content

Commit abc228e

Browse files
elazargJukkaL
authored andcommitted
Turn literal and literal_hash into functions (#3071)
This PR groups the handling of literal/literal_hash in one place, and removes the auxiliary attributes. I think it is clearer this way, and removes clutter from nodes.py. It is easier to check for consistency (e.g. serialization is not possible at all).
1 parent 7018ca0 commit abc228e

File tree

6 files changed

+266
-123
lines changed

6 files changed

+266
-123
lines changed

mypy/binder.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22
from contextlib import contextmanager
33

44
from mypy.types import Type, AnyType, PartialType, UnionType, TypeOfAny
5-
from mypy.nodes import (Key, Expression, Var, RefExpr)
6-
75
from mypy.subtypes import is_subtype
86
from mypy.join import join_simple
97
from mypy.sametypes import is_same_type
10-
8+
from mypy.nodes import Expression, Var, RefExpr
9+
from mypy.literals import Key, literal, literal_hash, subkeys
1110
from mypy.nodes import IndexExpr, MemberExpr, NameExpr
1211

1312

@@ -61,7 +60,7 @@ class A:
6160

6261
def __init__(self) -> None:
6362
# The stack of frames currently used. These map
64-
# expr.literal_hash -- literals like 'foo.bar' --
63+
# literal_hash(expr) -- literals like 'foo.bar' --
6564
# to types. The last element of this list is the
6665
# top-most, current frame. Each earlier element
6766
# records the state as of when that frame was last
@@ -75,7 +74,7 @@ def __init__(self) -> None:
7574
# has no corresponding element in this list.
7675
self.options_on_return = [] # type: List[List[Frame]]
7776

78-
# Maps expr.literal_hash to get_declaration(expr)
77+
# Maps literal_hash(expr) to get_declaration(expr)
7978
# for every expr stored in the binder
8079
self.declarations = DeclarationsFrame()
8180
# Set of other keys to invalidate if a key is changed, e.g. x -> {x.a, x[0]}
@@ -94,9 +93,8 @@ def _add_dependencies(self, key: Key, value: Optional[Key] = None) -> None:
9493
value = key
9594
else:
9695
self.dependencies.setdefault(key, set()).add(value)
97-
for elt in key:
98-
if isinstance(elt, Key):
99-
self._add_dependencies(elt, value)
96+
for elt in subkeys(key):
97+
self._add_dependencies(elt, value)
10098

10199
def push_frame(self) -> Frame:
102100
"""Push a new frame into the binder."""
@@ -119,12 +117,11 @@ def _get(self, key: Key, index: int=-1) -> Optional[Type]:
119117
def put(self, expr: Expression, typ: Type) -> None:
120118
if not isinstance(expr, BindableTypes):
121119
return
122-
if not expr.literal:
120+
if not literal(expr):
123121
return
124-
key = expr.literal_hash
122+
key = literal_hash(expr)
125123
assert key is not None, 'Internal error: binder tried to put non-literal'
126124
if key not in self.declarations:
127-
assert isinstance(expr, BindableTypes)
128125
self.declarations[key] = get_declaration(expr)
129126
self._add_dependencies(key)
130127
self._put(key, typ)
@@ -133,8 +130,9 @@ def unreachable(self) -> None:
133130
self.frames[-1].unreachable = True
134131

135132
def get(self, expr: Expression) -> Optional[Type]:
136-
assert expr.literal_hash is not None, 'Internal error: binder tried to get non-literal'
137-
return self._get(expr.literal_hash)
133+
key = literal_hash(expr)
134+
assert key is not None, 'Internal error: binder tried to get non-literal'
135+
return self._get(key)
138136

139137
def is_unreachable(self) -> bool:
140138
# TODO: Copy the value of unreachable into new frames to avoid
@@ -143,8 +141,9 @@ def is_unreachable(self) -> bool:
143141

144142
def cleanse(self, expr: Expression) -> None:
145143
"""Remove all references to a Node from the binder."""
146-
assert expr.literal_hash is not None, 'Internal error: binder tried cleanse non-literal'
147-
self._cleanse_key(expr.literal_hash)
144+
key = literal_hash(expr)
145+
assert key is not None, 'Internal error: binder tried cleanse non-literal'
146+
self._cleanse_key(key)
148147

149148
def _cleanse_key(self, key: Key) -> None:
150149
"""Remove all references to a key from the binder."""
@@ -217,7 +216,7 @@ def assign_type(self, expr: Expression,
217216
restrict_any: bool = False) -> None:
218217
if not isinstance(expr, BindableTypes):
219218
return None
220-
if not expr.literal:
219+
if not literal(expr):
221220
return
222221
self.invalidate_dependencies(expr)
223222

@@ -266,14 +265,15 @@ def invalidate_dependencies(self, expr: BindableExpression) -> None:
266265
It is overly conservative: it invalidates globally, including
267266
in code paths unreachable from here.
268267
"""
269-
assert expr.literal_hash is not None
270-
for dep in self.dependencies.get(expr.literal_hash, set()):
268+
key = literal_hash(expr)
269+
assert key is not None
270+
for dep in self.dependencies.get(key, set()):
271271
self._cleanse_key(dep)
272272

273273
def most_recent_enclosing_type(self, expr: BindableExpression, type: Type) -> Optional[Type]:
274274
if isinstance(type, AnyType):
275275
return get_declaration(expr)
276-
key = expr.literal_hash
276+
key = literal_hash(expr)
277277
assert key is not None
278278
enclosers = ([get_declaration(expr)] +
279279
[f[key] for f in self.frames

mypy/checker.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
ARG_POS, MDEF,
3030
CONTRAVARIANT, COVARIANT, INVARIANT)
3131
from mypy import nodes
32+
from mypy.literals import literal, literal_hash
3233
from mypy.typeanal import has_any_from_unimported_type, check_for_explicit_any
3334
from mypy.types import (
3435
Type, AnyType, CallableType, FunctionLike, Overloaded, TupleType, TypedDictType,
@@ -2846,9 +2847,9 @@ def and_conditional_maps(m1: TypeMap, m2: TypeMap) -> TypeMap:
28462847
# arbitrarily give precedence to m2. (In the future, we could use
28472848
# an intersection type.)
28482849
result = m2.copy()
2849-
m2_keys = set(n2.literal_hash for n2 in m2)
2850+
m2_keys = set(literal_hash(n2) for n2 in m2)
28502851
for n1 in m1:
2851-
if n1.literal_hash not in m2_keys:
2852+
if literal_hash(n1) not in m2_keys:
28522853
result[n1] = m1[n1]
28532854
return result
28542855

@@ -2870,7 +2871,7 @@ def or_conditional_maps(m1: TypeMap, m2: TypeMap) -> TypeMap:
28702871
result = {}
28712872
for n1 in m1:
28722873
for n2 in m2:
2873-
if n1.literal_hash == n2.literal_hash:
2874+
if literal_hash(n1) == literal_hash(n2):
28742875
result[n1] = UnionType.make_simplified_union([m1[n1], m2[n2]])
28752876
return result
28762877

@@ -2910,13 +2911,13 @@ def find_isinstance_check(node: Expression,
29102911
if len(node.args) != 2: # the error will be reported later
29112912
return {}, {}
29122913
expr = node.args[0]
2913-
if expr.literal == LITERAL_TYPE:
2914+
if literal(expr) == LITERAL_TYPE:
29142915
vartype = type_map[expr]
29152916
type = get_isinstance_type(node.args[1], type_map)
29162917
return conditional_type_map(expr, vartype, type)
29172918
elif refers_to_fullname(node.callee, 'builtins.issubclass'):
29182919
expr = node.args[0]
2919-
if expr.literal == LITERAL_TYPE:
2920+
if literal(expr) == LITERAL_TYPE:
29202921
vartype = type_map[expr]
29212922
type = get_isinstance_type(node.args[1], type_map)
29222923
if isinstance(vartype, UnionType):
@@ -2940,7 +2941,7 @@ def find_isinstance_check(node: Expression,
29402941
return yes_map, no_map
29412942
elif refers_to_fullname(node.callee, 'builtins.callable'):
29422943
expr = node.args[0]
2943-
if expr.literal == LITERAL_TYPE:
2944+
if literal(expr) == LITERAL_TYPE:
29442945
vartype = type_map[expr]
29452946
return conditional_callable_type_map(expr, vartype)
29462947
elif isinstance(node, ComparisonExpr) and experiments.STRICT_OPTIONAL:
@@ -2950,7 +2951,8 @@ def find_isinstance_check(node: Expression,
29502951
if_vars = {} # type: TypeMap
29512952
else_vars = {} # type: TypeMap
29522953
for expr in node.operands:
2953-
if expr.literal == LITERAL_TYPE and not is_literal_none(expr) and expr in type_map:
2954+
if (literal(expr) == LITERAL_TYPE and not is_literal_none(expr)
2955+
and expr in type_map):
29542956
# This should only be true at most once: there should be
29552957
# two elements in node.operands, and at least one of them
29562958
# should represent a None.

mypy/checkexpr.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
TypeAliasExpr, BackquoteExpr, EnumCallExpr,
2525
ARG_POS, ARG_NAMED, ARG_STAR, ARG_STAR2, MODULE_REF, TVAR, LITERAL_TYPE,
2626
)
27+
from mypy.literals import literal
2728
from mypy import nodes
2829
import mypy.checker
2930
from mypy import types
@@ -2497,7 +2498,7 @@ def bool_type(self) -> Instance:
24972498
return self.named_type('builtins.bool')
24982499

24992500
def narrow_type_from_binder(self, expr: Expression, known_type: Type) -> Type:
2500-
if expr.literal >= LITERAL_TYPE:
2501+
if literal(expr) >= LITERAL_TYPE:
25012502
restriction = self.chk.binder.get(expr)
25022503
if restriction:
25032504
ans = narrow_declared_type(known_type, restriction)

0 commit comments

Comments
 (0)