@@ -88,13 +88,18 @@ def get_line(self) -> int: pass
88
88
for alias , name in type_aliases .items ()) # type: Dict[str, str]
89
89
90
90
91
+ # See [Note Literals and literal_hash] below
92
+ Key = tuple
93
+
94
+
91
95
class Node (Context ):
92
96
"""Common base class for all non-type parse tree nodes."""
93
97
94
98
line = - 1
95
99
100
+ # See [Note Literals and literal_hash] below
96
101
literal = LITERAL_NO
97
- literal_hash = None # type: Any
102
+ literal_hash = None # type: Key
98
103
99
104
def __str__ (self ) -> str :
100
105
ans = self .accept (mypy .strconv .StrConv ())
@@ -132,6 +137,44 @@ def deserialize(cls, data: JsonDict) -> 'Node':
132
137
raise NotImplementedError ('unexpected .class {}' .format (classname ))
133
138
134
139
140
+ # [Note Literals and literal_hash]
141
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
142
+ #
143
+ # Mypy uses the term "literal" to refer to any expression built out of
144
+ # the following:
145
+ #
146
+ # * Plain literal expressions, like `1` (integer, float, string, etc.)
147
+ #
148
+ # * Compound literal expressions, like `(lit1, lit2)` (list, dict,
149
+ # set, or tuple)
150
+ #
151
+ # * Operator expressions, like `lit1 + lit2`
152
+ #
153
+ # * Variable references, like `x`
154
+ #
155
+ # * Member references, like `lit.m`
156
+ #
157
+ # * Index expressions, like `lit[0]`
158
+ #
159
+ # A typical "literal" looks like `x[(i,j+1)].m`.
160
+ #
161
+ # An expression that is a literal has a `literal_hash`, with the
162
+ # following properties.
163
+ #
164
+ # * `literal_hash` is a Key: a tuple containing basic data types and
165
+ # possibly other Keys. So it can be used as a key in a dictionary
166
+ # that will be compared by value (as opposed to the Node itself,
167
+ # which is compared by identity).
168
+ #
169
+ # * Two expressions have equal `literal_hash`es if and only if they
170
+ # are syntactically equal expressions. (NB: Actually, we also
171
+ # identify as equal expressions like `3` and `3.0`; is this a good
172
+ # idea?)
173
+ #
174
+ # * The elements of `literal_hash` that are tuples are exactly the
175
+ # subexpressions of the original expression (e.g. the base and index
176
+ # of an index expression, or the operands of an operator expression).
177
+
135
178
class SymbolNode (Node ):
136
179
# Nodes that can be stored in a symbol table.
137
180
@@ -953,7 +996,7 @@ class IntExpr(Node):
953
996
954
997
def __init__ (self , value : int ) -> None :
955
998
self .value = value
956
- self .literal_hash = value
999
+ self .literal_hash = ( 'Literal' , value )
957
1000
958
1001
def accept (self , visitor : NodeVisitor [T ]) -> T :
959
1002
return visitor .visit_int_expr (self )
@@ -978,7 +1021,7 @@ class StrExpr(Node):
978
1021
979
1022
def __init__ (self , value : str ) -> None :
980
1023
self .value = value
981
- self .literal_hash = value
1024
+ self .literal_hash = ( 'Literal' , value )
982
1025
983
1026
def accept (self , visitor : NodeVisitor [T ]) -> T :
984
1027
return visitor .visit_str_expr (self )
@@ -992,7 +1035,7 @@ class BytesExpr(Node):
992
1035
993
1036
def __init__ (self , value : str ) -> None :
994
1037
self .value = value
995
- self .literal_hash = value
1038
+ self .literal_hash = ( 'Literal' , value )
996
1039
997
1040
def accept (self , visitor : NodeVisitor [T ]) -> T :
998
1041
return visitor .visit_bytes_expr (self )
@@ -1006,7 +1049,7 @@ class UnicodeExpr(Node):
1006
1049
1007
1050
def __init__ (self , value : str ) -> None :
1008
1051
self .value = value
1009
- self .literal_hash = value
1052
+ self .literal_hash = ( 'Literal' , value )
1010
1053
1011
1054
def accept (self , visitor : NodeVisitor [T ]) -> T :
1012
1055
return visitor .visit_unicode_expr (self )
@@ -1020,7 +1063,7 @@ class FloatExpr(Node):
1020
1063
1021
1064
def __init__ (self , value : float ) -> None :
1022
1065
self .value = value
1023
- self .literal_hash = value
1066
+ self .literal_hash = ( 'Literal' , value )
1024
1067
1025
1068
def accept (self , visitor : NodeVisitor [T ]) -> T :
1026
1069
return visitor .visit_float_expr (self )
@@ -1034,7 +1077,7 @@ class ComplexExpr(Node):
1034
1077
1035
1078
def __init__ (self , value : complex ) -> None :
1036
1079
self .value = value
1037
- self .literal_hash = value
1080
+ self .literal_hash = ( 'Literal' , value )
1038
1081
1039
1082
def accept (self , visitor : NodeVisitor [T ]) -> T :
1040
1083
return visitor .visit_complex_expr (self )
@@ -1223,7 +1266,7 @@ def __init__(self, base: Node, index: Node) -> None:
1223
1266
self .analyzed = None
1224
1267
if self .index .literal == LITERAL_YES :
1225
1268
self .literal = self .base .literal
1226
- self .literal_hash = ('Member ' , base .literal_hash ,
1269
+ self .literal_hash = ('Index ' , base .literal_hash ,
1227
1270
index .literal_hash )
1228
1271
1229
1272
def accept (self , visitor : NodeVisitor [T ]) -> T :
@@ -1336,7 +1379,7 @@ def __init__(self, operators: List[str], operands: List[Node]) -> None:
1336
1379
self .operands = operands
1337
1380
self .method_types = []
1338
1381
self .literal = min (o .literal for o in self .operands )
1339
- self .literal_hash = (('Comparison' ,) + tuple (operators ) +
1382
+ self .literal_hash = ((cast ( Any , 'Comparison' ) ,) + tuple (operators ) +
1340
1383
tuple (o .literal_hash for o in operands ))
1341
1384
1342
1385
def accept (self , visitor : NodeVisitor [T ]) -> T :
@@ -1426,7 +1469,7 @@ def __init__(self, items: List[Node]) -> None:
1426
1469
self .items = items
1427
1470
if all (x .literal == LITERAL_YES for x in items ):
1428
1471
self .literal = LITERAL_YES
1429
- self .literal_hash = ('List' ,) + tuple (x .literal_hash for x in items )
1472
+ self .literal_hash = (cast ( Any , 'List' ) ,) + tuple (x .literal_hash for x in items )
1430
1473
1431
1474
def accept (self , visitor : NodeVisitor [T ]) -> T :
1432
1475
return visitor .visit_list_expr (self )
@@ -1442,8 +1485,8 @@ def __init__(self, items: List[Tuple[Node, Node]]) -> None:
1442
1485
if all (x [0 ].literal == LITERAL_YES and x [1 ].literal == LITERAL_YES
1443
1486
for x in items ):
1444
1487
self .literal = LITERAL_YES
1445
- self .literal_hash = ('Dict' ,) + tuple (
1446
- (x [0 ].literal_hash , x [1 ].literal_hash ) for x in items ) # type: ignore
1488
+ self .literal_hash = (cast ( Any , 'Dict' ) ,) + tuple (
1489
+ (x [0 ].literal_hash , x [1 ].literal_hash ) for x in items )
1447
1490
1448
1491
def accept (self , visitor : NodeVisitor [T ]) -> T :
1449
1492
return visitor .visit_dict_expr (self )
@@ -1458,7 +1501,7 @@ def __init__(self, items: List[Node]) -> None:
1458
1501
self .items = items
1459
1502
if all (x .literal == LITERAL_YES for x in items ):
1460
1503
self .literal = LITERAL_YES
1461
- self .literal_hash = ('Tuple' ,) + tuple (x .literal_hash for x in items )
1504
+ self .literal_hash = (cast ( Any , 'Tuple' ) ,) + tuple (x .literal_hash for x in items )
1462
1505
1463
1506
def accept (self , visitor : NodeVisitor [T ]) -> T :
1464
1507
return visitor .visit_tuple_expr (self )
@@ -1473,7 +1516,7 @@ def __init__(self, items: List[Node]) -> None:
1473
1516
self .items = items
1474
1517
if all (x .literal == LITERAL_YES for x in items ):
1475
1518
self .literal = LITERAL_YES
1476
- self .literal_hash = ('Set' ,) + tuple (x .literal_hash for x in items )
1519
+ self .literal_hash = (cast ( Any , 'Set' ) ,) + tuple (x .literal_hash for x in items )
1477
1520
1478
1521
def accept (self , visitor : NodeVisitor [T ]) -> T :
1479
1522
return visitor .visit_set_expr (self )
0 commit comments