Skip to content

Conversation

@ShenaoW
Copy link
Collaborator

@ShenaoW ShenaoW commented Dec 30, 2025

Description

This PR adds comprehensive support for complex type annotations in the YASA-UAST Python parser, addressing the issue described in #39.

Changes

1. Extended Type Annotation Parsing

Added a comprehensive _parse_type_annotation method that supports:

  • Basic Types: int, float, str, bool, None
  • Generic Types:
    • List[T]ArrayType(element=T)
    • Dict[K, V]MapType(keyType=K, valueType=V)
    • Tuple[T1, T2, ...]DynamicType(id="Tuple", typeArguments=[T1, T2, ...])
    • Set[T]DynamicType(id="Set", typeArguments=[T])
  • Special Types:
    • Optional[T]DynamicType(id="Optional", typeArguments=[T])
    • Union[T1, T2, ...]DynamicType(id="Union", typeArguments=[T1, T2, ...])
    • Literal[value, ...]DynamicType(id="Literal", typeArguments=[...])
    • AnyDynamicType()
  • Callable Types: Callable[[Args], ReturnType] with proper separation of parameter types and return type
  • Nested Types: Recursive parsing for nested type annotations
  • Python 3.9+ Syntax: Support for built-in generic syntax (list[T], dict[K, V], etc.)

2. Updated Function and Variable Annotation Handling

  • Modified visit_FunctionDef to use _parse_type_annotation for return types
  • Modified visit_AnnAssign to use _parse_type_annotation for variable annotations
  • Added support for ast.Constant(value=None) for None type annotations (Python 3.8+)

3. Test Cases

Added comprehensive test cases in parser-Python/test/case.py covering:

  • Basic types
  • Generic types (List, Dict, Tuple, Set)
  • Special types (Optional, Union, Literal)
  • Nested types
  • Complex combined types

Implementation Details

Type Mapping

Python Type Annotation UAST Representation
int, float PrimitiveType(kind="number")
str PrimitiveType(kind="string")
bool PrimitiveType(kind="boolean")
None PrimitiveType(kind="null")
List[T] ArrayType(element=T)
Dict[K, V] MapType(keyType=K, valueType=V)
Tuple[T1, T2, ...] DynamicType(id="Tuple", typeArguments=[T1, T2, ...])
Optional[T] DynamicType(id="Optional", typeArguments=[T])
Union[T1, T2, ...] DynamicType(id="Union", typeArguments=[T1, T2, ...])
Literal[value, ...] DynamicType(id="Literal", typeArguments=[Literal(...)])
Callable[[Args], Ret] DynamicType(id="Callable", typeArguments=[Params, Ret])
MyClass[T] DynamicType(id="MyClass", typeArguments=[T])

Testing

  • Tested with basic types (int, str, bool, None)
  • Tested with generic types (List[int], Dict[str, int])
  • Tested with special types (Optional[str], Union[int, str], Literal["a", "b"])
  • Tested with nested types (List[Dict[str, int]])
  • Tested with complex combinations (Optional[List[Dict[str, Union[int, str]]]])
  • Tested with Callable types (Callable[[int, str], bool])
  • Tested with user-defined generic types (MyClass[str])

Examples

Before (Issue)

def list_type() -> List[int]:
    return [1, 2, 3]

Result: return_type = None

After (This PR)

def list_type() -> List[int]:
    return [1, 2, 3]

Result: return_type = ArrayType(element=PrimitiveType(kind="number"))


Note

Adds full-featured type-annotation parsing to the Python UAST transformer and applies it across return/parameter/variable annotations.

  • Introduces _parse_type_annotation supporting int/float/str/bool/None, list/dict/tuple/set, Optional, Union (incl. |), Literal, Any, Callable, and generic/user-defined types; maps to UAST PrimitiveType, ArrayType, MapType, and DynamicType with typeArguments
  • Refactors visit_FunctionDef, visit_arguments, and visit_AnnAssign to use unified parsing for return types and parameter/variable annotations
  • Adds comprehensive tests in parser-Python/test/test_type_annotations.py covering basic, container, special, callable, nested, and generic scenarios
  • Minor: include MapType in uast/asttype.Node union; update .gitignore with .vscode/

Written by Cursor Bugbot for commit c219c8b. This will update automatically on new commits. Configure here.

@gemini-code-assist
Copy link

Summary of Changes

Hello @ShenaoW, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly upgrades the YASA-UAST Python parser by introducing robust support for complex type annotations. It centralizes the parsing logic for various type hints, ensuring that the Universal Abstract Syntax Tree accurately reflects the rich type information present in modern Python code. This enhancement resolves a long-standing issue and improves the parser's fidelity for static analysis and code understanding.

Highlights

  • Extended Type Annotation Parsing: Introduced a new _parse_type_annotation method to comprehensively handle various Python type annotations, including basic types (int, float, str, bool, None), generic types (List, Dict, Tuple, Set), special types (Optional, Union, Literal, Any), Callable types, nested types, and Python 3.9+ generic syntax.
  • Unified Annotation Handling: Integrated the new _parse_type_annotation method into visit_FunctionDef for function return types, visit_arguments for function parameter types, and visit_AnnAssign for variable annotations, replacing previous ad-hoc parsing logic.
  • Comprehensive Test Coverage: Added a new test file parser-Python/test/test_type_annotations.py with extensive test cases covering a wide array of type annotation scenarios to validate the new parsing capabilities.
  • Gitignore Update: Added new entries to .gitignore for Snyk Security Extension related files.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new, comprehensive test suite for Python type annotations in test_type_annotations.py, covering basic types, container types, special types, generics, and newer Python syntax (3.9+, 3.10+). Concurrently, uast/visitor.py was updated to include a new private method, _parse_type_annotation, which centralizes the parsing logic for various AST type annotation nodes into UAST type nodes. This new method is then integrated into visit_FunctionDef, visit_arguments, and visit_AnnAssign to uniformly handle return types, parameter types, and variable annotations, replacing previous ad-hoc parsing. Review comments identified an issue with ArrayType construction in the new parsing logic, suggested adding a test case for Callable with no arguments, and recommended a stylistic improvement for type name checks.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

# Callable[..., bool] → Params 包装器, typeArguments=None(None,表示任意参数)
# Callable[[int, str], bool] → Params 包装器, typeArguments=[int, str](具体参数类型)
param_types_list = self.packPos(param_list_node, UNode.ArrayType(UNode.SourceLocation(),
UNode.Meta(), element=param_types if param_types else []))
Copy link

Choose a reason for hiding this comment

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

ArrayType element receives list instead of single type

High Severity

When handling Callable parameter types, the code creates an ArrayType with element=param_types, but param_types is a list of types (accumulated via append in the loop). According to ArrayType in asttype.py, the element field expects a single Type, not a list. This semantic mismatch will cause the UAST to have an incorrect structure for Callable parameter representations, potentially breaking downstream consumers that expect ArrayType.element to be a single type value.

Fix in Cursor Fix in Web

elif isinstance(param_list_node, ast.Constant) and param_list_node.value == ...:
# Callable[..., ReturnType] 表示任意参数
param_types_list = self.packPos(param_list_node, UNode.DynamicType(UNode.SourceLocation(),
UNode.Meta(), id="Params", typeArguments="Ellipsis")) # Any 表示任意参数
Copy link

Choose a reason for hiding this comment

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

DynamicType typeArguments receives string instead of list

High Severity

When handling Callable[..., ReturnType] (ellipsis parameters), the code passes typeArguments="Ellipsis" as a string literal to DynamicType. However, the typeArguments field in DynamicType is defined as Optional[List['Type']], not a string. This type mismatch will produce invalid UAST nodes that don't conform to the expected schema and may cause errors in downstream processing.

Fix in Cursor Fix in Web

@Arielwyy Arielwyy merged commit dc3a01c into antgroup:main Jan 8, 2026
1 check passed
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