[ty] AST garbage collection (#18482)

## Summary

Garbage collect ASTs once we are done checking a given file. Queries
with a cross-file dependency on the AST will reparse the file on demand.
This reduces ty's peak memory usage by ~20-30%.

The primary change of this PR is adding a `node_index` field to every
AST node, that is assigned by the parser. `ParsedModule` can use this to
create a flat index of AST nodes any time the file is parsed (or
reparsed). This allows `AstNodeRef` to simply index into the current
instance of the `ParsedModule`, instead of storing a pointer directly.

The indices are somewhat hackily (using an atomic integer) assigned by
the `parsed_module` query instead of by the parser directly. Assigning
the indices in source-order in the (recursive) parser turns out to be
difficult, and collecting the nodes during semantic indexing is
impossible as `SemanticIndex` does not hold onto a specific
`ParsedModuleRef`, which the pointers in the flat AST are tied to. This
means that we have to do an extra AST traversal to assign and collect
the nodes into a flat index, but the small performance impact (~3% on
cold runs) seems worth it for the memory savings.

Part of https://github.com/astral-sh/ty/issues/214.
This commit is contained in:
Ibraheem Ahmed 2025-06-13 08:40:11 -04:00 committed by GitHub
parent 76d9009a6e
commit c9dff5c7d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
824 changed files with 25243 additions and 804 deletions

View file

@ -184,7 +184,7 @@ mod tests {
use insta::assert_debug_snapshot;
use ruff_formatter::SourceCode;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::{AnyNodeRef, AtomicNodeIndex};
use ruff_python_ast::{StmtBreak, StmtContinue};
use ruff_python_trivia::{CommentLinePosition, CommentRanges};
use ruff_text_size::{TextRange, TextSize};
@ -196,10 +196,12 @@ mod tests {
fn debug() {
let continue_statement = StmtContinue {
range: TextRange::new(TextSize::new(18), TextSize::new(26)),
node_index: AtomicNodeIndex::dummy(),
};
let break_statement = StmtBreak {
range: TextRange::new(TextSize::new(55), TextSize::new(60)),
node_index: AtomicNodeIndex::dummy(),
};
let source = r"# leading comment

View file

@ -53,6 +53,7 @@ impl<'a> From<AnyNodeRef<'a>> for NodeRefEqualityKey<'a> {
mod tests {
use crate::comments::node_key::NodeRefEqualityKey;
use ruff_python_ast::AnyNodeRef;
use ruff_python_ast::AtomicNodeIndex;
use ruff_python_ast::StmtContinue;
use ruff_text_size::TextRange;
use std::collections::hash_map::DefaultHasher;
@ -68,6 +69,7 @@ mod tests {
fn equality() {
let continue_statement = StmtContinue {
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
};
let ref_a = NodeRefEqualityKey::from_ref(AnyNodeRef::from(&continue_statement));
@ -81,6 +83,7 @@ mod tests {
fn inequality() {
let continue_statement = StmtContinue {
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
};
let boxed = Box::new(continue_statement.clone());

View file

@ -1067,6 +1067,7 @@ fn handle_slice_comments<'a>(
) -> CommentPlacement<'a> {
let ast::ExprSlice {
range: _,
node_index: _,
lower,
upper,
step,
@ -1450,6 +1451,7 @@ fn handle_expr_if_comment<'a>(
) -> CommentPlacement<'a> {
let ast::ExprIf {
range: _,
node_index: _,
test,
body,
orelse,

View file

@ -30,6 +30,7 @@ impl FormatNodeRule<ExprAttribute> for FormatExprAttribute {
let ExprAttribute {
value,
range: _,
node_index: _,
attr,
ctx: _,
} = item;
@ -188,7 +189,12 @@ impl NeedsParentheses for ExprAttribute {
// Non Hex, octal or binary number literals need parentheses to disambiguate the attribute `.` from
// a decimal point. Floating point numbers don't strictly need parentheses but it reads better (rather than 0.0.test()).
fn is_base_ten_number_literal(expr: &Expr, source: &str) -> bool {
if let Some(ExprNumberLiteral { value, range }) = expr.as_number_literal_expr() {
if let Some(ExprNumberLiteral {
value,
range,
node_index: _,
}) = expr.as_number_literal_expr()
{
match value {
Number::Float(_) => true,
Number::Int(_) => {

View file

@ -13,7 +13,11 @@ pub struct FormatExprAwait;
impl FormatNodeRule<ExprAwait> for FormatExprAwait {
fn fmt_fields(&self, item: &ExprAwait, f: &mut PyFormatter) -> FormatResult<()> {
let ExprAwait { range: _, value } = item;
let ExprAwait {
range: _,
node_index: _,
value,
} = item;
write!(
f,

View file

@ -27,6 +27,7 @@ impl FormatNodeRule<ExprCall> for FormatExprCall {
fn fmt_fields(&self, item: &ExprCall, f: &mut PyFormatter) -> FormatResult<()> {
let ExprCall {
range: _,
node_index: _,
func,
arguments,
} = item;

View file

@ -13,7 +13,11 @@ pub struct FormatExprDict;
impl FormatNodeRule<ExprDict> for FormatExprDict {
fn fmt_fields(&self, item: &ExprDict, f: &mut PyFormatter) -> FormatResult<()> {
let ExprDict { range: _, items } = item;
let ExprDict {
range: _,
node_index: _,
items,
} = item;
let comments = f.context().comments().clone();
let dangling = comments.dangling(item);

View file

@ -14,6 +14,7 @@ impl FormatNodeRule<ExprDictComp> for FormatExprDictComp {
fn fmt_fields(&self, item: &ExprDictComp, f: &mut PyFormatter) -> FormatResult<()> {
let ExprDictComp {
range: _,
node_index: _,
key,
value,
generators,

View file

@ -37,6 +37,7 @@ impl FormatNodeRule<ExprGenerator> for FormatExprGenerator {
fn fmt_fields(&self, item: &ExprGenerator, f: &mut PyFormatter) -> FormatResult<()> {
let ExprGenerator {
range: _,
node_index: _,
elt,
generators,
parenthesized: is_parenthesized,

View file

@ -46,6 +46,7 @@ impl FormatNodeRule<ExprIf> for FormatExprIf {
fn fmt_fields(&self, item: &ExprIf, f: &mut PyFormatter) -> FormatResult<()> {
let ExprIf {
range: _,
node_index: _,
test,
body,
orelse,

View file

@ -15,6 +15,7 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
fn fmt_fields(&self, item: &ExprLambda, f: &mut PyFormatter) -> FormatResult<()> {
let ExprLambda {
range: _,
node_index: _,
parameters,
body,
} = item;

View file

@ -15,6 +15,7 @@ impl FormatNodeRule<ExprList> for FormatExprList {
fn fmt_fields(&self, item: &ExprList, f: &mut PyFormatter) -> FormatResult<()> {
let ExprList {
range: _,
node_index: _,
elts,
ctx: _,
} = item;

View file

@ -12,6 +12,7 @@ impl FormatNodeRule<ExprListComp> for FormatExprListComp {
fn fmt_fields(&self, item: &ExprListComp, f: &mut PyFormatter) -> FormatResult<()> {
let ExprListComp {
range: _,
node_index: _,
elt,
generators,
} = item;

View file

@ -14,6 +14,7 @@ impl FormatNodeRule<ExprName> for FormatExprName {
id: _,
range,
ctx: _,
node_index: _,
} = item;
write!(f, [source_text_slice(*range)])
}

View file

@ -17,6 +17,7 @@ impl FormatNodeRule<ExprNamed> for FormatExprNamed {
target,
value,
range: _,
node_index: _,
} = item;
// This context, a dangling comment is a comment between the `:=` and the value.

View file

@ -10,7 +10,11 @@ pub struct FormatExprSet;
impl FormatNodeRule<ExprSet> for FormatExprSet {
fn fmt_fields(&self, item: &ExprSet, f: &mut PyFormatter) -> FormatResult<()> {
let ExprSet { range: _, elts } = item;
let ExprSet {
range: _,
node_index: _,
elts,
} = item;
// That would be a dict expression
assert!(!elts.is_empty());
// Avoid second mutable borrow of f

View file

@ -12,6 +12,7 @@ impl FormatNodeRule<ExprSetComp> for FormatExprSetComp {
fn fmt_fields(&self, item: &ExprSetComp, f: &mut PyFormatter) -> FormatResult<()> {
let ExprSetComp {
range: _,
node_index: _,
elt,
generators,
} = item;

View file

@ -21,6 +21,7 @@ impl FormatNodeRule<ExprSlice> for FormatExprSlice {
upper,
step,
range,
node_index: _,
} = item;
let (first_colon, second_colon) = find_colons(
@ -232,6 +233,7 @@ pub(crate) fn assign_comment_in_slice(
upper,
step: _,
range,
node_index: _,
} = expr_slice;
let (first_colon, second_colon) =

View file

@ -14,6 +14,7 @@ impl FormatNodeRule<ExprStarred> for FormatExprStarred {
fn fmt_fields(&self, item: &ExprStarred, f: &mut PyFormatter) -> FormatResult<()> {
let ExprStarred {
range: _,
node_index: _,
value,
ctx: _,
} = item;

View file

@ -27,6 +27,7 @@ impl FormatNodeRule<ExprSubscript> for FormatExprSubscript {
fn fmt_fields(&self, item: &ExprSubscript, f: &mut PyFormatter) -> FormatResult<()> {
let ExprSubscript {
range: _,
node_index: _,
value,
slice,
ctx: _,

View file

@ -116,6 +116,7 @@ impl FormatNodeRule<ExprTuple> for FormatExprTuple {
elts,
ctx: _,
range: _,
node_index: _,
parenthesized: is_parenthesized,
} = item;

View file

@ -15,6 +15,7 @@ impl FormatNodeRule<ExprUnaryOp> for FormatExprUnaryOp {
fn fmt_fields(&self, item: &ExprUnaryOp, f: &mut PyFormatter) -> FormatResult<()> {
let ExprUnaryOp {
range: _,
node_index: _,
op,
operand,
} = item;

View file

@ -685,6 +685,7 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
#[expect(clippy::cast_possible_truncation)]
Expr::BoolOp(ast::ExprBoolOp {
range: _,
node_index: _,
op: _,
values,
}) => self.update_max_precedence_with_count(
@ -696,6 +697,7 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
left: _,
right: _,
range: _,
node_index: _,
}) => self.update_max_precedence(OperatorPrecedence::from(*op)),
Expr::If(_) => {
@ -708,6 +710,7 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
#[expect(clippy::cast_possible_truncation)]
Expr::Compare(ast::ExprCompare {
range: _,
node_index: _,
left: _,
ops,
comparators: _,
@ -719,6 +722,7 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
}
Expr::Call(ast::ExprCall {
range: _,
node_index: _,
func,
arguments: _,
}) => {
@ -740,6 +744,7 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
// `[a, b].test.test[300].dot`
Expr::Attribute(ast::ExprAttribute {
range: _,
node_index: _,
value,
attr: _,
ctx: _,
@ -760,6 +765,7 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
// Visit the sub-expressions because the sub expressions may be the end of the entire expression.
Expr::UnaryOp(ast::ExprUnaryOp {
range: _,
node_index: _,
op,
operand: _,
}) => {

View file

@ -7,7 +7,11 @@ pub struct FormatModExpression;
impl FormatNodeRule<ModExpression> for FormatModExpression {
fn fmt_fields(&self, item: &ModExpression, f: &mut PyFormatter) -> FormatResult<()> {
let ModExpression { body, range: _ } = item;
let ModExpression {
body,
range: _,
node_index: _,
} = item;
body.format().fmt(f)
}
}

View file

@ -11,7 +11,11 @@ pub struct FormatModModule;
impl FormatNodeRule<ModModule> for FormatModModule {
fn fmt_fields(&self, item: &ModModule, f: &mut PyFormatter) -> FormatResult<()> {
let ModModule { range, body } = item;
let ModModule {
range,
body,
node_index: _,
} = item;
if body.is_empty() {
// Only preserve an empty line if the source contains an empty line too.

View file

@ -11,6 +11,7 @@ impl FormatNodeRule<Alias> for FormatAlias {
fn fmt_fields(&self, item: &Alias, f: &mut PyFormatter) -> FormatResult<()> {
let Alias {
range: _,
node_index: _,
name,
asname,
} = item;

View file

@ -19,6 +19,7 @@ impl FormatNodeRule<Arguments> for FormatArguments {
range,
args,
keywords,
node_index: _,
} = item;
// We have a case with `f()` without any argument, which is a special case because we can
// have a comment with no node attachment inside:

View file

@ -52,6 +52,7 @@ impl FormatNodeRule<Comprehension> for FormatComprehension {
let Comprehension {
range: _,
node_index: _,
target,
iter,
ifs,

View file

@ -14,6 +14,7 @@ impl FormatNodeRule<Decorator> for FormatDecorator {
let Decorator {
expression,
range: _,
node_index: _,
} = item;
write!(

View file

@ -42,6 +42,7 @@ impl FormatNodeRule<ExceptHandlerExceptHandler> for FormatExceptHandlerExceptHan
let except_handler_kind = self.except_handler_kind;
let ExceptHandlerExceptHandler {
range: _,
node_index: _,
type_,
name,
body,

View file

@ -10,6 +10,7 @@ impl FormatNodeRule<Keyword> for FormatKeyword {
fn fmt_fields(&self, item: &Keyword, f: &mut PyFormatter) -> FormatResult<()> {
let Keyword {
range: _,
node_index: _,
arg,
value,
} = item;

View file

@ -26,6 +26,7 @@ impl FormatNodeRule<MatchCase> for FormatMatchCase {
fn fmt_fields(&self, item: &MatchCase, f: &mut PyFormatter) -> FormatResult<()> {
let MatchCase {
range: _,
node_index: _,
pattern,
guard,
body,

View file

@ -9,6 +9,7 @@ impl FormatNodeRule<Parameter> for FormatParameter {
fn fmt_fields(&self, item: &Parameter, f: &mut PyFormatter) -> FormatResult<()> {
let Parameter {
range: _,
node_index: _,
name,
annotation,
} = item;

View file

@ -12,6 +12,7 @@ impl FormatNodeRule<ParameterWithDefault> for FormatParameterWithDefault {
fn fmt_fields(&self, item: &ParameterWithDefault, f: &mut PyFormatter) -> FormatResult<()> {
let ParameterWithDefault {
range: _,
node_index: _,
parameter,
default,
} = item;

View file

@ -49,6 +49,7 @@ impl FormatNodeRule<Parameters> for FormatParameters {
fn fmt_fields(&self, item: &Parameters, f: &mut PyFormatter) -> FormatResult<()> {
let Parameters {
range: _,
node_index: _,
posonlyargs,
args,
vararg,

View file

@ -94,6 +94,7 @@ impl FormatNodeRule<WithItem> for FormatWithItem {
fn fmt_fields(&self, item: &WithItem, f: &mut PyFormatter) -> FormatResult<()> {
let WithItem {
range: _,
node_index: _,
context_expr,
optional_vars,
} = item;

View file

@ -9,6 +9,7 @@ impl FormatNodeRule<PatternKeyword> for FormatPatternKeyword {
fn fmt_fields(&self, item: &PatternKeyword, f: &mut PyFormatter) -> FormatResult<()> {
let PatternKeyword {
range: _,
node_index: _,
attr,
pattern,
} = item;

View file

@ -13,6 +13,7 @@ impl FormatNodeRule<PatternMatchAs> for FormatPatternMatchAs {
fn fmt_fields(&self, item: &PatternMatchAs, f: &mut PyFormatter) -> FormatResult<()> {
let PatternMatchAs {
range: _,
node_index: _,
pattern,
name,
} = item;

View file

@ -13,6 +13,7 @@ impl FormatNodeRule<PatternMatchClass> for FormatPatternMatchClass {
fn fmt_fields(&self, item: &PatternMatchClass, f: &mut PyFormatter) -> FormatResult<()> {
let PatternMatchClass {
range: _,
node_index: _,
cls,
arguments,
} = item;

View file

@ -21,6 +21,7 @@ impl FormatNodeRule<PatternMatchMapping> for FormatPatternMatchMapping {
patterns,
rest,
range: _,
node_index: _,
} = item;
debug_assert_eq!(keys.len(), patterns.len());
@ -163,6 +164,7 @@ fn find_double_star(pattern: &PatternMatchMapping, source: &str) -> Option<(Text
patterns,
rest,
range: _,
node_index: _,
} = pattern;
// If there's no `rest` element, there's no `**`.

View file

@ -14,7 +14,11 @@ pub struct FormatPatternMatchOr;
impl FormatNodeRule<PatternMatchOr> for FormatPatternMatchOr {
fn fmt_fields(&self, item: &PatternMatchOr, f: &mut PyFormatter) -> FormatResult<()> {
let PatternMatchOr { range: _, patterns } = item;
let PatternMatchOr {
range: _,
node_index: _,
patterns,
} = item;
let inner = format_with(|f: &mut PyFormatter| {
let mut patterns = patterns.iter();
let comments = f.context().comments().clone();

View file

@ -14,7 +14,11 @@ pub struct FormatPatternMatchSequence;
impl FormatNodeRule<PatternMatchSequence> for FormatPatternMatchSequence {
fn fmt_fields(&self, item: &PatternMatchSequence, f: &mut PyFormatter) -> FormatResult<()> {
let PatternMatchSequence { patterns, range } = item;
let PatternMatchSequence {
patterns,
range,
node_index: _,
} = item;
let comments = f.context().comments().clone();
let dangling = comments.dangling(item);

View file

@ -9,7 +9,11 @@ pub struct FormatPatternMatchValue;
impl FormatNodeRule<PatternMatchValue> for FormatPatternMatchValue {
fn fmt_fields(&self, item: &PatternMatchValue, f: &mut PyFormatter) -> FormatResult<()> {
let PatternMatchValue { value, range: _ } = item;
let PatternMatchValue {
value,
range: _,
node_index: _,
} = item;
value.format().with_options(Parentheses::Never).fmt(f)
}
}

View file

@ -369,6 +369,7 @@ impl SourceOrderVisitor<'_> for NarrowRange<'_> {
subject: _,
cases,
range: _,
node_index: _,
}) => {
if let Some(saved_state) = self.enter_level(cases.first().map(AnyNodeRef::from)) {
for match_case in cases {
@ -387,6 +388,7 @@ impl SourceOrderVisitor<'_> for NarrowRange<'_> {
finalbody,
is_star: _,
range: _,
node_index: _,
}) => {
self.visit_body(body);
if let Some(except_handler_saved) =

View file

@ -87,6 +87,7 @@ impl ClauseHeader<'_> {
type_params,
arguments,
range: _,
node_index: _,
decorator_list: _,
name: _,
body: _,
@ -103,6 +104,7 @@ impl ClauseHeader<'_> {
type_params,
parameters,
range: _,
node_index: _,
is_async: _,
decorator_list: _,
name: _,
@ -121,6 +123,7 @@ impl ClauseHeader<'_> {
ClauseHeader::If(StmtIf {
test,
range: _,
node_index: _,
body: _,
elif_else_clauses: _,
}) => {
@ -129,6 +132,7 @@ impl ClauseHeader<'_> {
ClauseHeader::ElifElse(ElifElseClause {
test,
range: _,
node_index: _,
body: _,
}) => {
if let Some(test) = test.as_ref() {
@ -139,6 +143,7 @@ impl ClauseHeader<'_> {
ClauseHeader::ExceptHandler(ExceptHandlerExceptHandler {
type_: type_expr,
range: _,
node_index: _,
name: _,
body: _,
}) => {
@ -149,6 +154,7 @@ impl ClauseHeader<'_> {
ClauseHeader::Match(StmtMatch {
subject,
range: _,
node_index: _,
cases: _,
}) => {
visit(subject.as_ref(), visitor);
@ -157,6 +163,7 @@ impl ClauseHeader<'_> {
guard,
pattern,
range: _,
node_index: _,
body: _,
}) => {
visit(pattern, visitor);
@ -169,6 +176,7 @@ impl ClauseHeader<'_> {
target,
iter,
range: _,
node_index: _,
is_async: _,
body: _,
orelse: _,
@ -179,6 +187,7 @@ impl ClauseHeader<'_> {
ClauseHeader::While(StmtWhile {
test,
range: _,
node_index: _,
body: _,
orelse: _,
}) => {
@ -187,6 +196,7 @@ impl ClauseHeader<'_> {
ClauseHeader::With(StmtWith {
items,
range: _,
node_index: _,
is_async: _,
body: _,
}) => {

View file

@ -17,6 +17,7 @@ impl FormatNodeRule<StmtAnnAssign> for FormatStmtAnnAssign {
fn fmt_fields(&self, item: &StmtAnnAssign, f: &mut PyFormatter) -> FormatResult<()> {
let StmtAnnAssign {
range: _,
node_index: _,
target,
annotation,
value,

View file

@ -14,6 +14,7 @@ impl FormatNodeRule<StmtAssert> for FormatStmtAssert {
fn fmt_fields(&self, item: &StmtAssert, f: &mut PyFormatter) -> FormatResult<()> {
let StmtAssert {
range: _,
node_index: _,
test,
msg,
} = item;

View file

@ -33,6 +33,7 @@ impl FormatNodeRule<StmtAssign> for FormatStmtAssign {
fn fmt_fields(&self, item: &StmtAssign, f: &mut PyFormatter) -> FormatResult<()> {
let StmtAssign {
range: _,
node_index: _,
targets,
value,
} = item;

View file

@ -21,6 +21,7 @@ impl FormatNodeRule<StmtAugAssign> for FormatStmtAugAssign {
op,
value,
range: _,
node_index: _,
} = item;
if has_target_own_parentheses(target, f.context())

View file

@ -18,6 +18,7 @@ impl FormatNodeRule<StmtClassDef> for FormatStmtClassDef {
fn fmt_fields(&self, item: &StmtClassDef, f: &mut PyFormatter) -> FormatResult<()> {
let StmtClassDef {
range: _,
node_index: _,
name,
arguments,
body,

View file

@ -13,7 +13,11 @@ pub struct FormatStmtDelete;
impl FormatNodeRule<StmtDelete> for FormatStmtDelete {
fn fmt_fields(&self, item: &StmtDelete, f: &mut PyFormatter) -> FormatResult<()> {
let StmtDelete { range: _, targets } = item;
let StmtDelete {
range: _,
node_index: _,
targets,
} = item;
write!(f, [token("del"), space()])?;

View file

@ -36,6 +36,7 @@ impl FormatNodeRule<StmtFor> for FormatStmtFor {
body,
orelse,
range: _,
node_index: _,
} = item;
let comments = f.context().comments().clone();

View file

@ -93,6 +93,7 @@ impl FormatNodeRule<StmtFunctionDef> for FormatStmtFunctionDef {
fn format_function_header(f: &mut PyFormatter, item: &StmtFunctionDef) -> FormatResult<()> {
let StmtFunctionDef {
range: _,
node_index: _,
is_async,
decorator_list: _,
name,

View file

@ -15,6 +15,7 @@ impl FormatNodeRule<StmtIf> for FormatStmtIf {
fn fmt_fields(&self, item: &StmtIf, f: &mut PyFormatter) -> FormatResult<()> {
let StmtIf {
range: _,
node_index: _,
test,
body,
elif_else_clauses,
@ -68,6 +69,7 @@ pub(crate) fn format_elif_else_clause(
) -> FormatResult<()> {
let ElifElseClause {
range: _,
node_index: _,
test,
body,
} = item;

View file

@ -9,7 +9,11 @@ pub struct FormatStmtImport;
impl FormatNodeRule<StmtImport> for FormatStmtImport {
fn fmt_fields(&self, item: &StmtImport, f: &mut PyFormatter) -> FormatResult<()> {
let StmtImport { names, range: _ } = item;
let StmtImport {
names,
range: _,
node_index: _,
} = item;
let names = format_with(|f| {
f.join_with(&format_args![token(","), space()])
.entries(names.iter().formatted())

View file

@ -19,6 +19,7 @@ impl FormatNodeRule<StmtImportFrom> for FormatStmtImportFrom {
names,
level,
range: _,
node_index: _,
} = item;
write!(

View file

@ -15,6 +15,7 @@ impl FormatNodeRule<StmtMatch> for FormatStmtMatch {
fn fmt_fields(&self, item: &StmtMatch, f: &mut PyFormatter) -> FormatResult<()> {
let StmtMatch {
range: _,
node_index: _,
subject,
cases,
} = item;

View file

@ -13,6 +13,7 @@ impl FormatNodeRule<StmtRaise> for FormatStmtRaise {
fn fmt_fields(&self, item: &StmtRaise, f: &mut PyFormatter) -> FormatResult<()> {
let StmtRaise {
range: _,
node_index: _,
exc,
cause,
} = item;

View file

@ -11,7 +11,11 @@ pub struct FormatStmtReturn;
impl FormatNodeRule<StmtReturn> for FormatStmtReturn {
fn fmt_fields(&self, item: &StmtReturn, f: &mut PyFormatter) -> FormatResult<()> {
let StmtReturn { range: _, value } = item;
let StmtReturn {
range: _,
node_index: _,
value,
} = item;
token("return").fmt(f)?;

View file

@ -66,6 +66,7 @@ impl FormatNodeRule<StmtTry> for FormatStmtTry {
finalbody,
is_star,
range: _,
node_index: _,
} = item;
let comments_info = f.context().comments().clone();

View file

@ -17,6 +17,7 @@ impl FormatNodeRule<StmtTypeAlias> for FormatStmtTypeAlias {
type_params,
value,
range: _,
node_index: _,
} = item;
write!(f, [token("type"), space(), name.as_ref().format()])?;

View file

@ -15,6 +15,7 @@ impl FormatNodeRule<StmtWhile> for FormatStmtWhile {
fn fmt_fields(&self, item: &StmtWhile, f: &mut PyFormatter) -> FormatResult<()> {
let StmtWhile {
range: _,
node_index: _,
test,
body,
orelse,

View file

@ -10,6 +10,7 @@ impl FormatNodeRule<TypeParamParamSpec> for FormatTypeParamParamSpec {
fn fmt_fields(&self, item: &TypeParamParamSpec, f: &mut PyFormatter) -> FormatResult<()> {
let TypeParamParamSpec {
range: _,
node_index: _,
name,
default,
} = item;

View file

@ -10,6 +10,7 @@ impl FormatNodeRule<TypeParamTypeVar> for FormatTypeParamTypeVar {
fn fmt_fields(&self, item: &TypeParamTypeVar, f: &mut PyFormatter) -> FormatResult<()> {
let TypeParamTypeVar {
range: _,
node_index: _,
name,
bound,
default,

View file

@ -10,6 +10,7 @@ impl FormatNodeRule<TypeParamTypeVarTuple> for FormatTypeParamTypeVarTuple {
fn fmt_fields(&self, item: &TypeParamTypeVarTuple, f: &mut PyFormatter) -> FormatResult<()> {
let TypeParamTypeVarTuple {
range: _,
node_index: _,
name,
default,
} = item;