@@ -251,6 +251,26 @@ impl Compiler {
251
251
}
252
252
}
253
253
254
+ /// Push the next symbol table on to the stack
255
+ fn push_symbol_table ( & mut self ) -> & SymbolTable {
256
+ // Look up the next table contained in the scope of the current table
257
+ let table = self
258
+ . symbol_table_stack
259
+ . last_mut ( )
260
+ . expect ( "no next symbol table" )
261
+ . sub_tables
262
+ . remove ( 0 ) ;
263
+ // Push the next table onto the stack
264
+ let last_idx = self . symbol_table_stack . len ( ) ;
265
+ self . symbol_table_stack . push ( table) ;
266
+ & self . symbol_table_stack [ last_idx]
267
+ }
268
+
269
+ /// Pop the current symbol table off the stack
270
+ fn pop_symbol_table ( & mut self ) -> SymbolTable {
271
+ self . symbol_table_stack . pop ( ) . expect ( "compiler bug" )
272
+ }
273
+
254
274
fn push_output (
255
275
& mut self ,
256
276
flags : bytecode:: CodeFlags ,
@@ -262,12 +282,7 @@ impl Compiler {
262
282
let source_path = self . source_path . clone ( ) ;
263
283
let first_line_number = self . get_source_line_number ( ) ;
264
284
265
- let table = self
266
- . symbol_table_stack
267
- . last_mut ( )
268
- . unwrap ( )
269
- . sub_tables
270
- . remove ( 0 ) ;
285
+ let table = self . push_symbol_table ( ) ;
271
286
272
287
let cellvar_cache = table
273
288
. symbols
@@ -284,8 +299,6 @@ impl Compiler {
284
299
. map ( |( var, _) | var. clone ( ) )
285
300
. collect ( ) ;
286
301
287
- self . symbol_table_stack . push ( table) ;
288
-
289
302
let info = ir:: CodeInfo {
290
303
flags,
291
304
posonlyarg_count,
@@ -307,7 +320,7 @@ impl Compiler {
307
320
}
308
321
309
322
fn pop_code_object ( & mut self ) -> CodeObject {
310
- let table = self . symbol_table_stack . pop ( ) . unwrap ( ) ;
323
+ let table = self . pop_symbol_table ( ) ;
311
324
assert ! ( table. sub_tables. is_empty( ) ) ;
312
325
self . code_stack
313
326
. pop ( )
@@ -752,6 +765,7 @@ impl Compiler {
752
765
body,
753
766
decorator_list,
754
767
returns,
768
+ type_params,
755
769
..
756
770
} ) => self . compile_function_def (
757
771
name. as_str ( ) ,
@@ -760,13 +774,15 @@ impl Compiler {
760
774
decorator_list,
761
775
returns. as_deref ( ) ,
762
776
false ,
777
+ type_params,
763
778
) ?,
764
779
Stmt :: AsyncFunctionDef ( StmtAsyncFunctionDef {
765
780
name,
766
781
args,
767
782
body,
768
783
decorator_list,
769
784
returns,
785
+ type_params,
770
786
..
771
787
} ) => self . compile_function_def (
772
788
name. as_str ( ) ,
@@ -775,15 +791,24 @@ impl Compiler {
775
791
decorator_list,
776
792
returns. as_deref ( ) ,
777
793
true ,
794
+ type_params,
778
795
) ?,
779
796
Stmt :: ClassDef ( StmtClassDef {
780
797
name,
781
798
body,
782
799
bases,
783
800
keywords,
784
801
decorator_list,
802
+ type_params,
785
803
..
786
- } ) => self . compile_class_def ( name. as_str ( ) , body, bases, keywords, decorator_list) ?,
804
+ } ) => self . compile_class_def (
805
+ name. as_str ( ) ,
806
+ body,
807
+ bases,
808
+ keywords,
809
+ decorator_list,
810
+ type_params,
811
+ ) ?,
787
812
Stmt :: Assert ( StmtAssert { test, msg, .. } ) => {
788
813
// if some flag, ignore all assert statements!
789
814
if self . opts . optimize == 0 {
@@ -885,7 +910,27 @@ impl Compiler {
885
910
Stmt :: Pass ( _) => {
886
911
// No need to emit any code here :)
887
912
}
888
- Stmt :: TypeAlias ( _) => { }
913
+ Stmt :: TypeAlias ( StmtTypeAlias {
914
+ name,
915
+ type_params,
916
+ value,
917
+ ..
918
+ } ) => {
919
+ let name_string = name. to_string ( ) ;
920
+ if !type_params. is_empty ( ) {
921
+ self . push_symbol_table ( ) ;
922
+ }
923
+ self . compile_expression ( value) ?;
924
+ self . compile_type_params ( type_params) ?;
925
+ if !type_params. is_empty ( ) {
926
+ self . pop_symbol_table ( ) ;
927
+ }
928
+ self . emit_load_const ( ConstantData :: Str {
929
+ value : name_string. clone ( ) ,
930
+ } ) ;
931
+ emit ! ( self , Instruction :: TypeAlias ) ;
932
+ self . store_name ( & name_string) ?;
933
+ }
889
934
}
890
935
Ok ( ( ) )
891
936
}
@@ -1005,6 +1050,47 @@ impl Compiler {
1005
1050
}
1006
1051
}
1007
1052
1053
+ /// Store each type parameter so it is accessible to the current scope, and leave a tuple of
1054
+ /// all the type parameters on the stack.
1055
+ fn compile_type_params ( & mut self , type_params : & [ located_ast:: TypeParam ] ) -> CompileResult < ( ) > {
1056
+ for type_param in type_params {
1057
+ match type_param {
1058
+ located_ast:: TypeParam :: TypeVar ( located_ast:: TypeParamTypeVar {
1059
+ name,
1060
+ bound,
1061
+ ..
1062
+ } ) => {
1063
+ if let Some ( expr) = & bound {
1064
+ self . compile_expression ( expr) ?;
1065
+ self . emit_load_const ( ConstantData :: Str {
1066
+ value : name. to_string ( ) ,
1067
+ } ) ;
1068
+ emit ! ( self , Instruction :: TypeVarWithBound ) ;
1069
+ emit ! ( self , Instruction :: Duplicate ) ;
1070
+ self . store_name ( name. as_ref ( ) ) ?;
1071
+ } else {
1072
+ // self.store_name(type_name.as_str())?;
1073
+ self . emit_load_const ( ConstantData :: Str {
1074
+ value : name. to_string ( ) ,
1075
+ } ) ;
1076
+ emit ! ( self , Instruction :: TypeVar ) ;
1077
+ emit ! ( self , Instruction :: Duplicate ) ;
1078
+ self . store_name ( name. as_ref ( ) ) ?;
1079
+ }
1080
+ }
1081
+ located_ast:: TypeParam :: ParamSpec ( _) => todo ! ( ) ,
1082
+ located_ast:: TypeParam :: TypeVarTuple ( _) => todo ! ( ) ,
1083
+ } ;
1084
+ }
1085
+ emit ! (
1086
+ self ,
1087
+ Instruction :: BuildTuple {
1088
+ size: u32 :: try_from( type_params. len( ) ) . unwrap( ) ,
1089
+ }
1090
+ ) ;
1091
+ Ok ( ( ) )
1092
+ }
1093
+
1008
1094
fn compile_try_statement (
1009
1095
& mut self ,
1010
1096
body : & [ located_ast:: Stmt ] ,
@@ -1151,6 +1237,7 @@ impl Compiler {
1151
1237
is_forbidden_name ( name)
1152
1238
}
1153
1239
1240
+ #[ allow( clippy:: too_many_arguments) ]
1154
1241
fn compile_function_def (
1155
1242
& mut self ,
1156
1243
name : & str ,
@@ -1159,10 +1246,15 @@ impl Compiler {
1159
1246
decorator_list : & [ located_ast:: Expr ] ,
1160
1247
returns : Option < & located_ast:: Expr > , // TODO: use type hint somehow..
1161
1248
is_async : bool ,
1249
+ type_params : & [ located_ast:: TypeParam ] ,
1162
1250
) -> CompileResult < ( ) > {
1163
- // Create bytecode for this function:
1164
-
1165
1251
self . prepare_decorators ( decorator_list) ?;
1252
+
1253
+ // If there are type params, we need to push a special symbol table just for them
1254
+ if !type_params. is_empty ( ) {
1255
+ self . push_symbol_table ( ) ;
1256
+ }
1257
+
1166
1258
let mut func_flags = self . enter_function ( name, args) ?;
1167
1259
self . current_code_info ( )
1168
1260
. flags
@@ -1208,6 +1300,12 @@ impl Compiler {
1208
1300
self . qualified_path . pop ( ) ;
1209
1301
self . ctx = prev_ctx;
1210
1302
1303
+ // Prepare generic type parameters:
1304
+ if !type_params. is_empty ( ) {
1305
+ self . compile_type_params ( type_params) ?;
1306
+ func_flags |= bytecode:: MakeFunctionFlags :: TYPE_PARAMS ;
1307
+ }
1308
+
1211
1309
// Prepare type annotations:
1212
1310
let mut num_annotations = 0 ;
1213
1311
@@ -1253,6 +1351,11 @@ impl Compiler {
1253
1351
func_flags |= bytecode:: MakeFunctionFlags :: CLOSURE ;
1254
1352
}
1255
1353
1354
+ // Pop the special type params symbol table
1355
+ if !type_params. is_empty ( ) {
1356
+ self . pop_symbol_table ( ) ;
1357
+ }
1358
+
1256
1359
self . emit_load_const ( ConstantData :: Code {
1257
1360
code : Box :: new ( code) ,
1258
1361
} ) ;
@@ -1352,6 +1455,7 @@ impl Compiler {
1352
1455
bases : & [ located_ast:: Expr ] ,
1353
1456
keywords : & [ located_ast:: Keyword ] ,
1354
1457
decorator_list : & [ located_ast:: Expr ] ,
1458
+ type_params : & [ located_ast:: TypeParam ] ,
1355
1459
) -> CompileResult < ( ) > {
1356
1460
self . prepare_decorators ( decorator_list) ?;
1357
1461
@@ -1378,6 +1482,11 @@ impl Compiler {
1378
1482
self . push_qualified_path ( name) ;
1379
1483
let qualified_name = self . qualified_path . join ( "." ) ;
1380
1484
1485
+ // If there are type params, we need to push a special symbol table just for them
1486
+ if !type_params. is_empty ( ) {
1487
+ self . push_symbol_table ( ) ;
1488
+ }
1489
+
1381
1490
self . push_output ( bytecode:: CodeFlags :: empty ( ) , 0 , 0 , 0 , name. to_owned ( ) ) ;
1382
1491
1383
1492
let ( doc_str, body) = split_doc ( body, & self . opts ) ;
@@ -1428,10 +1537,21 @@ impl Compiler {
1428
1537
1429
1538
let mut func_flags = bytecode:: MakeFunctionFlags :: empty ( ) ;
1430
1539
1540
+ // Prepare generic type parameters:
1541
+ if !type_params. is_empty ( ) {
1542
+ self . compile_type_params ( type_params) ?;
1543
+ func_flags |= bytecode:: MakeFunctionFlags :: TYPE_PARAMS ;
1544
+ }
1545
+
1431
1546
if self . build_closure ( & code) {
1432
1547
func_flags |= bytecode:: MakeFunctionFlags :: CLOSURE ;
1433
1548
}
1434
1549
1550
+ // Pop the special type params symbol table
1551
+ if !type_params. is_empty ( ) {
1552
+ self . pop_symbol_table ( ) ;
1553
+ }
1554
+
1435
1555
self . emit_load_const ( ConstantData :: Code {
1436
1556
code : Box :: new ( code) ,
1437
1557
} ) ;
0 commit comments