From 8a0f84464256add13c019047e6803fe8a63736f6 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 2 Aug 2023 12:47:06 -0400 Subject: [PATCH] Box type params and arguments fields on the class definition node (#6275) ## Summary This PR boxes the `TypeParams` and `Arguments` fields on the class definition node. These fields are optional and often emitted, and given that class definition is our largest enum variant, we pay the cost of including them for every statement in the AST. Boxing these types reduces the statement size by 40 bytes, which seems like a good tradeoff given how infrequently these are accessed. ## Test Plan Need to benchmark, but no behavior changes. --- .../src/checkers/ast/analyze/expression.rs | 2 +- .../src/checkers/ast/analyze/statement.rs | 18 +++--- .../rules/builtin_attribute_shadowing.rs | 2 +- .../rules/model_without_dunder_str.rs | 2 +- .../flake8_pie/rules/non_unique_enums.rs | 10 +--- .../flake8_pyi/rules/non_self_return_type.rs | 4 +- .../rules/flake8_pyi/rules/simple_defaults.rs | 2 +- .../rules/unused_private_type_definition.rs | 28 +++------- .../rules/no_slots_in_namedtuple_subclass.rs | 2 +- .../rules/no_slots_in_str_subclass.rs | 2 +- .../rules/no_slots_in_tuple_subclass.rs | 2 +- .../src/rules/flake8_type_checking/helpers.rs | 56 ++++++++----------- ...convert_named_tuple_functional_to_class.rs | 4 +- .../convert_typed_dict_functional_to_class.rs | 4 +- .../rules/unnecessary_class_parentheses.rs | 2 +- .../rules/useless_object_inheritance.rs | 2 +- crates/ruff/src/rules/ruff/rules/helpers.rs | 2 +- crates/ruff_python_ast/src/comparable.rs | 22 +++++--- crates/ruff_python_ast/src/helpers.rs | 2 +- crates/ruff_python_ast/src/nodes.rs | 9 +-- .../src/statement/stmt_class_def.rs | 2 +- crates/ruff_python_parser/src/python.lalrpop | 4 +- crates/ruff_python_parser/src/python.rs | 6 +- 23 files changed, 87 insertions(+), 102 deletions(-) diff --git a/crates/ruff/src/checkers/ast/analyze/expression.rs b/crates/ruff/src/checkers/ast/analyze/expression.rs index 7cb5268c12..3918ef9d23 100644 --- a/crates/ruff/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff/src/checkers/ast/analyze/expression.rs @@ -218,7 +218,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { checker, expr, id, - arguments.as_ref(), + arguments.as_deref(), ); } } diff --git a/crates/ruff/src/checkers/ast/analyze/statement.rs b/crates/ruff/src/checkers/ast/analyze/statement.rs index cfb8d24b22..55e34d28cd 100644 --- a/crates/ruff/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff/src/checkers/ast/analyze/statement.rs @@ -374,15 +374,17 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { flake8_django::rules::nullable_model_string_field(checker, body); } if checker.enabled(Rule::DjangoExcludeWithModelForm) { - if let Some(diagnostic) = - flake8_django::rules::exclude_with_model_form(checker, arguments.as_ref(), body) - { + if let Some(diagnostic) = flake8_django::rules::exclude_with_model_form( + checker, + arguments.as_deref(), + body, + ) { checker.diagnostics.push(diagnostic); } } if checker.enabled(Rule::DjangoAllWithModelForm) { if let Some(diagnostic) = - flake8_django::rules::all_with_model_form(checker, arguments.as_ref(), body) + flake8_django::rules::all_with_model_form(checker, arguments.as_deref(), body) { checker.diagnostics.push(diagnostic); } @@ -390,7 +392,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::DjangoUnorderedBodyContentInModel) { flake8_django::rules::unordered_body_content_in_model( checker, - arguments.as_ref(), + arguments.as_deref(), body, ); } @@ -428,7 +430,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { if checker.enabled(Rule::ErrorSuffixOnExceptionName) { if let Some(diagnostic) = pep8_naming::rules::error_suffix_on_exception_name( stmt, - arguments.as_ref(), + arguments.as_deref(), name, &checker.settings.pep8_naming.ignore_names, ) { @@ -444,7 +446,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { checker, stmt, name, - arguments.as_ref(), + arguments.as_deref(), body, ); } @@ -485,7 +487,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) { flake8_builtins::rules::builtin_variable_shadowing(checker, name, name.range()); } if checker.enabled(Rule::DuplicateBases) { - pylint::rules::duplicate_bases(checker, name, arguments.as_ref()); + pylint::rules::duplicate_bases(checker, name, arguments.as_deref()); } if checker.enabled(Rule::NoSlotsInStrSubclass) { flake8_slots::rules::no_slots_in_str_subclass(checker, stmt, class_def); diff --git a/crates/ruff/src/rules/flake8_builtins/rules/builtin_attribute_shadowing.rs b/crates/ruff/src/rules/flake8_builtins/rules/builtin_attribute_shadowing.rs index 19c73550cb..a2e7347a1b 100644 --- a/crates/ruff/src/rules/flake8_builtins/rules/builtin_attribute_shadowing.rs +++ b/crates/ruff/src/rules/flake8_builtins/rules/builtin_attribute_shadowing.rs @@ -132,7 +132,7 @@ fn is_standard_library_override( class_def: &ast::StmtClassDef, model: &SemanticModel, ) -> bool { - let Some(Arguments { args: bases, .. }) = class_def.arguments.as_ref() else { + let Some(Arguments { args: bases, .. }) = class_def.arguments.as_deref() else { return false; }; match name { diff --git a/crates/ruff/src/rules/flake8_django/rules/model_without_dunder_str.rs b/crates/ruff/src/rules/flake8_django/rules/model_without_dunder_str.rs index f73921212c..ed310166bc 100644 --- a/crates/ruff/src/rules/flake8_django/rules/model_without_dunder_str.rs +++ b/crates/ruff/src/rules/flake8_django/rules/model_without_dunder_str.rs @@ -60,7 +60,7 @@ pub(crate) fn model_without_dunder_str( .. }: &ast::StmtClassDef, ) { - if !is_non_abstract_model(arguments.as_ref(), body, checker.semantic()) { + if !is_non_abstract_model(arguments.as_deref(), body, checker.semantic()) { return; } if has_dunder_method(body) { diff --git a/crates/ruff/src/rules/flake8_pie/rules/non_unique_enums.rs b/crates/ruff/src/rules/flake8_pie/rules/non_unique_enums.rs index bf8c5ba99c..1ce7512c45 100644 --- a/crates/ruff/src/rules/flake8_pie/rules/non_unique_enums.rs +++ b/crates/ruff/src/rules/flake8_pie/rules/non_unique_enums.rs @@ -1,10 +1,10 @@ -use ruff_python_ast::{self as ast, Arguments, Expr, Ranged, Stmt}; use rustc_hash::FxHashSet; use ruff_diagnostics::Diagnostic; use ruff_diagnostics::Violation; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::comparable::ComparableExpr; +use ruff_python_ast::{self as ast, Expr, Ranged, Stmt}; use crate::checkers::ast::Checker; @@ -54,15 +54,11 @@ impl Violation for NonUniqueEnums { /// PIE796 pub(crate) fn non_unique_enums(checker: &mut Checker, parent: &Stmt, body: &[Stmt]) { - let Stmt::ClassDef(ast::StmtClassDef { - arguments: Some(Arguments { args: bases, .. }), - .. - }) = parent - else { + let Stmt::ClassDef(parent) = parent else { return; }; - if !bases.iter().any(|expr| { + if !parent.bases().any(|expr| { checker .semantic() .resolve_call_path(expr) diff --git a/crates/ruff/src/rules/flake8_pyi/rules/non_self_return_type.rs b/crates/ruff/src/rules/flake8_pyi/rules/non_self_return_type.rs index da09ce0246..e88e6d3f37 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/non_self_return_type.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/non_self_return_type.rs @@ -186,7 +186,7 @@ pub(crate) fn non_self_return_type( match name { "__iter__" => { if is_iterable(returns, checker.semantic()) - && is_iterator(class_def.arguments.as_ref(), checker.semantic()) + && is_iterator(class_def.arguments.as_deref(), checker.semantic()) { checker.diagnostics.push(Diagnostic::new( NonSelfReturnType { @@ -199,7 +199,7 @@ pub(crate) fn non_self_return_type( } "__aiter__" => { if is_async_iterable(returns, checker.semantic()) - && is_async_iterator(class_def.arguments.as_ref(), checker.semantic()) + && is_async_iterator(class_def.arguments.as_deref(), checker.semantic()) { checker.diagnostics.push(Diagnostic::new( NonSelfReturnType { diff --git a/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs b/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs index cf106710ac..ef3ef722af 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/simple_defaults.rs @@ -570,7 +570,7 @@ pub(crate) fn unannotated_assignment_in_stub( } if let ScopeKind::Class(ast::StmtClassDef { arguments, .. }) = checker.semantic().scope().kind { - if is_enum(arguments.as_ref(), checker.semantic()) { + if is_enum(arguments.as_deref(), checker.semantic()) { return; } } diff --git a/crates/ruff/src/rules/flake8_pyi/rules/unused_private_type_definition.rs b/crates/ruff/src/rules/flake8_pyi/rules/unused_private_type_definition.rs index d55b5f47ca..ddd57f9ccb 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/unused_private_type_definition.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/unused_private_type_definition.rs @@ -1,6 +1,6 @@ use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, Arguments, Expr, Stmt}; +use ruff_python_ast::{self as ast, Expr, Stmt}; use ruff_python_semantic::Scope; use crate::checkers::ast::Checker; @@ -217,17 +217,12 @@ pub(crate) fn unused_private_protocol( continue; }; - let Stmt::ClassDef(ast::StmtClassDef { - name, - arguments: Some(Arguments { args: bases, .. }), - .. - }) = checker.semantic().stmts[source] - else { + let Stmt::ClassDef(class_def) = checker.semantic().stmts[source] else { continue; }; - if !bases - .iter() + if !class_def + .bases() .any(|base| checker.semantic().match_typing_expr(base, "Protocol")) { continue; @@ -235,7 +230,7 @@ pub(crate) fn unused_private_protocol( diagnostics.push(Diagnostic::new( UnusedPrivateProtocol { - name: name.to_string(), + name: class_def.name.to_string(), }, binding.range, )); @@ -308,17 +303,12 @@ pub(crate) fn unused_private_typed_dict( let Some(source) = binding.source else { continue; }; - let Stmt::ClassDef(ast::StmtClassDef { - name, - arguments: Some(Arguments { args: bases, .. }), - .. - }) = checker.semantic().stmts[source] - else { + let Stmt::ClassDef(class_def) = checker.semantic().stmts[source] else { continue; }; - if !bases - .iter() + if !class_def + .bases() .any(|base| checker.semantic().match_typing_expr(base, "TypedDict")) { continue; @@ -326,7 +316,7 @@ pub(crate) fn unused_private_typed_dict( diagnostics.push(Diagnostic::new( UnusedPrivateTypedDict { - name: name.to_string(), + name: class_def.name.to_string(), }, binding.range, )); diff --git a/crates/ruff/src/rules/flake8_slots/rules/no_slots_in_namedtuple_subclass.rs b/crates/ruff/src/rules/flake8_slots/rules/no_slots_in_namedtuple_subclass.rs index 3e8f1ca593..bffa54d55a 100644 --- a/crates/ruff/src/rules/flake8_slots/rules/no_slots_in_namedtuple_subclass.rs +++ b/crates/ruff/src/rules/flake8_slots/rules/no_slots_in_namedtuple_subclass.rs @@ -63,7 +63,7 @@ pub(crate) fn no_slots_in_namedtuple_subclass( stmt: &Stmt, class: &StmtClassDef, ) { - let Some(Arguments { args: bases, .. }) = class.arguments.as_ref() else { + let Some(Arguments { args: bases, .. }) = class.arguments.as_deref() else { return; }; diff --git a/crates/ruff/src/rules/flake8_slots/rules/no_slots_in_str_subclass.rs b/crates/ruff/src/rules/flake8_slots/rules/no_slots_in_str_subclass.rs index ca41e61afe..45213759fb 100644 --- a/crates/ruff/src/rules/flake8_slots/rules/no_slots_in_str_subclass.rs +++ b/crates/ruff/src/rules/flake8_slots/rules/no_slots_in_str_subclass.rs @@ -51,7 +51,7 @@ impl Violation for NoSlotsInStrSubclass { /// SLOT000 pub(crate) fn no_slots_in_str_subclass(checker: &mut Checker, stmt: &Stmt, class: &StmtClassDef) { - let Some(Arguments { args: bases, .. }) = class.arguments.as_ref() else { + let Some(Arguments { args: bases, .. }) = class.arguments.as_deref() else { return; }; diff --git a/crates/ruff/src/rules/flake8_slots/rules/no_slots_in_tuple_subclass.rs b/crates/ruff/src/rules/flake8_slots/rules/no_slots_in_tuple_subclass.rs index 0b4d478b85..c0f7a0d897 100644 --- a/crates/ruff/src/rules/flake8_slots/rules/no_slots_in_tuple_subclass.rs +++ b/crates/ruff/src/rules/flake8_slots/rules/no_slots_in_tuple_subclass.rs @@ -51,7 +51,7 @@ impl Violation for NoSlotsInTupleSubclass { /// SLOT001 pub(crate) fn no_slots_in_tuple_subclass(checker: &mut Checker, stmt: &Stmt, class: &StmtClassDef) { - let Some(Arguments { args: bases, .. }) = class.arguments.as_ref() else { + let Some(Arguments { args: bases, .. }) = class.arguments.as_deref() else { return; }; diff --git a/crates/ruff/src/rules/flake8_type_checking/helpers.rs b/crates/ruff/src/rules/flake8_type_checking/helpers.rs index 51b38d2ea8..fa25bd0f13 100644 --- a/crates/ruff/src/rules/flake8_type_checking/helpers.rs +++ b/crates/ruff/src/rules/flake8_type_checking/helpers.rs @@ -1,6 +1,3 @@ -use ruff_python_ast as ast; -use ruff_python_ast::Arguments; - use ruff_python_ast::call_path::from_qualified_name; use ruff_python_ast::helpers::map_callable; use ruff_python_semantic::{Binding, BindingKind, ScopeKind, SemanticModel}; @@ -38,38 +35,31 @@ pub(crate) fn runtime_evaluated( } fn runtime_evaluated_base_class(base_classes: &[String], semantic: &SemanticModel) -> bool { - if let ScopeKind::Class(ast::StmtClassDef { - arguments: Some(Arguments { args: bases, .. }), - .. - }) = &semantic.scope().kind - { - for base in bases { - if let Some(call_path) = semantic.resolve_call_path(base) { - if base_classes - .iter() - .any(|base_class| from_qualified_name(base_class) == call_path) - { - return true; - } - } - } - } - false + let ScopeKind::Class(class_def) = &semantic.scope().kind else { + return false; + }; + + class_def.bases().any(|base| { + semantic.resolve_call_path(base).is_some_and(|call_path| { + base_classes + .iter() + .any(|base_class| from_qualified_name(base_class) == call_path) + }) + }) } fn runtime_evaluated_decorators(decorators: &[String], semantic: &SemanticModel) -> bool { - if let ScopeKind::Class(ast::StmtClassDef { decorator_list, .. }) = &semantic.scope().kind { - for decorator in decorator_list { - if let Some(call_path) = semantic.resolve_call_path(map_callable(&decorator.expression)) - { - if decorators + let ScopeKind::Class(class_def) = &semantic.scope().kind else { + return false; + }; + + class_def.decorator_list.iter().any(|decorator| { + semantic + .resolve_call_path(map_callable(&decorator.expression)) + .is_some_and(|call_path| { + decorators .iter() - .any(|decorator| from_qualified_name(decorator) == call_path) - { - return true; - } - } - } - } - false + .any(|base_class| from_qualified_name(base_class) == call_path) + }) + }) } diff --git a/crates/ruff/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs b/crates/ruff/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs index 6ecc2db6c2..a245a15e4f 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/convert_named_tuple_functional_to_class.rs @@ -166,11 +166,11 @@ fn create_properties_from_keywords(keywords: &[Keyword]) -> Result> { fn create_class_def_stmt(typename: &str, body: Vec, base_class: &Expr) -> Stmt { ast::StmtClassDef { name: Identifier::new(typename.to_string(), TextRange::default()), - arguments: Some(Arguments { + arguments: Some(Box::new(Arguments { args: vec![base_class.clone()], keywords: vec![], range: TextRange::default(), - }), + })), body, type_params: None, decorator_list: vec![], diff --git a/crates/ruff/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs b/crates/ruff/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs index b89930e845..4a23cbf2a0 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/convert_typed_dict_functional_to_class.rs @@ -119,14 +119,14 @@ fn create_class_def_stmt( ) -> Stmt { ast::StmtClassDef { name: Identifier::new(class_name.to_string(), TextRange::default()), - arguments: Some(Arguments { + arguments: Some(Box::new(Arguments { args: vec![base_class.clone()], keywords: match total_keyword { Some(keyword) => vec![keyword.clone()], None => vec![], }, range: TextRange::default(), - }), + })), body, type_params: None, decorator_list: vec![], diff --git a/crates/ruff/src/rules/pyupgrade/rules/unnecessary_class_parentheses.rs b/crates/ruff/src/rules/pyupgrade/rules/unnecessary_class_parentheses.rs index 758a2e6d54..b45b3a5e3f 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/unnecessary_class_parentheses.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/unnecessary_class_parentheses.rs @@ -40,7 +40,7 @@ impl AlwaysAutofixableViolation for UnnecessaryClassParentheses { /// UP039 pub(crate) fn unnecessary_class_parentheses(checker: &mut Checker, class_def: &ast::StmtClassDef) { - let Some(arguments) = class_def.arguments.as_ref() else { + let Some(arguments) = class_def.arguments.as_deref() else { return; }; diff --git a/crates/ruff/src/rules/pyupgrade/rules/useless_object_inheritance.rs b/crates/ruff/src/rules/pyupgrade/rules/useless_object_inheritance.rs index 7298309a06..127ab261c8 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/useless_object_inheritance.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/useless_object_inheritance.rs @@ -46,7 +46,7 @@ impl AlwaysAutofixableViolation for UselessObjectInheritance { /// UP004 pub(crate) fn useless_object_inheritance(checker: &mut Checker, class_def: &ast::StmtClassDef) { - let Some(arguments) = class_def.arguments.as_ref() else { + let Some(arguments) = class_def.arguments.as_deref() else { return; }; diff --git a/crates/ruff/src/rules/ruff/rules/helpers.rs b/crates/ruff/src/rules/ruff/rules/helpers.rs index 0271a730c8..8ccb070376 100644 --- a/crates/ruff/src/rules/ruff/rules/helpers.rs +++ b/crates/ruff/src/rules/ruff/rules/helpers.rs @@ -51,7 +51,7 @@ pub(super) fn is_dataclass(class_def: &ast::StmtClassDef, semantic: &SemanticMod /// Returns `true` if the given class is a Pydantic `BaseModel` or `BaseSettings` subclass. pub(super) fn is_pydantic_model(class_def: &ast::StmtClassDef, semantic: &SemanticModel) -> bool { - let Some(Arguments { args: bases, .. }) = class_def.arguments.as_ref() else { + let Some(Arguments { args: bases, .. }) = class_def.arguments.as_deref() else { return false; }; diff --git a/crates/ruff_python_ast/src/comparable.rs b/crates/ruff_python_ast/src/comparable.rs index f2e0ec6f24..42d9fee50d 100644 --- a/crates/ruff_python_ast/src/comparable.rs +++ b/crates/ruff_python_ast/src/comparable.rs @@ -965,31 +965,31 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> { #[derive(Debug, PartialEq, Eq, Hash)] pub struct StmtFunctionDef<'a> { - name: &'a str, - parameters: ComparableParameters<'a>, - body: Vec>, decorator_list: Vec>, + name: &'a str, type_params: Option>, + parameters: ComparableParameters<'a>, returns: Option>, + body: Vec>, } #[derive(Debug, PartialEq, Eq, Hash)] pub struct StmtAsyncFunctionDef<'a> { - name: &'a str, - parameters: ComparableParameters<'a>, - body: Vec>, decorator_list: Vec>, + name: &'a str, type_params: Option>, + parameters: ComparableParameters<'a>, returns: Option>, + body: Vec>, } #[derive(Debug, PartialEq, Eq, Hash)] pub struct StmtClassDef<'a> { + decorator_list: Vec>, name: &'a str, + type_params: Option>, arguments: Option>, body: Vec>, - decorator_list: Vec>, - type_params: Option>, } #[derive(Debug, PartialEq, Eq, Hash)] @@ -1022,6 +1022,12 @@ impl<'a> From<&'a ast::TypeParams> for ComparableTypeParams<'a> { } } +impl<'a> From<&'a Box> for ComparableTypeParams<'a> { + fn from(type_params: &'a Box) -> Self { + type_params.as_ref().into() + } +} + #[derive(Debug, PartialEq, Eq, Hash)] pub enum ComparableTypeParam<'a> { TypeVar(TypeParamTypeVar<'a>), diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 95b0d376c0..bc2857529e 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -409,7 +409,7 @@ where .. }) => { arguments - .as_ref() + .as_deref() .is_some_and(|Arguments { args, keywords, .. }| { args.iter().any(|expr| any_over_expr(expr, func)) || keywords diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index 9225728c2b..9969086595 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -160,8 +160,8 @@ pub struct StmtClassDef { pub range: TextRange, pub decorator_list: Vec, pub name: Identifier, - pub type_params: Option, - pub arguments: Option, + pub type_params: Option>, + pub arguments: Option>, pub body: Vec, } @@ -3032,9 +3032,10 @@ mod size_assertions { use super::*; use static_assertions::assert_eq_size; - assert_eq_size!(Stmt, [u8; 184]); + assert_eq_size!(Stmt, [u8; 144]); assert_eq_size!(StmtFunctionDef, [u8; 136]); - assert_eq_size!(StmtClassDef, [u8; 176]); + assert_eq_size!(StmtAsyncFunctionDef, [u8; 136]); + assert_eq_size!(StmtClassDef, [u8; 104]); assert_eq_size!(StmtTry, [u8; 104]); assert_eq_size!(Expr, [u8; 80]); assert_eq_size!(Constant, [u8; 32]); diff --git a/crates/ruff_python_formatter/src/statement/stmt_class_def.rs b/crates/ruff_python_formatter/src/statement/stmt_class_def.rs index 7596453172..3333fa91e7 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_class_def.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_class_def.rs @@ -58,7 +58,7 @@ impl FormatNodeRule for FormatStmtClassDef { write!(f, [text("class"), space(), name.format()])?; - if let Some(arguments) = arguments { + if let Some(arguments) = arguments.as_deref() { // Drop empty parentheses, e.g., in: // ```python // class A(): diff --git a/crates/ruff_python_parser/src/python.lalrpop b/crates/ruff_python_parser/src/python.lalrpop index 6e6869b1c6..fb75124ea0 100644 --- a/crates/ruff_python_parser/src/python.lalrpop +++ b/crates/ruff_python_parser/src/python.lalrpop @@ -1199,10 +1199,10 @@ ClassDef: ast::Stmt = { ast::Stmt::ClassDef( ast::StmtClassDef { name, - arguments, + arguments: arguments.map(Box::new), body, decorator_list, - type_params, + type_params: type_params.map(Box::new), range: (location..end_location).into() }, ) diff --git a/crates/ruff_python_parser/src/python.rs b/crates/ruff_python_parser/src/python.rs index f01da55f4f..8577cb525b 100644 --- a/crates/ruff_python_parser/src/python.rs +++ b/crates/ruff_python_parser/src/python.rs @@ -1,5 +1,5 @@ // auto-generated: "lalrpop 0.20.0" -// sha3: aadf067e37a9f39d450f1403b759a9659c60e697758ddd2b8c2b5fa2d0d73672 +// sha3: f99d8cb29227bfbe1fa07719f655304a9a93fd4715726687ef40c091adbdbad5 use num_bigint::BigInt; use ruff_text_size::TextSize; use ruff_python_ast::{self as ast, Ranged, MagicKind}; @@ -33583,10 +33583,10 @@ fn __action170< ast::Stmt::ClassDef( ast::StmtClassDef { name, - arguments, + arguments: arguments.map(Box::new), body, decorator_list, - type_params, + type_params: type_params.map(Box::new), range: (location..end_location).into() }, )