Skip to content

Conversation

@youknowone
Copy link
Member

@youknowone youknowone commented Feb 11, 2026

Summary by CodeRabbit

  • Refactor
    • Improved generic type support with enhanced TypeVarTuple parameter handling
    • Refined type parameter processing and selective name handling in code generation
    • Updated type variable variance representation and type immutability semantics for better correctness

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

📝 Walkthrough

Walkthrough

This PR introduces selective name mangling for type parameters in generic contexts, refactoring the symbol table to track which names require mangling and conditionally applying mangling during name resolution. It updates TypeVar/ParamSpec variance handling, adds TypeVarTuple unpacking support in generic aliases, and adjusts the NoDefault type's immutability flag.

Changes

Cohort / File(s) Summary
Compiler Name Mangling
crates/codegen/src/compile.rs
Updated name mangling invocation to use maybe_mangle_name with per-scope mangled names set instead of unconditional mangling.
Symbol Table Selective Mangling
crates/codegen/src/symboltable.rs
Introduced optional mangled_names set to control selective mangling within type parameter scopes; added maybe_mangle_name function, updated scope/parameter entry to propagate mangling data, added default parameter scanning, and integrated class-aware type parameter block handling.
Generic Type System
crates/vm/src/builtins/genericalias.rs, crates/vm/src/stdlib/typevar.rs
Added TypeVarTuple unpacking logic in subscript_generic; updated TypeVar/ParamSpec variance inference behavior and bound validation; refactored comparison logic for ParamSpecArgs/ParamSpecKwargs.
Type Module Configuration
crates/vm/src/stdlib/typing.rs
Changed NoDefault pyclass flag from BASETYPE to IMMUTABLETYPE.

Sequence Diagram

sequenceDiagram
    participant Compiler as Compiler<br/>(compile.rs)
    participant SymTable as Symbol Table<br/>(symboltable.rs)
    participant Resolution as Name Resolution<br/>(maybe_mangle_name)
    
    Compiler->>SymTable: enter_type_param_block(for_class: bool)
    SymTable->>SymTable: Initialize mangled_names set
    
    Compiler->>SymTable: register_name(name, usage)
    alt TypeParam usage
        SymTable->>SymTable: Add name to mangled_names
    end
    
    Compiler->>Compiler: Encounter name to mangle
    Compiler->>Resolution: maybe_mangle_name(class_name, mangled_names, name)
    
    alt name in mangled_names
        Resolution->>Resolution: Apply mangle_name()
        Resolution-->>Compiler: Return mangled name
    else name not in set or set is None
        Resolution-->>Compiler: Return original name
    end
    
    Compiler->>SymTable: Insert/lookup resolved name
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • arihant2math

Poem

🐰 A rabbit hops through scopes so deep,
Where type parameters their secrets keep,
Mangling names with selective care,
The symbol table's gotten quite aware!
Variances dance and aliases unfold,
Generic magic, wondrous and bold! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title broadly lists affected modules but does not clearly convey the specific changes or main intent of the pull request. Consider a more specific title that describes the primary change, such as 'Implement selective name mangling for generic type parameters' or 'Add selective mangling support for generic classes and type parameters'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@youknowone youknowone force-pushed the typing branch 2 times, most recently from 07fbdd0 to cf798e7 Compare February 13, 2026 05:13
@youknowone youknowone changed the title fix more typing Fix typing, typevar, genericalias, and symboltable Feb 13, 2026
- TypeVar/ParamSpec repr: use infer_variance flag
- ParamSpec: add type_check on bound argument
- ParamSpecArgs/Kwargs: use equality instead of identity
- NoDefault: change to IMMUTABLETYPE flag
- subscript_generic: wrap TypeVarTuple in Unpack
- symboltable: selective name mangling in type param scopes
- symboltable: fix double default scanning for non-generic fns
- Unmark 4 passing tests in test_type_params
@youknowone youknowone marked this pull request as ready for review February 13, 2026 09:09
@github-actions
Copy link
Contributor

📦 Library Dependencies

The following Lib/ modules were modified. Here are their dependencies:

[ ] lib: cpython/Lib/concurrent
[ ] test: cpython/Lib/test/test_concurrent_futures (TODO: 18)
[ ] test: cpython/Lib/test/test_interpreters
[ ] test: cpython/Lib/test/test__interpreters.py
[ ] test: cpython/Lib/test/test__interpchannels.py
[ ] test: cpython/Lib/test/test_crossinterp.py

dependencies:

  • concurrent (native: _interpqueues, _interpreters, concurrent.futures, concurrent.futures._base, itertools, multiprocessing.connection, multiprocessing.queues, sys, time)
    • collections (native: _weakref, itertools, sys)
    • logging (native: atexit, errno, logging.handlers, sys, time)
    • multiprocessing (native: _multiprocessing, _winapi, array, atexit, collections.abc, errno, itertools, mmap, msvcrt, sys, time)
    • pickle (native: itertools, sys)
    • types
    • functools, os, queue, threading, traceback, weakref

dependent tests: (11 tests)

  • concurrent: test_asyncio test_concurrent_futures test_context test_genericalias
    • asyncio: test_asyncio test_contextlib_async test_inspect test_logging test_os test_sys_settrace test_unittest

[x] lib: cpython/Lib/typing.py
[ ] test: cpython/Lib/test/test_typing.py (TODO: 5)
[x] test: cpython/Lib/test/test_type_aliases.py
[x] test: cpython/Lib/test/test_type_annotations.py (TODO: 1)
[x] test: cpython/Lib/test/test_type_params.py (TODO: 6)
[x] test: cpython/Lib/test/test_genericalias.py

dependencies:

  • typing

dependent tests: (14 tests)

  • typing: test_annotationlib test_builtin test_enum test_fractions test_funcattrs test_functools test_genericalias test_grammar test_isinstance test_pydoc test_type_aliases test_type_params test_types test_typing

Legend:

  • [+] path exists in CPython
  • [x] up-to-date, [ ] outdated

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/codegen/src/symboltable.rs (1)

1279-1322: ⚠️ Potential issue | 🔴 Critical

Base class names are mangled incorrectly due to class_name being set when scanning bases (regression).

In the old code, self.class_name = prev_class was restored immediately after self.leave_scope() and before scanning bases. The new code moved this restoration to after base scanning, leaving class_name set to the current class during base expression evaluation.

This breaks name mangling for nested classes with private base names:

Non-generic class: Bases are scanned with class_name = "Child" and mangled_names = None, so __Private gets mangled as _Child__Private. CPython mangles it as _Outer__Private (bases are evaluated in the enclosing scope).

Generic class: Bases are scanned with class_name = "Child" and mangled_names = Some({T}). Since __Private is not in the set, maybe_mangle_name returns it unmangled. CPython would mangle it as _Outer__Private.

Root cause: The refactored code moved self.class_name = prev_class (restoration of the enclosing class name) to line 1320, after bases are scanned (lines 1310–1315), whereas the old code restored it before scanning bases.

Fix: Restore self.class_name to prev_class (the enclosing class name) immediately after self.leave_scope() and before scanning base arguments.

🧹 Nitpick comments (2)
crates/vm/src/builtins/genericalias.rs (1)

737-766: Duplicated logic with unpack_typevartuples in typing.rs.

This TypeVarTuple unpacking logic (check downcast_ref::<TypeVarTuple>, wrap with Unpack.__getitem__) is essentially identical to unpack_typevartuples in crates/vm/src/stdlib/typing.rs (lines 469–490). Consider extracting a shared helper to avoid maintaining both copies.

Additionally, new_args (line 738) is allocated even when needs_unpack is false and the else branch returns params without using it. Move the allocation inside the if needs_unpack block.

Suggested refactor
-    // Unpack TypeVarTuples: wrap each TypeVarTuple in Unpack[...]
-    let mut new_args = Vec::with_capacity(params.len());
-    let mut needs_unpack = false;
-    for param in params.iter() {
-        if param
-            .downcast_ref::<crate::stdlib::typing::TypeVarTuple>()
-            .is_some()
-        {
-            needs_unpack = true;
-            break;
-        }
-    }
-
-    let args = if needs_unpack {
-        let unpack_cls = typing_module.get_attr("Unpack", vm)?;
-        for param in params.iter() {
-            if param
-                .downcast_ref::<crate::stdlib::typing::TypeVarTuple>()
-                .is_some()
-            {
-                let unpacked = vm.call_method(&unpack_cls, "__getitem__", (param.clone(),))?;
-                new_args.push(unpacked);
-            } else {
-                new_args.push(param.clone());
-            }
-        }
-        PyTuple::new_ref(new_args, &vm.ctx)
-    } else {
-        params
-    };
+    // Unpack TypeVarTuples: wrap each TypeVarTuple in Unpack[...]
+    let has_tvt = params
+        .iter()
+        .any(|p| p.downcast_ref::<crate::stdlib::typing::TypeVarTuple>().is_some());
+
+    let args = if has_tvt {
+        let unpack_cls = typing_module.get_attr("Unpack", vm)?;
+        let new_args: Vec<PyObjectRef> = params
+            .iter()
+            .map(|p| {
+                if p.downcast_ref::<crate::stdlib::typing::TypeVarTuple>().is_some() {
+                    vm.call_method(&unpack_cls, "__getitem__", (p.clone(),))
+                } else {
+                    Ok(p.clone())
+                }
+            })
+            .collect::<PyResult<_>>()?;
+        PyTuple::new_ref(new_args, &vm.ctx)
+    } else {
+        params
+    };

This also aligns the style with the existing unpack_typevartuples in crates/vm/src/stdlib/typing.rs (line 479–488), which uses the iterator/map/collect pattern.

crates/vm/src/stdlib/typevar.rs (1)

670-685: ParamSpec and TypeVar repr implementations are identical — consider extracting a shared helper.

The variance-prefix formatting logic (lines 674–684) is a direct copy of TypeVar's repr_str (lines 273–283). A small shared function like format_variance_prefix(name, infer_variance, covariant, contravariant) would eliminate the duplication.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant