Skip to content

handle type annotations in nested functions correctly#7072

Merged
youknowone merged 1 commit intoRustPython:mainfrom
elmjag:nested-funcs-annotations
Feb 10, 2026
Merged

handle type annotations in nested functions correctly#7072
youknowone merged 1 commit intoRustPython:mainfrom
elmjag:nested-funcs-annotations

Conversation

@elmjag
Copy link
Contributor

@elmjag elmjag commented Feb 10, 2026

For example in the following code:

def foo(x: int, y: float):
    def bar(q: int):
        return q
    pass

Make sure that foo type annotations are correctly propogated to it's __annotate__ and __annotations__ attributes.

With this chage, we'll get:

>>>>> foo.__annotations__
{'x': <class 'int'>, 'y': <class 'float'>}

Previously annotations where 'lost', and we would get:

>>>>> foo.__annotations__
{}

Summary by CodeRabbit

  • Refactor
    • Improved internal handling of annotation scopes so annotations are preserved and restored more consistently around definition boundaries, reducing rare inconsistencies and improving overall stability and predictability.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 10, 2026

📝 Walkthrough

Walkthrough

The SymbolTableBuilder::scan_statement handling for FunctionDef now saves/restores the current scope's annotation_block for Function and AsyncFunction in addition to Class and Module, extending annotation scope preservation to function definitions.

Changes

Cohort / File(s) Summary
Annotation Block Handling
crates/codegen/src/symboltable.rs
Adjusted the condition in the FunctionDef branch to include Function and AsyncFunction alongside Class and Module when deciding to save the current scope's annotation_block, ensuring annotation scopes are captured/restored around function definitions.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

🐰✍️ I hopped through scopes both near and far,
Saved annotations like a tiny star.
Functions now hold what they once forgot,
Restored with care — a neat little plot. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly relates to the main change: expanding annotation_block preservation to nested functions (Function/AsyncFunction) to correctly handle type annotations in nested functions.

✏️ 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

No actionable comments were generated in the recent review. 🎉


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.

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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@crates/codegen/src/symboltable.rs`:
- Around line 1137-1142: The matches expression that sets
should_save_annotation_block currently checks parent_scope_typ for
CompilerScope::Class, ::Module, and ::Function but omits
CompilerScope::AsyncFunction; update the matches to include
Some(CompilerScope::AsyncFunction) so async functions are treated the same as
normal functions when deciding to save/restore annotation blocks (referencing
the local variables should_save_annotation_block and parent_scope_typ in
symboltable.rs).

For example in the following code:

    def foo(x: int, y: float):
        def bar(q: int):
            return q
        pass

Make sure that `foo` type annotations are correctly propogated to
it's `__annotate__` and `__annotations__` attributes.

With this chage, we'll get:

    >>>>> foo.__annotations__
    {'x': <class 'int'>, 'y': <class 'float'>}

Previously annotations where 'lost', and we would get:

    >>>>> foo.__annotations__
    {}
@elmjag elmjag force-pushed the nested-funcs-annotations branch from 890e8ed to 2c83511 Compare February 10, 2026 14:07
@github-actions
Copy link
Contributor

📦 Library Dependencies

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

[ ] lib: cpython/Lib/typing.py
[ ] test: cpython/Lib/test/test_typing.py (TODO: 19)
[ ] test: cpython/Lib/test/test_type_aliases.py
[ ] test: cpython/Lib/test/test_type_annotations.py
[ ] test: cpython/Lib/test/test_type_params.py
[ ] test: cpython/Lib/test/test_genericalias.py (TODO: 3)

dependencies:

  • typing (native: _typing, collections.abc, sys)
    • collections (native: _weakref, itertools, sys)
    • types
    • abc, copyreg, functools, operator

dependent tests: (10 tests)

  • typing: test_annotationlib test_builtin test_enum test_fractions test_functools test_genericalias test_grammar test_isinstance test_types test_typing

Legend:

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

Copy link
Member

@youknowone youknowone left a comment

Choose a reason for hiding this comment

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

👍 Thank you!

@youknowone youknowone merged commit fde808e into RustPython:main Feb 10, 2026
13 of 14 checks passed
@elmjag elmjag deleted the nested-funcs-annotations branch February 12, 2026 13:46
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.

2 participants