◐ Shell
reader mode source ↗
Skip to content

compiler parity for typealias#7645

Merged
youknowone merged 1 commit into
RustPython:mainfrom
youknowone:bytecode-parity-typealias
Apr 21, 2026
Merged

compiler parity for typealias#7645
youknowone merged 1 commit into
RustPython:mainfrom
youknowone:bytecode-parity-typealias

Conversation

@youknowone

@youknowone youknowone commented Apr 21, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Bug Fixes

    • Fixed type annotation scoping and free variable resolution in function contexts
    • Improved type alias value closure compilation for more accurate lazy evaluation
  • Chores

    • Enhanced symbol table analysis for annotation and type parameter handling
    • Updated type mapping in symbol table introspection to correctly identify annotation and function scopes

@coderabbitai

coderabbitai Bot commented Apr 21, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The pull request refactors symbol table and code generation for PEP 695 type aliases and PEP 649 annotations. It introduces CompilerScope::Annotation for annotation-specific scoping, adjusts free-variable selection to exclude annotation-related names, modifies type alias and type parameter compilation to use annotation scopes with dedicated closure helpers, and updates the Python-exposed symtable API to properly map new scope variants.

Changes

Cohort / File(s) Summary
Type Alias & Annotation Scope Compilation
crates/codegen/src/compile.rs
Introduces compile_typealias_value_closure helper; refactors type alias codegen to build 3-tuple and call IntrinsicFunction1::TypeAlias directly; modifies type parameter bound/default compilation to use CompilerScope::Annotation with MakeFunctionFlag::Defaults; updates varname keys from "format" to ".format".
Free Variable & Name Opcode Handling
crates/codegen/src/compile.rs
Filters free names in enter_scope to exclude annotation-related symbols with empty flags; adjusts make_qualname to skip CompilerScope::Annotation like TypeParams; changes SymbolScope::GlobalExplicit name opcode selection to conditionally use NameOp::DictOrGlobals based on can_see_class_scope.
Symbol Table Analysis & Annotation Scopes
crates/codegen/src/symboltable.rs
Adds skip_enclosing_function_scope field to SymbolTable and threads it through analyzer stack; enters CompilerScope::Annotation for PEP 649 and type alias/parameter scopes; adjusts evaluator parameter registration from "format" to ".format" for annotation contexts.
Python-Exposed Symtable API
crates/vm/src/stdlib/_symtable.rs
Updates type getter for symtable entry to map AsyncFunction, Lambda, Comprehension to TYPE_FUNCTION; adds AnnotationTYPE_ANNOTATION mapping; removes -1 fallback for unhandled scope variants.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 In scope we hop, through annotations so fair,
Where type aliases dance in the annotation air,
New helpers compile the closures with care,
Free variables skip with skip_enclosing_function_scope where fair,
From .format names to tuples we dare! 🎯

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.71% 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 'compiler parity for typealias' is partially related to the changeset. It correctly identifies that the PR addresses TypeAlias functionality, but it is overly broad and vague. It doesn't clarify what specific aspect of 'parity' is being achieved (bytecode generation, scoping rules, annotation handling, etc.), and it obscures the broader scope of changes that also affect annotation handling, type parameters, and symbol table analysis beyond just TypeAlias. Consider a more specific title that captures the core change, such as 'Refactor annotation scoping for typealias and type parameters' or 'Update compiler annotation scope handling for PEP 695 parity'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 bytecode-parity-typealias branch from 76ef95e to 8a0f9ba Compare April 21, 2026 04:38
@github-actions

Copy link
Copy Markdown
Contributor

📦 Library Dependencies

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

[x] test: cpython/Lib/test/test_compile.py (TODO: 18)
[x] test: cpython/Lib/test/test_compiler_assemble.py
[x] test: cpython/Lib/test/test_compiler_codegen.py
[x] test: cpython/Lib/test/test_peepholer.py (TODO: 12)

dependencies:

dependent tests: (no tests depend on compile)

Legend:

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

@youknowone youknowone marked this pull request as ready for review April 21, 2026 13:30

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hide comment

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (3)
crates/codegen/src/compile.rs (3)

4585-4592: ⚠️ Potential issue | 🟡 Minor

Use the same format varname as the module/class annotation symbol table.

symboltable.rs registers module/class __annotate__ scopes with "format", but Line 4589 appends ".format". Since enter_scope already copies symbol-table varnames, this creates an extra unused local and breaks co_varnames parity.

Proposed fix
         self.current_code_info()
             .metadata
             .varnames
-            .insert(".format".to_owned());
+            .insert("format".to_owned());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/codegen/src/compile.rs` around lines 4585 - 4592, The code is
inserting ".format" into the current code object's metadata.varnames, creating
an extra local that breaks co_varnames parity with symboltable.rs which
registers "format" for __annotate__ scopes; change the insertion in the block
that calls self.current_code_info().metadata.varnames.insert(...) to insert
"format" (no leading dot) so it matches the symbol-table/enter_scope behavior
and keeps co_varnames aligned with emit_format_validation() and the __annotate__
scopes managed in symboltable.rs.

1892-1911: ⚠️ Potential issue | 🟠 Major

Skip synthetic parents repeatedly when building __qualname__.

This only skips one parent. For a nested scope inside an annotation scope inside a type-params scope, the grandparent can still be TypeParams, so the generated qualname can include <generic parameters of ...> instead of the real owner.

Proposed fix
-        let parent_scope = self
-            .symbol_table_stack
-            .get(parent_idx)
-            .map(|table| table.typ);
-
-        // CPython skips both generic-parameter scopes and annotation scopes
-        // when building qualnames for the contained function/class code object.
-        if matches!(
-            parent_scope,
-            Some(CompilerScope::TypeParams | CompilerScope::Annotation)
-        ) || parent.metadata.name.starts_with("<generic parameters of ")
-        {
-            if stack_size == 2 {
-                // If we're immediately within the module, qualname is just the name
-                return current_obj_name;
-            }
-            // Use grandparent
-            parent_idx = stack_size - 3;
-            parent = &self.code_stack[parent_idx];
-        }
+        // CPython skips generic-parameter and annotation scopes when building
+        // qualnames for contained function/class code objects. These synthetic
+        // scopes can be stacked, so keep walking until a real parent is found.
+        loop {
+            let parent_scope = self
+                .symbol_table_stack
+                .get(parent_idx)
+                .map(|table| table.typ);
+            let skip_parent = matches!(
+                parent_scope,
+                Some(CompilerScope::TypeParams | CompilerScope::Annotation)
+            ) || parent.metadata.name.starts_with("<generic parameters of ");
+            if !skip_parent {
+                break;
+            }
+            if parent_idx == 0 {
+                return current_obj_name;
+            }
+            parent_idx -= 1;
+            parent = &self.code_stack[parent_idx];
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/codegen/src/compile.rs` around lines 1892 - 1911, The current logic
only skips one synthetic parent when building __qualname__ (using parent_scope,
symbol_table_stack and checks for CompilerScope::TypeParams |
CompilerScope::Annotation and parent.metadata.name starting with "<generic
parameters of "), which can leave further synthetic ancestors in place; change
this to repeatedly skip synthetic parents by looping (while) to move parent_idx
up until the parent is not a TypeParams/Annotation and its metadata.name is not
the generic-parameters sentinel, updating parent_scope and parent from
symbol_table_stack and code_stack each iteration, and preserve the existing
early-return when the adjusted stack_size indicates the module-level parent
(using stack_size to decide when to return current_obj_name).

3011-3016: ⚠️ Potential issue | 🔴 Critical

Fix type-parameter evaluator parameter spelling to match type-alias evaluator and symbol table registration.

Change "format" to ".format" at line 3012. The type-parameter bound/default evaluator scope should use the same parameter name as the type-alias evaluator (compile_typealias_value_closure line 3068) and the symbol table registration (symboltable.rs lines 1803, 2323), which all use ".format". Using different spellings will create inconsistent co_varnames indices.

Current code
        self.current_code_info()
            .metadata
            .varnames
            .insert("format".to_owned());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/codegen/src/compile.rs` around lines 3011 - 3016, The varname inserted
into the current code info is misspelled — replace the string "format" with
".format" in the call to self.current_code_info().metadata.varnames.insert(...)
so the type-parameter evaluator parameter matches the type-alias evaluator (see
compile_typealias_value_closure) and the symbol table registration entries; this
ensures co_varnames indices remain consistent with emit_format_validation() and
the symbol table registrations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/codegen/src/compile.rs`:
- Around line 2329-2335: The branch for SymbolScope::GlobalExplicit incorrectly
falls back to checking can_see_class_scope and returning NameOp::DictOrGlobals;
update the match arm handling SymbolScope::GlobalExplicit so it unconditionally
returns NameOp::Global (remove the can_see_class_scope check and the
NameOp::DictOrGlobals path) so explicit global declarations always use
NameOp::Global instead of class-dict lookup.

In `@crates/codegen/src/symboltable.rs`:
- Around line 1769-1778: Update the grammatically incorrect error string in the
SymbolTableError returned from the name.as_name_expr() check: replace "type
alias expect name" with a clear message such as "type alias expects name" or
"type alias must be a Name node" in the code inside the conditional that checks
let Some(name_expr) = name.as_name_expr(); ensure the replacement occurs where
SymbolTableError { error: ... } is constructed so the new message is
logged/returned; optionally add or adjust a unit test to exercise this error
path to validate the corrected message.

---

Outside diff comments:
In `@crates/codegen/src/compile.rs`:
- Around line 4585-4592: The code is inserting ".format" into the current code
object's metadata.varnames, creating an extra local that breaks co_varnames
parity with symboltable.rs which registers "format" for __annotate__ scopes;
change the insertion in the block that calls
self.current_code_info().metadata.varnames.insert(...) to insert "format" (no
leading dot) so it matches the symbol-table/enter_scope behavior and keeps
co_varnames aligned with emit_format_validation() and the __annotate__ scopes
managed in symboltable.rs.
- Around line 1892-1911: The current logic only skips one synthetic parent when
building __qualname__ (using parent_scope, symbol_table_stack and checks for
CompilerScope::TypeParams | CompilerScope::Annotation and parent.metadata.name
starting with "<generic parameters of "), which can leave further synthetic
ancestors in place; change this to repeatedly skip synthetic parents by looping
(while) to move parent_idx up until the parent is not a TypeParams/Annotation
and its metadata.name is not the generic-parameters sentinel, updating
parent_scope and parent from symbol_table_stack and code_stack each iteration,
and preserve the existing early-return when the adjusted stack_size indicates
the module-level parent (using stack_size to decide when to return
current_obj_name).
- Around line 3011-3016: The varname inserted into the current code info is
misspelled — replace the string "format" with ".format" in the call to
self.current_code_info().metadata.varnames.insert(...) so the type-parameter
evaluator parameter matches the type-alias evaluator (see
compile_typealias_value_closure) and the symbol table registration entries; this
ensures co_varnames indices remain consistent with emit_format_validation() and
the symbol table registrations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 35eaf435-1de2-4960-af00-7f73988741ce

📥 Commits

Reviewing files that changed from the base of the PR and between d5921d1 and 8a0f9ba.

⛔ Files ignored due to path filters (1)
  • Lib/test/test_compile.py is excluded by !Lib/**
📒 Files selected for processing (3)
  • crates/codegen/src/compile.rs
  • crates/codegen/src/symboltable.rs
  • crates/vm/src/stdlib/_symtable.rs

Hide details View details @youknowone youknowone merged commit b929a50 into RustPython:main Apr 21, 2026
21 checks passed
@youknowone youknowone deleted the bytecode-parity-typealias branch April 21, 2026 14:59
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