@@ -1293,25 +1293,21 @@ def store_declared_types(self, lvalue: Node, typ: Type) -> None:
1293
1293
1294
1294
def process_newtype_declaration (self , s : AssignmentStmt ) -> None :
1295
1295
"""Check if s declares a NewType; if yes, store it in symbol table."""
1296
+ # Extract and check all information from newtype declaration
1296
1297
call = self .get_newtype_declaration (s )
1297
- if not call :
1298
+ if call is None :
1298
1299
return
1299
1300
call .analyzed = NewTypeExpr (None ).set_line (call .line )
1300
1301
1301
- lvalue = cast (NameExpr , s .lvalues [0 ])
1302
- name = lvalue .name
1303
- if not lvalue .is_def :
1304
- if s .type :
1305
- self .fail ("Cannot declare the type of a NewType declaration" , s )
1306
- else :
1307
- self .fail ("Cannot redefine '%s' as a NewType" % name , s )
1302
+ name = self .get_newtype_name (s )
1303
+ if name is None :
1308
1304
return
1309
1305
1310
1306
old_type = self .check_newtype_args (call , name , s )
1311
1307
if old_type is None :
1312
1308
return
1313
1309
1314
- # Create the corresponding class def if it's subtypeable...
1310
+ # Create the corresponding class definition if the aliased type is subtypeable
1315
1311
if isinstance (old_type , TupleType ):
1316
1312
newtype_class_info = self .build_newtype_typeinfo (name , old_type , old_type .fallback )
1317
1313
newtype_class_info .tuple_type = old_type
@@ -1322,39 +1318,41 @@ def process_newtype_declaration(self, s: AssignmentStmt) -> None:
1322
1318
self .fail (message .format (old_type ), s )
1323
1319
return
1324
1320
1325
- # ...and add it to the symbol table.
1321
+ # If so, add it to the symbol table.
1326
1322
node = self .lookup (name , s )
1327
- node . kind = GDEF # TODO: locally defined newtype
1328
- call . analyzed = NewTypeExpr ( newtype_class_info ). set_line ( call . line )
1323
+ # TODO: why does NewType work in local scopes despite always being of kind GDEF?
1324
+ node . kind = GDEF
1329
1325
node .node = newtype_class_info
1326
+ call .analyzed = NewTypeExpr (newtype_class_info ).set_line (call .line )
1330
1327
1331
- def build_newtype_typeinfo (self ,name : str , old_type : Type , base_type : Instance ) -> TypeInfo :
1332
- class_def = ClassDef (name , Block ([]))
1333
- class_def .fullname = self .qualified_name (name )
1334
-
1335
- symbols = SymbolTable ()
1336
- info = TypeInfo (symbols , class_def )
1337
- info .mro = [info ] + base_type .type .mro
1338
- info .bases = [base_type ]
1339
- info .is_newtype = True
1340
-
1341
- # Add __init__ method
1342
- args = [Argument (Var ('cls' ), NoneTyp (), None , ARG_POS ),
1343
- self .make_argument ('item' , old_type )]
1344
- signature = CallableType (
1345
- arg_types = [cast (Type , None ), old_type ],
1346
- arg_kinds = [arg .kind for arg in args ],
1347
- arg_names = ['self' , 'item' ],
1348
- ret_type = old_type ,
1349
- fallback = self .named_type ('__builtins__.function' ),
1350
- name = name )
1351
- init_func = FuncDef ('__init__' , args , Block ([]), typ = signature )
1352
- init_func .info = info
1353
- symbols ['__init__' ] = SymbolTableNode (MDEF , init_func )
1328
+ def get_newtype_declaration (self , s : AssignmentStmt ) -> Optional [CallExpr ]:
1329
+ """Returns the Newtype() call statement if `s` is a newtype declaration
1330
+ or None otherwise."""
1331
+ # TODO: determine if this and get_typevar_declaration should be refactored
1332
+ if len (s .lvalues ) != 1 or not isinstance (s .lvalues [0 ], NameExpr ):
1333
+ return None
1334
+ if not isinstance (s .rvalue , CallExpr ):
1335
+ return None
1336
+ call = s .rvalue
1337
+ if not isinstance (call .callee , RefExpr ):
1338
+ return None
1339
+ callee = call .callee
1340
+ if callee .fullname != 'typing.NewType' :
1341
+ return None
1342
+ return call
1354
1343
1355
- return info
1344
+ def get_newtype_name (self , s : AssignmentStmt ) -> Optional [str ]:
1345
+ lvalue = cast (NameExpr , s .lvalues [0 ])
1346
+ name = lvalue .name
1347
+ if not lvalue .is_def :
1348
+ if s .type :
1349
+ self .fail ("Cannot declare the type of a NewType declaration" , s )
1350
+ else :
1351
+ self .fail ("Cannot redefine '%s' as a NewType" % name , s )
1352
+ return None
1353
+ return name
1356
1354
1357
- def check_newtype_args (self , call : CallExpr , name : str , context : Context ) -> Type :
1355
+ def check_newtype_args (self , call : CallExpr , name : str , context : Context ) -> Optional [ Type ] :
1358
1356
has_failed = False
1359
1357
args = call .args
1360
1358
if len (args ) != 2 :
@@ -1387,21 +1385,31 @@ def check_newtype_args(self, call: CallExpr, name: str, context: Context) -> Typ
1387
1385
1388
1386
return None if has_failed else value
1389
1387
1390
- def get_newtype_declaration (self , s : AssignmentStmt ) -> Optional [CallExpr ]:
1391
- """Returns the Newtype() call statement if `s` is a newtype declaration
1392
- or None otherwise."""
1393
- # TODO: determine if this and get_typevar_declaration should be refactored
1394
- if len (s .lvalues ) != 1 or not isinstance (s .lvalues [0 ], NameExpr ):
1395
- return None
1396
- if not isinstance (s .rvalue , CallExpr ):
1397
- return None
1398
- call = s .rvalue
1399
- if not isinstance (call .callee , RefExpr ):
1400
- return None
1401
- callee = call .callee
1402
- if callee .fullname != 'typing.NewType' :
1403
- return None
1404
- return call
1388
+ def build_newtype_typeinfo (self , name : str , old_type : Type , base_type : Instance ) -> TypeInfo :
1389
+ class_def = ClassDef (name , Block ([]))
1390
+ class_def .fullname = self .qualified_name (name )
1391
+
1392
+ symbols = SymbolTable ()
1393
+ info = TypeInfo (symbols , class_def )
1394
+ info .mro = [info ] + base_type .type .mro
1395
+ info .bases = [base_type ]
1396
+ info .is_newtype = True
1397
+
1398
+ # Add __init__ method
1399
+ args = [Argument (Var ('cls' ), NoneTyp (), None , ARG_POS ),
1400
+ self .make_argument ('item' , old_type )]
1401
+ signature = CallableType (
1402
+ arg_types = [cast (Type , None ), old_type ],
1403
+ arg_kinds = [arg .kind for arg in args ],
1404
+ arg_names = ['self' , 'item' ],
1405
+ ret_type = old_type ,
1406
+ fallback = self .named_type ('__builtins__.function' ),
1407
+ name = name )
1408
+ init_func = FuncDef ('__init__' , args , Block ([]), typ = signature )
1409
+ init_func .info = info
1410
+ symbols ['__init__' ] = SymbolTableNode (MDEF , init_func )
1411
+
1412
+ return info
1405
1413
1406
1414
def process_typevar_declaration (self , s : AssignmentStmt ) -> None :
1407
1415
"""Check if s declares a TypeVar; it yes, store it in symbol table."""
0 commit comments