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