@@ -54,6 +54,9 @@ pub struct SymbolTable {
5454
5555 /// Whether this class scope needs an implicit __classdict__ cell
5656 pub needs_classdict : bool ,
57+
58+ /// Whether this type param scope can see the parent class scope
59+ pub can_see_class_scope : bool ,
5760}
5861
5962impl SymbolTable {
@@ -68,6 +71,7 @@ impl SymbolTable {
6871 varnames : Vec :: new ( ) ,
6972 needs_class_closure : false ,
7073 needs_classdict : false ,
74+ can_see_class_scope : false ,
7175 }
7276 }
7377
@@ -665,6 +669,31 @@ impl SymbolTableBuilder<'_> {
665669 self . current_varnames . clear ( ) ;
666670 }
667671
672+ fn enter_type_param_block ( & mut self , name : & str , line_number : u32 ) -> SymbolTableResult {
673+ // Check if we're in a class scope
674+ let in_class = self
675+ . tables
676+ . last ( )
677+ . is_some_and ( |t| t. typ == CompilerScope :: Class ) ;
678+
679+ self . enter_scope ( name, CompilerScope :: TypeParams , line_number) ;
680+
681+ // If we're in a class, mark that this type param scope can see the class scope
682+ if let Some ( table) = self . tables . last_mut ( ) {
683+ table. can_see_class_scope = in_class;
684+
685+ // Add __classdict__ as a USE symbol in type param scope if in class
686+ if in_class {
687+ self . register_name ( "__classdict__" , SymbolUsage :: Used , TextRange :: default ( ) ) ?;
688+ }
689+ }
690+
691+ // Register .type_params as a SET symbol (it will be converted to cell variable later)
692+ self . register_name ( ".type_params" , SymbolUsage :: Assigned , TextRange :: default ( ) ) ?;
693+
694+ Ok ( ( ) )
695+ }
696+
668697 /// Pop symbol table and add to sub table of parent table.
669698 fn leave_scope ( & mut self ) {
670699 let mut table = self . tables . pop ( ) . unwrap ( ) ;
@@ -746,12 +775,10 @@ impl SymbolTableBuilder<'_> {
746775 self . scan_annotation ( expression) ?;
747776 }
748777 if let Some ( type_params) = type_params {
749- self . enter_scope (
778+ self . enter_type_param_block (
750779 & format ! ( "<generic parameters of {}>" , name. as_str( ) ) ,
751- CompilerScope :: TypeParams ,
752- // FIXME: line no
753- self . line_index_start ( * range) ,
754- ) ;
780+ self . line_index_start ( type_params. range ) ,
781+ ) ?;
755782 self . scan_type_params ( type_params) ?;
756783 }
757784 self . enter_scope_with_parameters (
@@ -774,11 +801,10 @@ impl SymbolTableBuilder<'_> {
774801 range,
775802 } ) => {
776803 if let Some ( type_params) = type_params {
777- self . enter_scope (
804+ self . enter_type_param_block (
778805 & format ! ( "<generic parameters of {}>" , name. as_str( ) ) ,
779- CompilerScope :: TypeParams ,
780806 self . line_index_start ( type_params. range ) ,
781- ) ;
807+ ) ? ;
782808 self . scan_type_params ( type_params) ?;
783809 }
784810 self . enter_scope (
@@ -965,12 +991,10 @@ impl SymbolTableBuilder<'_> {
965991 ..
966992 } ) => {
967993 if let Some ( type_params) = type_params {
968- self . enter_scope (
969- // &name.to_string(),
994+ self . enter_type_param_block (
970995 "TypeAlias" ,
971- CompilerScope :: TypeParams ,
972996 self . line_index_start ( type_params. range ) ,
973- ) ;
997+ ) ? ;
974998 self . scan_type_params ( type_params) ?;
975999 self . scan_expression ( value, ExpressionContext :: Load ) ?;
9761000 self . leave_scope ( ) ;
@@ -1344,6 +1368,26 @@ impl SymbolTableBuilder<'_> {
13441368 Ok ( ( ) )
13451369 }
13461370
1371+ /// Scan type parameter bound or default in a separate scope
1372+ // = symtable_visit_type_param_bound_or_default
1373+ fn scan_type_param_bound_or_default ( & mut self , expr : & Expr , name : & str ) -> SymbolTableResult {
1374+ // Enter a new TypeParams scope for the bound/default expression
1375+ // This allows the expression to access outer scope symbols
1376+ let line_number = self . line_index_start ( expr. range ( ) ) ;
1377+ self . enter_scope ( name, CompilerScope :: TypeParams , line_number) ;
1378+
1379+ // Note: In CPython, can_see_class_scope is preserved in the new scope
1380+ // In RustPython, this is handled through the scope hierarchy
1381+
1382+ // Scan the expression in this new scope
1383+ let result = self . scan_expression ( expr, ExpressionContext :: Load ) ;
1384+
1385+ // Exit the scope
1386+ self . leave_scope ( ) ;
1387+
1388+ result
1389+ }
1390+
13471391 fn scan_type_params ( & mut self , type_params : & TypeParams ) -> SymbolTableResult {
13481392 // Register .type_params as a type parameter (automatically becomes cell variable)
13491393 self . register_name ( ".type_params" , SymbolUsage :: TypeParam , type_params. range ) ?;
@@ -1355,26 +1399,51 @@ impl SymbolTableBuilder<'_> {
13551399 name,
13561400 bound,
13571401 range : type_var_range,
1358- ..
1402+ default ,
13591403 } ) => {
13601404 self . register_name ( name. as_str ( ) , SymbolUsage :: TypeParam , * type_var_range) ?;
1405+
1406+ // Process bound in a separate scope
13611407 if let Some ( binding) = bound {
1362- self . scan_expression ( binding, ExpressionContext :: Load ) ?;
1408+ let scope_name = if binding. is_tuple_expr ( ) {
1409+ format ! ( "<TypeVar constraint of {name}>" )
1410+ } else {
1411+ format ! ( "<TypeVar bound of {name}>" )
1412+ } ;
1413+ self . scan_type_param_bound_or_default ( binding, & scope_name) ?;
1414+ }
1415+
1416+ // Process default in a separate scope
1417+ if let Some ( default_value) = default {
1418+ let scope_name = format ! ( "<TypeVar default of {name}>" ) ;
1419+ self . scan_type_param_bound_or_default ( default_value, & scope_name) ?;
13631420 }
13641421 }
13651422 TypeParam :: ParamSpec ( TypeParamParamSpec {
13661423 name,
13671424 range : param_spec_range,
1368- ..
1425+ default ,
13691426 } ) => {
13701427 self . register_name ( name, SymbolUsage :: TypeParam , * param_spec_range) ?;
1428+
1429+ // Process default in a separate scope
1430+ if let Some ( default_value) = default {
1431+ let scope_name = format ! ( "<ParamSpec default of {name}>" ) ;
1432+ self . scan_type_param_bound_or_default ( default_value, & scope_name) ?;
1433+ }
13711434 }
13721435 TypeParam :: TypeVarTuple ( TypeParamTypeVarTuple {
13731436 name,
13741437 range : type_var_tuple_range,
1375- ..
1438+ default ,
13761439 } ) => {
13771440 self . register_name ( name, SymbolUsage :: TypeParam , * type_var_tuple_range) ?;
1441+
1442+ // Process default in a separate scope
1443+ if let Some ( default_value) = default {
1444+ let scope_name = format ! ( "<TypeVarTuple default of {name}>" ) ;
1445+ self . scan_type_param_bound_or_default ( default_value, & scope_name) ?;
1446+ }
13781447 }
13791448 }
13801449 }
0 commit comments