From 84d1a3291c0d4c3487c8ef7a0bf0e48400a0abed Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 11 Jul 2025 10:23:58 +0900 Subject: [PATCH] Add SymbolUsage::TypeParams --- Lib/test/test_typing.py | 4 ---- compiler/codegen/src/compile.rs | 7 ++++++- compiler/codegen/src/symboltable.rs | 20 +++++++++++++++++--- vm/src/frame.rs | 6 +++++- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index a048c39cc9..1c74e1adac 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3888,8 +3888,6 @@ def test_pep695_generic_class_with_future_annotations(self): # should not have changed as a result of the get_type_hints() calls! self.assertEqual(ann_module695.__dict__, original_globals) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_pep695_generic_class_with_future_annotations_and_local_shadowing(self): hints_for_B = get_type_hints(ann_module695.B) self.assertEqual(hints_for_B, {"x": int, "y": str, "z": bytes}) @@ -3935,8 +3933,6 @@ def test_pep_695_generic_method_with_future_annotations_name_clash_with_global_v set(ann_module695.D.generic_method_2.__type_params__) ) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_pep_695_generics_with_future_annotations_nested_in_function(self): results = ann_module695.nested() diff --git a/compiler/codegen/src/compile.rs b/compiler/codegen/src/compile.rs index ab9b469ad8..61e459500a 100644 --- a/compiler/codegen/src/compile.rs +++ b/compiler/codegen/src/compile.rs @@ -638,7 +638,11 @@ impl Compiler<'_> { cache = &mut info.cellvar_cache; NameOpType::Deref } // TODO: is this right? - // SymbolScope::Unknown => NameOpType::Global, + SymbolScope::TypeParams => { + // Type parameters are always cell variables + cache = &mut info.cellvar_cache; + NameOpType::Deref + } // SymbolScope::Unknown => NameOpType::Global, }; if NameUsage::Load == usage && name == "__debug__" { @@ -1630,6 +1634,7 @@ impl Compiler<'_> { let vars = match symbol.scope { SymbolScope::Free => &parent_code.freevar_cache, SymbolScope::Cell => &parent_code.cellvar_cache, + SymbolScope::TypeParams => &parent_code.cellvar_cache, _ if symbol.flags.contains(SymbolFlags::FREE_CLASS) => &parent_code.freevar_cache, x => unreachable!( "var {} in a {:?} should be free or cell but it's {:?}", diff --git a/compiler/codegen/src/symboltable.rs b/compiler/codegen/src/symboltable.rs index 2949f39a9f..f215ce38f4 100644 --- a/compiler/codegen/src/symboltable.rs +++ b/compiler/codegen/src/symboltable.rs @@ -113,6 +113,7 @@ pub enum SymbolScope { GlobalImplicit, Free, Cell, + TypeParams, } bitflags! { @@ -359,6 +360,10 @@ impl SymbolTableAnalyzer { SymbolScope::Local | SymbolScope::Cell => { // all is well } + SymbolScope::TypeParams => { + // Type parameters are always cell variables in their scope + symbol.scope = SymbolScope::Cell; + } SymbolScope::Unknown => { // Try hard to figure out what the scope of this symbol is. let scope = if symbol.is_bound() { @@ -557,6 +562,7 @@ enum SymbolUsage { AnnotationParameter, AssignedNamedExprInComprehension, Iter, + TypeParam, } struct SymbolTableBuilder<'src> { @@ -1267,6 +1273,9 @@ impl SymbolTableBuilder<'_> { } fn scan_type_params(&mut self, type_params: &TypeParams) -> SymbolTableResult { + // Register .type_params as a type parameter (automatically becomes cell variable) + self.register_name(".type_params", SymbolUsage::TypeParam, type_params.range)?; + // First register all type parameters for type_param in &type_params.type_params { match type_param { @@ -1276,7 +1285,7 @@ impl SymbolTableBuilder<'_> { range: type_var_range, .. }) => { - self.register_name(name.as_str(), SymbolUsage::Assigned, *type_var_range)?; + self.register_name(name.as_str(), SymbolUsage::TypeParam, *type_var_range)?; if let Some(binding) = bound { self.scan_expression(binding, ExpressionContext::Load)?; } @@ -1286,14 +1295,14 @@ impl SymbolTableBuilder<'_> { range: param_spec_range, .. }) => { - self.register_name(name, SymbolUsage::Assigned, *param_spec_range)?; + self.register_name(name, SymbolUsage::TypeParam, *param_spec_range)?; } TypeParam::TypeVarTuple(TypeParamTypeVarTuple { name, range: type_var_tuple_range, .. }) => { - self.register_name(name, SymbolUsage::Assigned, *type_var_tuple_range)?; + self.register_name(name, SymbolUsage::TypeParam, *type_var_tuple_range)?; } } } @@ -1544,6 +1553,11 @@ impl SymbolTableBuilder<'_> { SymbolUsage::Iter => { flags.insert(SymbolFlags::ITER); } + SymbolUsage::TypeParam => { + // Type parameters are always cell variables in their scope + symbol.scope = SymbolScope::Cell; + flags.insert(SymbolFlags::ASSIGNED); + } } // and even more checking diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 3b69de8fd3..2bcfeebf54 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -596,7 +596,11 @@ impl ExecutingFrame<'_> { } bytecode::Instruction::LoadClassDeref(i) => { let i = i.get(arg) as usize; - let name = self.code.freevars[i - self.code.cellvars.len()]; + let name = if i < self.code.cellvars.len() { + self.code.cellvars[i] + } else { + self.code.freevars[i - self.code.cellvars.len()] + }; let value = self.locals.mapping().subscript(name, vm).ok(); self.push_value(match value { Some(v) => v,