@@ -1009,11 +1009,6 @@ def __init__(self,
1009
1009
self .callable_class_names = set () # type: Set[str]
1010
1010
self .options = options
1011
1011
1012
- # This instance of NonExtClassInfo keeps track of information needed to construct
1013
- # a non-extension class. Its' value is None if the current class being visited
1014
- # is an extension class.
1015
- self .non_ext_info = None # type: Optional[NonExtClassInfo]
1016
-
1017
1012
# These variables keep track of the number of lambdas, implicit indices, and implicit
1018
1013
# iterators instantiated so we avoid name conflicts. The indices and iterators are
1019
1014
# instantiated from for-loops.
@@ -1143,7 +1138,8 @@ def handle_ext_method(self, cdef: ClassDef, fdef: FuncDef) -> None:
1143
1138
class_ir .glue_methods [(cls , name )] = f
1144
1139
self .functions .append (f )
1145
1140
1146
- def handle_non_ext_method (self , cdef : ClassDef , fdef : FuncDef ) -> None :
1141
+ def handle_non_ext_method (
1142
+ self , non_ext : NonExtClassInfo , cdef : ClassDef , fdef : FuncDef ) -> None :
1147
1143
# Perform the function of visit_method for methods inside non-extension classes.
1148
1144
name = fdef .name ()
1149
1145
func_ir , func_reg = self .gen_func_item (fdef , name , self .mapper .fdef_to_sig (fdef ), cdef )
@@ -1168,14 +1164,14 @@ def handle_non_ext_method(self, cdef: ClassDef, fdef: FuncDef) -> None:
1168
1164
stat_meth = self .load_module_attr_by_fullname ('builtins.staticmethod' , fdef .line )
1169
1165
func_reg = self .py_call (stat_meth , [func_reg ], fdef .line )
1170
1166
1171
- self .add_to_non_ext_dict (name , func_reg , fdef .line )
1167
+ self .add_to_non_ext_dict (non_ext , name , func_reg , fdef .line )
1172
1168
1173
- def visit_method (self , cdef : ClassDef , fdef : FuncDef ) -> None :
1174
- class_ir = self . mapper . type_to_ir [ cdef . info ]
1175
- if class_ir . is_ext_class :
1176
- self .handle_ext_method ( cdef , fdef )
1169
+ def visit_method (
1170
+ self , cdef : ClassDef , non_ext : Optional [ NonExtClassInfo ], fdef : FuncDef ) -> None :
1171
+ if non_ext :
1172
+ self .handle_non_ext_method ( non_ext , cdef , fdef )
1177
1173
else :
1178
- self .handle_non_ext_method (cdef , fdef )
1174
+ self .handle_ext_method (cdef , fdef )
1179
1175
1180
1176
def is_constant (self , e : Expression ) -> bool :
1181
1177
"""Check whether we allow an expression to appear as a default value.
@@ -1253,27 +1249,27 @@ def generate_attr_defaults(self, cdef: ClassDef) -> None:
1253
1249
self .functions .append (ir )
1254
1250
cls .methods [ir .name ] = ir
1255
1251
1256
- def load_non_ext_class (self , ir : ClassIR , line : int ) -> Value :
1257
- assert self .non_ext_info is not None
1258
-
1252
+ def load_non_ext_class (self , ir : ClassIR , non_ext : NonExtClassInfo , line : int ) -> Value :
1259
1253
cls_name = self .load_static_unicode (ir .name )
1260
1254
1261
1255
# Add __annotations__ to the class dict.
1262
1256
self .primitive_op (dict_set_item_op ,
1263
- [self . non_ext_info .dict , self .load_static_unicode ('__annotations__' ),
1264
- self . non_ext_info .anns ], - 1 )
1257
+ [non_ext .dict , self .load_static_unicode ('__annotations__' ),
1258
+ non_ext .anns ], - 1 )
1265
1259
1266
1260
# We add a __doc__ attribute so if the non-extension class is decorated with the
1267
1261
# dataclass decorator, dataclass will not try to look for __text_signature__.
1268
1262
# https://github.com/python/cpython/blob/3.7/Lib/dataclasses.py#L957
1269
1263
filler_doc_str = 'filler docstring for classes decorated with dataclass'
1270
- self .add_to_non_ext_dict ('__doc__' , self .load_static_unicode (filler_doc_str ), line )
1271
- self .add_to_non_ext_dict ('__module__' , self .load_static_unicode (self .module_name ), line )
1264
+ self .add_to_non_ext_dict (
1265
+ non_ext , '__doc__' , self .load_static_unicode (filler_doc_str ), line )
1266
+ self .add_to_non_ext_dict (
1267
+ non_ext , '__module__' , self .load_static_unicode (self .module_name ), line )
1272
1268
metaclass = self .primitive_op (type_object_op , [], line )
1273
- metaclass = self .primitive_op (py_calc_meta_op , [metaclass , self . non_ext_info .bases ], line )
1269
+ metaclass = self .primitive_op (py_calc_meta_op , [metaclass , non_ext .bases ], line )
1274
1270
1275
1271
class_type_obj = self .py_call (metaclass ,
1276
- [cls_name , self . non_ext_info . bases , self . non_ext_info .dict ],
1272
+ [cls_name , non_ext . bases , non_ext .dict ],
1277
1273
line )
1278
1274
return class_type_obj
1279
1275
@@ -1309,13 +1305,13 @@ def populate_non_ext_bases(self, cdef: ClassDef) -> Value:
1309
1305
bases .append (base )
1310
1306
return self .primitive_op (new_tuple_op , bases , cdef .line )
1311
1307
1312
- def add_to_non_ext_dict (self , key : str , val : Value , line : int ) -> None :
1308
+ def add_to_non_ext_dict (self , non_ext : NonExtClassInfo ,
1309
+ key : str , val : Value , line : int ) -> None :
1313
1310
# Add an attribute entry into the class dict of a non-extension class.
1314
- assert self .non_ext_info is not None
1315
1311
key_unicode = self .load_static_unicode (key )
1316
- self .primitive_op (dict_set_item_op , [self . non_ext_info .dict , key_unicode , val ], line )
1312
+ self .primitive_op (dict_set_item_op , [non_ext .dict , key_unicode , val ], line )
1317
1313
1318
- def add_non_ext_class_attr (self , lvalue : NameExpr ,
1314
+ def add_non_ext_class_attr (self , non_ext : NonExtClassInfo , lvalue : NameExpr ,
1319
1315
stmt : AssignmentStmt , cdef : ClassDef ,
1320
1316
attr_to_cache : List [Lvalue ]) -> None :
1321
1317
"""
@@ -1326,16 +1322,15 @@ def add_non_ext_class_attr(self, lvalue: NameExpr,
1326
1322
# We populate __annotations__ because dataclasses uses it to determine
1327
1323
# which attributes to compute on.
1328
1324
# TODO: Maybe generate more precise types for annotations
1329
- assert self .non_ext_info is not None
1330
1325
key = self .load_static_unicode (lvalue .name )
1331
1326
typ = self .primitive_op (type_object_op , [], stmt .line )
1332
- self .primitive_op (dict_set_item_op , [self . non_ext_info .anns , key , typ ], stmt .line )
1327
+ self .primitive_op (dict_set_item_op , [non_ext .anns , key , typ ], stmt .line )
1333
1328
1334
1329
# Only add the attribute to the __dict__ if the assignment is of the form:
1335
1330
# x: type = value (don't add attributes of the form 'x: type' to the __dict__).
1336
1331
if not isinstance (stmt .rvalue , TempNode ):
1337
1332
rvalue = self .accept (stmt .rvalue )
1338
- self .add_to_non_ext_dict (lvalue .name , rvalue , stmt .line )
1333
+ self .add_to_non_ext_dict (non_ext , lvalue .name , rvalue , stmt .line )
1339
1334
# We cache enum attributes to speed up enum attribute lookup since they
1340
1335
# are final.
1341
1336
if cdef .info .bases and cdef .info .bases [0 ].type .fullname () == 'enum.Enum' :
@@ -1390,14 +1385,15 @@ def visit_class_def(self, cdef: ClassDef) -> None:
1390
1385
if ir .is_ext_class :
1391
1386
# If the class is not decorated, generate an extension class for it.
1392
1387
self .allocate_class (cdef )
1388
+ non_ext = None # type: Optional[NonExtClassInfo]
1393
1389
else :
1394
1390
non_ext_bases = self .populate_non_ext_bases (cdef )
1395
1391
non_ext_dict = self .setup_non_ext_dict (cdef , non_ext_bases )
1396
1392
# We populate __annotations__ for non-extension classes
1397
1393
# because dataclasses uses it to determine which attributes to compute on.
1398
1394
# TODO: Maybe generate more precise types for annotations
1399
1395
non_ext_anns = self .primitive_op (new_dict_op , [], cdef .line )
1400
- self . non_ext_info = NonExtClassInfo (non_ext_dict , non_ext_bases , non_ext_anns )
1396
+ non_ext = NonExtClassInfo (non_ext_dict , non_ext_bases , non_ext_anns )
1401
1397
1402
1398
attrs_to_cache = [] # type: List[Lvalue]
1403
1399
@@ -1410,13 +1406,13 @@ def visit_class_def(self, cdef: ClassDef) -> None:
1410
1406
stmt .line )
1411
1407
for item in stmt .items :
1412
1408
with self .catch_errors (stmt .line ):
1413
- self .visit_method (cdef , get_func_def (item ))
1409
+ self .visit_method (cdef , non_ext , get_func_def (item ))
1414
1410
elif isinstance (stmt , (FuncDef , Decorator , OverloadedFuncDef )):
1415
1411
if cdef .info .names [stmt .name ()].plugin_generated and not ir .is_ext_class :
1416
1412
# Ignore plugin generated methods when creating non-extension classes
1417
1413
continue
1418
1414
with self .catch_errors (stmt .line ):
1419
- self .visit_method (cdef , get_func_def (stmt ))
1415
+ self .visit_method (cdef , non_ext , get_func_def (stmt ))
1420
1416
elif isinstance (stmt , PassStmt ):
1421
1417
continue
1422
1418
elif isinstance (stmt , AssignmentStmt ):
@@ -1430,8 +1426,9 @@ def visit_class_def(self, cdef: ClassDef) -> None:
1430
1426
self .error ("Only assignment to variables is supported in class bodies" ,
1431
1427
stmt .line )
1432
1428
continue
1433
- if not ir .is_ext_class :
1434
- self .add_non_ext_class_attr (lvalue , stmt , cdef , attrs_to_cache )
1429
+ if non_ext :
1430
+ self .add_non_ext_class_attr (
1431
+ non_ext , lvalue , stmt , cdef , attrs_to_cache )
1435
1432
continue
1436
1433
# Variable declaration with no body
1437
1434
if isinstance (stmt .rvalue , TempNode ):
@@ -1451,12 +1448,12 @@ def visit_class_def(self, cdef: ClassDef) -> None:
1451
1448
else :
1452
1449
self .error ("Unsupported statement in class body" , stmt .line )
1453
1450
1454
- if ir . is_ext_class :
1451
+ if not non_ext : # That is, an extension class
1455
1452
self .generate_attr_defaults (cdef )
1456
1453
self .create_ne_from_eq (cdef )
1457
1454
else :
1458
1455
# Dynamically create the class via the type constructor
1459
- non_ext_class = self .load_non_ext_class (ir , cdef .line )
1456
+ non_ext_class = self .load_non_ext_class (ir , non_ext , cdef .line )
1460
1457
non_ext_class = self .load_decorated_class (cdef , non_ext_class )
1461
1458
1462
1459
# Save the decorated class
0 commit comments