Implement visitation of type aliases and parameters (#5927)

<!--
Thank you for contributing to Ruff! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

Part of #5062 
Requires https://github.com/astral-sh/RustPython-Parser/pull/32

Adds visitation of type alias statements and type parameters in class
and function definitions.

Duplicates tests for `PreorderVisitor` into `Visitor` with new
snapshots. Testing required node implementations for the `TypeParam`
enum, which is a chunk of the diff and the reason we need `Ranged`
implementations in
https://github.com/astral-sh/RustPython-Parser/pull/32.

## Test Plan

<!-- How was it tested? -->

Adds unit tests with snapshots.
This commit is contained in:
Zanie Blue 2023-07-25 12:11:26 -05:00 committed by GitHub
parent 3000a47fe8
commit 389fe13c93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 837 additions and 8 deletions

View file

@ -1,7 +1,8 @@
use rustpython_ast::{ArgWithDefault, ElifElseClause, Mod, TypeIgnore};
use rustpython_parser::ast::{
self, Alias, Arg, Arguments, BoolOp, CmpOp, Comprehension, Constant, Decorator, ExceptHandler,
Expr, Keyword, MatchCase, Operator, Pattern, Stmt, UnaryOp, WithItem,
Expr, Keyword, MatchCase, Operator, Pattern, Stmt, TypeParam, TypeParamTypeVar, UnaryOp,
WithItem,
};
/// Visitor that traverses all nodes recursively in pre-order.
@ -80,6 +81,10 @@ pub trait PreorderVisitor<'a> {
walk_with_item(self, with_item);
}
fn visit_type_param(&mut self, type_param: &'a TypeParam) {
walk_type_param(self, type_param);
}
fn visit_match_case(&mut self, match_case: &'a MatchCase) {
walk_match_case(self, match_case);
}
@ -156,6 +161,7 @@ where
body,
decorator_list,
returns,
type_params,
..
})
| Stmt::AsyncFunctionDef(ast::StmtAsyncFunctionDef {
@ -163,12 +169,17 @@ where
body,
decorator_list,
returns,
type_params,
..
}) => {
for decorator in decorator_list {
visitor.visit_decorator(decorator);
}
for type_param in type_params {
visitor.visit_type_param(type_param);
}
visitor.visit_arguments(args);
for expr in returns {
@ -183,12 +194,17 @@ where
keywords,
body,
decorator_list,
type_params,
..
}) => {
for decorator in decorator_list {
visitor.visit_decorator(decorator);
}
for type_param in type_params {
visitor.visit_type_param(type_param);
}
for expr in bases {
visitor.visit_expr(expr);
}
@ -218,6 +234,19 @@ where
}
}
Stmt::TypeAlias(ast::StmtTypeAlias {
range: _range,
name,
type_params,
value,
}) => {
visitor.visit_expr(name);
for type_param in type_params {
visitor.visit_type_param(type_param);
}
visitor.visit_expr(value);
}
Stmt::Assign(ast::StmtAssign {
targets,
value,
@ -400,7 +429,6 @@ where
| Stmt::Continue(_)
| Stmt::Global(_)
| Stmt::Nonlocal(_) => {}
Stmt::TypeAlias(_) => todo!(),
}
}
@ -805,6 +833,24 @@ where
}
}
pub fn walk_type_param<'a, V>(visitor: &mut V, type_param: &'a TypeParam)
where
V: PreorderVisitor<'a> + ?Sized,
{
match type_param {
TypeParam::TypeVar(TypeParamTypeVar {
bound,
name: _,
range: _,
}) => {
if let Some(expr) = bound {
visitor.visit_expr(expr);
}
}
TypeParam::TypeVarTuple(_) | TypeParam::ParamSpec(_) => {}
}
}
pub fn walk_match_case<'a, V>(visitor: &mut V, match_case: &'a MatchCase)
where
V: PreorderVisitor<'a> + ?Sized,
@ -947,9 +993,9 @@ mod tests {
use crate::visitor::preorder::{
walk_alias, walk_arg, walk_arguments, walk_comprehension, walk_except_handler, walk_expr,
walk_keyword, walk_match_case, walk_module, walk_pattern, walk_stmt, walk_type_ignore,
walk_with_item, Alias, Arg, Arguments, BoolOp, CmpOp, Comprehension, Constant,
ExceptHandler, Expr, Keyword, MatchCase, Mod, Operator, Pattern, PreorderVisitor, Stmt,
TypeIgnore, UnaryOp, WithItem,
walk_type_param, walk_with_item, Alias, Arg, Arguments, BoolOp, CmpOp, Comprehension,
Constant, ExceptHandler, Expr, Keyword, MatchCase, Mod, Operator, Pattern, PreorderVisitor,
Stmt, TypeIgnore, TypeParam, UnaryOp, WithItem,
};
#[test]
@ -1038,6 +1084,33 @@ class A:
assert_snapshot!(trace);
}
#[test]
fn type_aliases() {
let source = r#"type X[T: str, U, *Ts, **P] = list[T]"#;
let trace = trace_preorder_visitation(source);
assert_snapshot!(trace);
}
#[test]
fn class_type_parameters() {
let source = r#"class X[T: str, U, *Ts, **P]: ..."#;
let trace = trace_preorder_visitation(source);
assert_snapshot!(trace);
}
#[test]
fn function_type_parameters() {
let source = r#"def X[T: str, U, *Ts, **P](): ..."#;
let trace = trace_preorder_visitation(source);
assert_snapshot!(trace);
}
fn trace_preorder_visitation(source: &str) -> String {
let tokens = lex(source, Mode::Module);
let parsed = parse_tokens(tokens, Mode::Module, "test.py").unwrap();
@ -1188,5 +1261,11 @@ class A:
walk_type_ignore(self, type_ignore);
self.exit_node();
}
fn visit_type_param(&mut self, type_param: &TypeParam) {
self.enter_node(type_param);
walk_type_param(self, type_param);
self.exit_node();
}
}
}