[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

@ -300,9 +300,11 @@ def write_owned_enum(out: list[str], ast: Ast) -> None:
Also creates:
- `impl Ranged for TypeParam`
- `impl HasNodeIndex for TypeParam`
- `TypeParam::visit_source_order`
- `impl From<TypeParamTypeVar> for TypeParam`
- `impl Ranged for TypeParamTypeVar`
- `impl HasNodeIndex for TypeParamTypeVar`
- `fn TypeParam::is_type_var() -> bool`
If the `add_suffix_to_is_methods` group option is true, then the
@ -341,6 +343,19 @@ def write_owned_enum(out: list[str], ast: Ast) -> None:
}
""")
out.append(f"""
impl crate::HasNodeIndex for {group.owned_enum_ty} {{
fn node_index(&self) -> &crate::AtomicNodeIndex {{
match self {{
""")
for node in group.nodes:
out.append(f"Self::{node.variant}(node) => node.node_index(),")
out.append("""
}
}
}
""")
out.append(
"#[allow(dead_code, clippy::match_wildcard_for_single_variants)]"
) # Not all is_methods are used
@ -437,6 +452,15 @@ def write_owned_enum(out: list[str], ast: Ast) -> None:
}}
""")
for node in ast.all_nodes:
out.append(f"""
impl crate::HasNodeIndex for {node.ty} {{
fn node_index(&self) -> &crate::AtomicNodeIndex {{
&self.node_index
}}
}}
""")
for group in ast.groups:
out.append(f"""
impl {group.owned_enum_ty} {{
@ -478,6 +502,7 @@ def write_ref_enum(out: list[str], ast: Ast) -> None:
- `impl<'a> From<&'a TypeParam> for TypeParamRef<'a>`
- `impl<'a> From<&'a TypeParamTypeVar> for TypeParamRef<'a>`
- `impl Ranged for TypeParamRef<'_>`
- `impl HasNodeIndex for TypeParamRef<'_>`
- `fn TypeParamRef::is_type_var() -> bool`
The name of each variant can be customized via the `variant` node option. If
@ -535,6 +560,19 @@ def write_ref_enum(out: list[str], ast: Ast) -> None:
}
""")
out.append(f"""
impl crate::HasNodeIndex for {group.ref_enum_ty}<'_> {{
fn node_index(&self) -> &crate::AtomicNodeIndex {{
match self {{
""")
for node in group.nodes:
out.append(f"Self::{node.variant}(node) => node.node_index(),")
out.append("""
}
}
}
""")
# ------------------------------------------------------------------------------
# AnyNodeRef
@ -558,11 +596,13 @@ def write_anynoderef(out: list[str], ast: Ast) -> None:
- `impl<'a> From<TypeParamRef<'a>> for AnyNodeRef<'a>`
- `impl<'a> From<&'a TypeParamTypeVarTuple> for AnyNodeRef<'a>`
- `impl Ranged for AnyNodeRef<'_>`
- `impl HasNodeIndex for AnyNodeRef<'_>`
- `fn AnyNodeRef::as_ptr(&self) -> std::ptr::NonNull<()>`
- `fn AnyNodeRef::visit_source_order(self, visitor &mut impl SourceOrderVisitor)`
"""
out.append("""
/// A flattened enumeration of all AST nodes.
#[derive(Copy, Clone, Debug, is_macro::Is, PartialEq)]
pub enum AnyNodeRef<'a> {
""")
@ -642,6 +682,19 @@ def write_anynoderef(out: list[str], ast: Ast) -> None:
}
""")
out.append("""
impl crate::HasNodeIndex for AnyNodeRef<'_> {
fn node_index(&self) -> &crate::AtomicNodeIndex {
match self {
""")
for node in ast.all_nodes:
out.append(f"""AnyNodeRef::{node.name}(node) => node.node_index(),""")
out.append("""
}
}
}
""")
out.append("""
impl AnyNodeRef<'_> {
pub fn as_ptr(&self) -> std::ptr::NonNull<()> {
@ -693,6 +746,161 @@ def write_anynoderef(out: list[str], ast: Ast) -> None:
""")
# ------------------------------------------------------------------------------
# AnyRootNodeRef
def write_root_anynoderef(out: list[str], ast: Ast) -> None:
"""
Create the AnyRootNodeRef type.
```rust
pub enum AnyRootNodeRef<'a> {
...
TypeParam(&'a TypeParam),
...
}
```
Also creates:
- `impl<'a> From<&'a TypeParam> for AnyRootNodeRef<'a>`
- `impl<'a> TryFrom<AnyRootNodeRef<'a>> for &'a TypeParam`
- `impl<'a> TryFrom<AnyRootNodeRef<'a>> for &'a TypeParamVarTuple`
- `impl Ranged for AnyRootNodeRef<'_>`
- `impl HasNodeIndex for AnyRootNodeRef<'_>`
- `fn AnyRootNodeRef::visit_source_order(self, visitor &mut impl SourceOrderVisitor)`
"""
out.append("""
/// An enumeration of all AST nodes.
///
/// Unlike `AnyNodeRef`, this type does not flatten nested enums, so its variants only
/// consist of the "root" AST node types. This is useful as it exposes references to the
/// original enums, not just references to their inner values.
///
/// For example, `AnyRootNodeRef::Mod` contains a reference to the `Mod` enum, while
/// `AnyNodeRef` has top-level `AnyNodeRef::ModModule` and `AnyNodeRef::ModExpression`
/// variants.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AnyRootNodeRef<'a> {
""")
for group in ast.groups:
out.append(f"""{group.name}(&'a {group.owned_enum_ty}),""")
for node in ast.ungrouped_nodes:
out.append(f"""{node.name}(&'a {node.ty}),""")
out.append("""
}
""")
for group in ast.groups:
out.append(f"""
impl<'a> From<&'a {group.owned_enum_ty}> for AnyRootNodeRef<'a> {{
fn from(node: &'a {group.owned_enum_ty}) -> AnyRootNodeRef<'a> {{
AnyRootNodeRef::{group.name}(node)
}}
}}
""")
out.append(f"""
impl<'a> TryFrom<AnyRootNodeRef<'a>> for &'a {group.owned_enum_ty} {{
type Error = ();
fn try_from(node: AnyRootNodeRef<'a>) -> Result<&'a {group.owned_enum_ty}, ()> {{
match node {{
AnyRootNodeRef::{group.name}(node) => Ok(node),
_ => Err(())
}}
}}
}}
""")
for node in group.nodes:
out.append(f"""
impl<'a> TryFrom<AnyRootNodeRef<'a>> for &'a {node.ty} {{
type Error = ();
fn try_from(node: AnyRootNodeRef<'a>) -> Result<&'a {node.ty}, ()> {{
match node {{
AnyRootNodeRef::{group.name}({group.owned_enum_ty}::{node.variant}(node)) => Ok(node),
_ => Err(())
}}
}}
}}
""")
for node in ast.ungrouped_nodes:
out.append(f"""
impl<'a> From<&'a {node.ty}> for AnyRootNodeRef<'a> {{
fn from(node: &'a {node.ty}) -> AnyRootNodeRef<'a> {{
AnyRootNodeRef::{node.name}(node)
}}
}}
""")
out.append(f"""
impl<'a> TryFrom<AnyRootNodeRef<'a>> for &'a {node.ty} {{
type Error = ();
fn try_from(node: AnyRootNodeRef<'a>) -> Result<&'a {node.ty}, ()> {{
match node {{
AnyRootNodeRef::{node.name}(node) => Ok(node),
_ => Err(())
}}
}}
}}
""")
out.append("""
impl ruff_text_size::Ranged for AnyRootNodeRef<'_> {
fn range(&self) -> ruff_text_size::TextRange {
match self {
""")
for group in ast.groups:
out.append(f"""AnyRootNodeRef::{group.name}(node) => node.range(),""")
for node in ast.ungrouped_nodes:
out.append(f"""AnyRootNodeRef::{node.name}(node) => node.range(),""")
out.append("""
}
}
}
""")
out.append("""
impl crate::HasNodeIndex for AnyRootNodeRef<'_> {
fn node_index(&self) -> &crate::AtomicNodeIndex {
match self {
""")
for group in ast.groups:
out.append(f"""AnyRootNodeRef::{group.name}(node) => node.node_index(),""")
for node in ast.ungrouped_nodes:
out.append(f"""AnyRootNodeRef::{node.name}(node) => node.node_index(),""")
out.append("""
}
}
}
""")
out.append("""
impl<'a> AnyRootNodeRef<'a> {
pub fn visit_source_order<'b, V>(self, visitor: &mut V)
where
V: crate::visitor::source_order::SourceOrderVisitor<'b> + ?Sized,
'a: 'b,
{
match self {
""")
for group in ast.groups:
out.append(
f"""AnyRootNodeRef::{group.name}(node) => node.visit_source_order(visitor),"""
)
for node in ast.ungrouped_nodes:
out.append(
f"""AnyRootNodeRef::{node.name}(node) => node.visit_source_order(visitor),"""
)
out.append("""
}
}
}
""")
# ------------------------------------------------------------------------------
# NodeKind
@ -757,6 +965,7 @@ def write_node(out: list[str], ast: Ast) -> None:
)
name = node.name
out.append(f"pub struct {name} {{")
out.append("pub node_index: crate::AtomicNodeIndex,")
out.append("pub range: ruff_text_size::TextRange,")
for field in node.fields:
field_str = f"pub {field.name}: "
@ -800,6 +1009,7 @@ def write_source_order(out: list[str], ast: Ast) -> None:
else:
fields_list += f"{field.name},\n"
fields_list += "range: _,\n"
fields_list += "node_index: _,\n"
for field in node.fields_in_source_order():
visitor_name = (
@ -859,6 +1069,7 @@ def generate(ast: Ast) -> list[str]:
write_owned_enum(out, ast)
write_ref_enum(out, ast)
write_anynoderef(out, ast)
write_root_anynoderef(out, ast)
write_nodekind(out, ast)
write_node(out, ast)
write_source_order(out, ast)

View file

@ -547,6 +547,7 @@ impl<'a> From<&'a ast::InterpolatedElement> for InterpolatedElement<'a> {
conversion,
format_spec,
range: _,
node_index: _,
} = interpolated_element;
Self {
@ -576,6 +577,7 @@ impl<'a> From<&'a ast::ElifElseClause> for ComparableElifElseClause<'a> {
fn from(elif_else_clause: &'a ast::ElifElseClause) -> Self {
let ast::ElifElseClause {
range: _,
node_index: _,
test,
body,
} = elif_else_clause;
@ -1109,6 +1111,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
op,
values,
range: _,
node_index: _,
}) => Self::BoolOp(ExprBoolOp {
op: (*op).into(),
values: values.iter().map(Into::into).collect(),
@ -1117,6 +1120,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
target,
value,
range: _,
node_index: _,
}) => Self::NamedExpr(ExprNamed {
target: target.into(),
value: value.into(),
@ -1126,6 +1130,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
op,
right,
range: _,
node_index: _,
}) => Self::BinOp(ExprBinOp {
left: left.into(),
op: (*op).into(),
@ -1135,6 +1140,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
op,
operand,
range: _,
node_index: _,
}) => Self::UnaryOp(ExprUnaryOp {
op: (*op).into(),
operand: operand.into(),
@ -1143,6 +1149,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
parameters,
body,
range: _,
node_index: _,
}) => Self::Lambda(ExprLambda {
parameters: parameters.as_ref().map(Into::into),
body: body.into(),
@ -1152,21 +1159,31 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
body,
orelse,
range: _,
node_index: _,
}) => Self::IfExp(ExprIf {
test: test.into(),
body: body.into(),
orelse: orelse.into(),
}),
ast::Expr::Dict(ast::ExprDict { items, range: _ }) => Self::Dict(ExprDict {
ast::Expr::Dict(ast::ExprDict {
items,
range: _,
node_index: _,
}) => Self::Dict(ExprDict {
items: items.iter().map(ComparableDictItem::from).collect(),
}),
ast::Expr::Set(ast::ExprSet { elts, range: _ }) => Self::Set(ExprSet {
ast::Expr::Set(ast::ExprSet {
elts,
range: _,
node_index: _,
}) => Self::Set(ExprSet {
elts: elts.iter().map(Into::into).collect(),
}),
ast::Expr::ListComp(ast::ExprListComp {
elt,
generators,
range: _,
node_index: _,
}) => Self::ListComp(ExprListComp {
elt: elt.into(),
generators: generators.iter().map(Into::into).collect(),
@ -1175,6 +1192,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
elt,
generators,
range: _,
node_index: _,
}) => Self::SetComp(ExprSetComp {
elt: elt.into(),
generators: generators.iter().map(Into::into).collect(),
@ -1184,6 +1202,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
value,
generators,
range: _,
node_index: _,
}) => Self::DictComp(ExprDictComp {
key: key.into(),
value: value.into(),
@ -1193,27 +1212,39 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
elt,
generators,
range: _,
node_index: _,
parenthesized: _,
}) => Self::GeneratorExp(ExprGenerator {
elt: elt.into(),
generators: generators.iter().map(Into::into).collect(),
}),
ast::Expr::Await(ast::ExprAwait { value, range: _ }) => Self::Await(ExprAwait {
ast::Expr::Await(ast::ExprAwait {
value,
range: _,
node_index: _,
}) => Self::Await(ExprAwait {
value: value.into(),
}),
ast::Expr::Yield(ast::ExprYield { value, range: _ }) => Self::Yield(ExprYield {
ast::Expr::Yield(ast::ExprYield {
value,
range: _,
node_index: _,
}) => Self::Yield(ExprYield {
value: value.as_ref().map(Into::into),
}),
ast::Expr::YieldFrom(ast::ExprYieldFrom { value, range: _ }) => {
Self::YieldFrom(ExprYieldFrom {
value: value.into(),
})
}
ast::Expr::YieldFrom(ast::ExprYieldFrom {
value,
range: _,
node_index: _,
}) => Self::YieldFrom(ExprYieldFrom {
value: value.into(),
}),
ast::Expr::Compare(ast::ExprCompare {
left,
ops,
comparators,
range: _,
node_index: _,
}) => Self::Compare(ExprCompare {
left: left.into(),
ops: ops.iter().copied().map(Into::into).collect(),
@ -1223,42 +1254,55 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
func,
arguments,
range: _,
node_index: _,
}) => Self::Call(ExprCall {
func: func.into(),
arguments: arguments.into(),
}),
ast::Expr::FString(ast::ExprFString { value, range: _ }) => {
Self::FString(ExprFString {
value: value.into(),
})
}
ast::Expr::TString(ast::ExprTString { value, range: _ }) => {
Self::TString(ExprTString {
value: value.into(),
})
}
ast::Expr::StringLiteral(ast::ExprStringLiteral { value, range: _ }) => {
Self::StringLiteral(ExprStringLiteral {
value: ComparableStringLiteral {
value: value.to_str(),
},
})
}
ast::Expr::BytesLiteral(ast::ExprBytesLiteral { value, range: _ }) => {
Self::BytesLiteral(ExprBytesLiteral {
value: ComparableBytesLiteral {
value: Cow::from(value),
},
})
}
ast::Expr::NumberLiteral(ast::ExprNumberLiteral { value, range: _ }) => {
Self::NumberLiteral(ExprNumberLiteral {
value: value.into(),
})
}
ast::Expr::BooleanLiteral(ast::ExprBooleanLiteral { value, range: _ }) => {
Self::BoolLiteral(ExprBoolLiteral { value: *value })
}
ast::Expr::FString(ast::ExprFString {
value,
range: _,
node_index: _,
}) => Self::FString(ExprFString {
value: value.into(),
}),
ast::Expr::TString(ast::ExprTString {
value,
range: _,
node_index: _,
}) => Self::TString(ExprTString {
value: value.into(),
}),
ast::Expr::StringLiteral(ast::ExprStringLiteral {
value,
range: _,
node_index: _,
}) => Self::StringLiteral(ExprStringLiteral {
value: ComparableStringLiteral {
value: value.to_str(),
},
}),
ast::Expr::BytesLiteral(ast::ExprBytesLiteral {
value,
range: _,
node_index: _,
}) => Self::BytesLiteral(ExprBytesLiteral {
value: ComparableBytesLiteral {
value: Cow::from(value),
},
}),
ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
value,
range: _,
node_index: _,
}) => Self::NumberLiteral(ExprNumberLiteral {
value: value.into(),
}),
ast::Expr::BooleanLiteral(ast::ExprBooleanLiteral {
value,
range: _,
node_index: _,
}) => Self::BoolLiteral(ExprBoolLiteral { value: *value }),
ast::Expr::NoneLiteral(_) => Self::NoneLiteral,
ast::Expr::EllipsisLiteral(_) => Self::EllipsisLiteral,
ast::Expr::Attribute(ast::ExprAttribute {
@ -1266,6 +1310,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
attr,
ctx: _,
range: _,
node_index: _,
}) => Self::Attribute(ExprAttribute {
value: value.into(),
attr: attr.as_str(),
@ -1275,6 +1320,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
slice,
ctx: _,
range: _,
node_index: _,
}) => Self::Subscript(ExprSubscript {
value: value.into(),
slice: slice.into(),
@ -1283,6 +1329,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
value,
ctx: _,
range: _,
node_index: _,
}) => Self::Starred(ExprStarred {
value: value.into(),
}),
@ -1291,6 +1338,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
elts,
ctx: _,
range: _,
node_index: _,
}) => Self::List(ExprList {
elts: elts.iter().map(Into::into).collect(),
}),
@ -1298,6 +1346,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
elts,
ctx: _,
range: _,
node_index: _,
parenthesized: _,
}) => Self::Tuple(ExprTuple {
elts: elts.iter().map(Into::into).collect(),
@ -1307,6 +1356,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
upper,
step,
range: _,
node_index: _,
}) => Self::Slice(ExprSlice {
lower: lower.as_ref().map(Into::into),
upper: upper.as_ref().map(Into::into),
@ -1316,6 +1366,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
kind,
value,
range: _,
node_index: _,
}) => Self::IpyEscapeCommand(ExprIpyEscapeCommand { kind: *kind, value }),
}
}
@ -1400,6 +1451,7 @@ impl<'a> From<&'a ast::TypeParam> for ComparableTypeParam<'a> {
bound,
default,
range: _,
node_index: _,
}) => Self::TypeVar(TypeParamTypeVar {
name: name.as_str(),
bound: bound.as_ref().map(Into::into),
@ -1409,6 +1461,7 @@ impl<'a> From<&'a ast::TypeParam> for ComparableTypeParam<'a> {
name,
default,
range: _,
node_index: _,
}) => Self::TypeVarTuple(TypeParamTypeVarTuple {
name: name.as_str(),
default: default.as_ref().map(Into::into),
@ -1417,6 +1470,7 @@ impl<'a> From<&'a ast::TypeParam> for ComparableTypeParam<'a> {
name,
default,
range: _,
node_index: _,
}) => Self::ParamSpec(TypeParamParamSpec {
name: name.as_str(),
default: default.as_ref().map(Into::into),
@ -1596,6 +1650,7 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
returns,
type_params,
range: _,
node_index: _,
}) => Self::FunctionDef(StmtFunctionDef {
is_async: *is_async,
name: name.as_str(),
@ -1612,6 +1667,7 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
decorator_list,
type_params,
range: _,
node_index: _,
}) => Self::ClassDef(StmtClassDef {
name: name.as_str(),
arguments: arguments.as_ref().map(Into::into).unwrap_or_default(),
@ -1619,14 +1675,23 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
decorator_list: decorator_list.iter().map(Into::into).collect(),
type_params: type_params.as_ref().map(Into::into),
}),
ast::Stmt::Return(ast::StmtReturn { value, range: _ }) => Self::Return(StmtReturn {
ast::Stmt::Return(ast::StmtReturn {
value,
range: _,
node_index: _,
}) => Self::Return(StmtReturn {
value: value.as_ref().map(Into::into),
}),
ast::Stmt::Delete(ast::StmtDelete { targets, range: _ }) => Self::Delete(StmtDelete {
ast::Stmt::Delete(ast::StmtDelete {
targets,
range: _,
node_index: _,
}) => Self::Delete(StmtDelete {
targets: targets.iter().map(Into::into).collect(),
}),
ast::Stmt::TypeAlias(ast::StmtTypeAlias {
range: _,
node_index: _,
name,
type_params,
value,
@ -1639,6 +1704,7 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
targets,
value,
range: _,
node_index: _,
}) => Self::Assign(StmtAssign {
targets: targets.iter().map(Into::into).collect(),
value: value.into(),
@ -1648,6 +1714,7 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
op,
value,
range: _,
node_index: _,
}) => Self::AugAssign(StmtAugAssign {
target: target.into(),
op: (*op).into(),
@ -1659,6 +1726,7 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
value,
simple,
range: _,
node_index: _,
}) => Self::AnnAssign(StmtAnnAssign {
target: target.into(),
annotation: annotation.into(),
@ -1672,6 +1740,7 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
body,
orelse,
range: _,
node_index: _,
}) => Self::For(StmtFor {
is_async: *is_async,
target: target.into(),
@ -1684,6 +1753,7 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
body,
orelse,
range: _,
node_index: _,
}) => Self::While(StmtWhile {
test: test.into(),
body: body.iter().map(Into::into).collect(),
@ -1694,6 +1764,7 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
body,
elif_else_clauses,
range: _,
node_index: _,
}) => Self::If(StmtIf {
test: test.into(),
body: body.iter().map(Into::into).collect(),
@ -1704,6 +1775,7 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
items,
body,
range: _,
node_index: _,
}) => Self::With(StmtWith {
is_async: *is_async,
items: items.iter().map(Into::into).collect(),
@ -1713,6 +1785,7 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
subject,
cases,
range: _,
node_index: _,
}) => Self::Match(StmtMatch {
subject: subject.into(),
cases: cases.iter().map(Into::into).collect(),
@ -1721,6 +1794,7 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
exc,
cause,
range: _,
node_index: _,
}) => Self::Raise(StmtRaise {
exc: exc.as_ref().map(Into::into),
cause: cause.as_ref().map(Into::into),
@ -1732,6 +1806,7 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
finalbody,
is_star,
range: _,
node_index: _,
}) => Self::Try(StmtTry {
body: body.iter().map(Into::into).collect(),
handlers: handlers.iter().map(Into::into).collect(),
@ -1743,11 +1818,16 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
test,
msg,
range: _,
node_index: _,
}) => Self::Assert(StmtAssert {
test: test.into(),
msg: msg.as_ref().map(Into::into),
}),
ast::Stmt::Import(ast::StmtImport { names, range: _ }) => Self::Import(StmtImport {
ast::Stmt::Import(ast::StmtImport {
names,
range: _,
node_index: _,
}) => Self::Import(StmtImport {
names: names.iter().map(Into::into).collect(),
}),
ast::Stmt::ImportFrom(ast::StmtImportFrom {
@ -1755,25 +1835,37 @@ impl<'a> From<&'a ast::Stmt> for ComparableStmt<'a> {
names,
level,
range: _,
node_index: _,
}) => Self::ImportFrom(StmtImportFrom {
module: module.as_deref(),
names: names.iter().map(Into::into).collect(),
level: *level,
}),
ast::Stmt::Global(ast::StmtGlobal { names, range: _ }) => Self::Global(StmtGlobal {
ast::Stmt::Global(ast::StmtGlobal {
names,
range: _,
node_index: _,
}) => Self::Global(StmtGlobal {
names: names.iter().map(ast::Identifier::as_str).collect(),
}),
ast::Stmt::Nonlocal(ast::StmtNonlocal {
names,
range: _,
node_index: _,
}) => Self::Nonlocal(StmtNonlocal {
names: names.iter().map(ast::Identifier::as_str).collect(),
}),
ast::Stmt::Nonlocal(ast::StmtNonlocal { names, range: _ }) => {
Self::Nonlocal(StmtNonlocal {
names: names.iter().map(ast::Identifier::as_str).collect(),
})
}
ast::Stmt::IpyEscapeCommand(ast::StmtIpyEscapeCommand {
kind,
value,
range: _,
node_index: _,
}) => Self::IpyEscapeCommand(StmtIpyEscapeCommand { kind: *kind, value }),
ast::Stmt::Expr(ast::StmtExpr { value, range: _ }) => Self::Expr(StmtExpr {
ast::Stmt::Expr(ast::StmtExpr {
value,
range: _,
node_index: _,
}) => Self::Expr(StmtExpr {
value: value.into(),
}),
ast::Stmt::Pass(_) => Self::Pass,

File diff suppressed because it is too large Load diff

View file

@ -12,8 +12,8 @@ use crate::parenthesize::parenthesized_range;
use crate::statement_visitor::StatementVisitor;
use crate::visitor::Visitor;
use crate::{
self as ast, Arguments, CmpOp, DictItem, ExceptHandler, Expr, InterpolatedStringElement,
MatchCase, Operator, Pattern, Stmt, TypeParam,
self as ast, Arguments, AtomicNodeIndex, CmpOp, DictItem, ExceptHandler, Expr,
InterpolatedStringElement, MatchCase, Operator, Pattern, Stmt, TypeParam,
};
use crate::{AnyNodeRef, ExprContext};
@ -53,6 +53,7 @@ where
func,
arguments,
range: _,
node_index: _,
}) = expr
{
// Ex) `list()`
@ -146,6 +147,7 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool {
target,
value,
range: _,
node_index: _,
}) => any_over_expr(target, func) || any_over_expr(value, func),
Expr::BinOp(ast::ExprBinOp { left, right, .. }) => {
any_over_expr(left, func) || any_over_expr(right, func)
@ -157,32 +159,49 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool {
body,
orelse,
range: _,
node_index: _,
}) => any_over_expr(test, func) || any_over_expr(body, func) || any_over_expr(orelse, func),
Expr::Dict(ast::ExprDict { items, range: _ }) => {
items.iter().any(|ast::DictItem { key, value }| {
any_over_expr(value, func)
|| key.as_ref().is_some_and(|key| any_over_expr(key, func))
})
}
Expr::Set(ast::ExprSet { elts, range: _ })
| Expr::List(ast::ExprList { elts, range: _, .. })
| Expr::Tuple(ast::ExprTuple { elts, range: _, .. }) => {
elts.iter().any(|expr| any_over_expr(expr, func))
}
Expr::Dict(ast::ExprDict {
items,
range: _,
node_index: _,
}) => items.iter().any(|ast::DictItem { key, value }| {
any_over_expr(value, func) || key.as_ref().is_some_and(|key| any_over_expr(key, func))
}),
Expr::Set(ast::ExprSet {
elts,
range: _,
node_index: _,
})
| Expr::List(ast::ExprList {
elts,
range: _,
node_index: _,
..
})
| Expr::Tuple(ast::ExprTuple {
elts,
range: _,
node_index: _,
..
}) => elts.iter().any(|expr| any_over_expr(expr, func)),
Expr::ListComp(ast::ExprListComp {
elt,
generators,
range: _,
node_index: _,
})
| Expr::SetComp(ast::ExprSetComp {
elt,
generators,
range: _,
node_index: _,
})
| Expr::Generator(ast::ExprGenerator {
elt,
generators,
range: _,
node_index: _,
parenthesized: _,
}) => {
any_over_expr(elt, func)
@ -197,6 +216,7 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool {
value,
generators,
range: _,
node_index: _,
}) => {
any_over_expr(key, func)
|| any_over_expr(value, func)
@ -206,15 +226,33 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool {
|| generator.ifs.iter().any(|expr| any_over_expr(expr, func))
})
}
Expr::Await(ast::ExprAwait { value, range: _ })
| Expr::YieldFrom(ast::ExprYieldFrom { value, range: _ })
Expr::Await(ast::ExprAwait {
value,
range: _,
node_index: _,
})
| Expr::YieldFrom(ast::ExprYieldFrom {
value,
range: _,
node_index: _,
})
| Expr::Attribute(ast::ExprAttribute {
value, range: _, ..
value,
range: _,
node_index: _,
..
})
| Expr::Starred(ast::ExprStarred {
value, range: _, ..
value,
range: _,
node_index: _,
..
}) => any_over_expr(value, func),
Expr::Yield(ast::ExprYield { value, range: _ }) => value
Expr::Yield(ast::ExprYield {
value,
range: _,
node_index: _,
}) => value
.as_ref()
.is_some_and(|value| any_over_expr(value, func)),
Expr::Compare(ast::ExprCompare {
@ -224,6 +262,7 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool {
func: call_func,
arguments,
range: _,
node_index: _,
}) => {
any_over_expr(call_func, func)
// Note that this is the evaluation order but not necessarily the declaration order
@ -241,6 +280,7 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool {
upper,
step,
range: _,
node_index: _,
}) => {
lower
.as_ref()
@ -284,11 +324,17 @@ pub fn any_over_type_param(type_param: &TypeParam, func: &dyn Fn(&Expr) -> bool)
pub fn any_over_pattern(pattern: &Pattern, func: &dyn Fn(&Expr) -> bool) -> bool {
match pattern {
Pattern::MatchValue(ast::PatternMatchValue { value, range: _ }) => {
any_over_expr(value, func)
}
Pattern::MatchValue(ast::PatternMatchValue {
value,
range: _,
node_index: _,
}) => any_over_expr(value, func),
Pattern::MatchSingleton(_) => false,
Pattern::MatchSequence(ast::PatternMatchSequence { patterns, range: _ }) => patterns
Pattern::MatchSequence(ast::PatternMatchSequence {
patterns,
range: _,
node_index: _,
}) => patterns
.iter()
.any(|pattern| any_over_pattern(pattern, func)),
Pattern::MatchMapping(ast::PatternMatchMapping { keys, patterns, .. }) => {
@ -312,7 +358,11 @@ pub fn any_over_pattern(pattern: &Pattern, func: &dyn Fn(&Expr) -> bool) -> bool
Pattern::MatchAs(ast::PatternMatchAs { pattern, .. }) => pattern
.as_ref()
.is_some_and(|pattern| any_over_pattern(pattern, func)),
Pattern::MatchOr(ast::PatternMatchOr { patterns, range: _ }) => patterns
Pattern::MatchOr(ast::PatternMatchOr {
patterns,
range: _,
node_index: _,
}) => patterns
.iter()
.any(|pattern| any_over_pattern(pattern, func)),
}
@ -395,12 +445,18 @@ pub fn any_over_stmt(stmt: &Stmt, func: &dyn Fn(&Expr) -> bool) -> bool {
.iter()
.any(|decorator| any_over_expr(&decorator.expression, func))
}
Stmt::Return(ast::StmtReturn { value, range: _ }) => value
Stmt::Return(ast::StmtReturn {
value,
range: _,
node_index: _,
}) => value
.as_ref()
.is_some_and(|value| any_over_expr(value, func)),
Stmt::Delete(ast::StmtDelete { targets, range: _ }) => {
targets.iter().any(|expr| any_over_expr(expr, func))
}
Stmt::Delete(ast::StmtDelete {
targets,
range: _,
node_index: _,
}) => targets.iter().any(|expr| any_over_expr(expr, func)),
Stmt::TypeAlias(ast::StmtTypeAlias {
name,
type_params,
@ -450,12 +506,14 @@ pub fn any_over_stmt(stmt: &Stmt, func: &dyn Fn(&Expr) -> bool) -> bool {
body,
orelse,
range: _,
node_index: _,
}) => any_over_expr(test, func) || any_over_body(body, func) || any_over_body(orelse, func),
Stmt::If(ast::StmtIf {
test,
body,
elif_else_clauses,
range: _,
node_index: _,
}) => {
any_over_expr(test, func)
|| any_over_body(body, func)
@ -480,6 +538,7 @@ pub fn any_over_stmt(stmt: &Stmt, func: &dyn Fn(&Expr) -> bool) -> bool {
exc,
cause,
range: _,
node_index: _,
}) => {
exc.as_ref().is_some_and(|value| any_over_expr(value, func))
|| cause
@ -493,6 +552,7 @@ pub fn any_over_stmt(stmt: &Stmt, func: &dyn Fn(&Expr) -> bool) -> bool {
finalbody,
is_star: _,
range: _,
node_index: _,
}) => {
any_over_body(body, func)
|| handlers.iter().any(|handler| {
@ -511,6 +571,7 @@ pub fn any_over_stmt(stmt: &Stmt, func: &dyn Fn(&Expr) -> bool) -> bool {
test,
msg,
range: _,
node_index: _,
}) => {
any_over_expr(test, func)
|| msg.as_ref().is_some_and(|value| any_over_expr(value, func))
@ -519,6 +580,7 @@ pub fn any_over_stmt(stmt: &Stmt, func: &dyn Fn(&Expr) -> bool) -> bool {
subject,
cases,
range: _,
node_index: _,
}) => {
any_over_expr(subject, func)
|| cases.iter().any(|case| {
@ -527,6 +589,7 @@ pub fn any_over_stmt(stmt: &Stmt, func: &dyn Fn(&Expr) -> bool) -> bool {
guard,
body,
range: _,
node_index: _,
} = case;
any_over_pattern(pattern, func)
|| guard.as_ref().is_some_and(|expr| any_over_expr(expr, func))
@ -537,7 +600,11 @@ pub fn any_over_stmt(stmt: &Stmt, func: &dyn Fn(&Expr) -> bool) -> bool {
Stmt::ImportFrom(_) => false,
Stmt::Global(_) => false,
Stmt::Nonlocal(_) => false,
Stmt::Expr(ast::StmtExpr { value, range: _ }) => any_over_expr(value, func),
Stmt::Expr(ast::StmtExpr {
value,
range: _,
node_index: _,
}) => any_over_expr(value, func),
Stmt::Pass(_) | Stmt::Break(_) | Stmt::Continue(_) => false,
Stmt::IpyEscapeCommand(_) => false,
}
@ -957,6 +1024,7 @@ impl<'a> StatementVisitor<'a> for RaiseStatementVisitor<'a> {
exc,
cause,
range: _,
node_index: _,
}) => {
self.raises
.push((stmt.range(), exc.as_deref(), cause.as_deref()));
@ -1026,7 +1094,12 @@ impl Visitor<'_> for AwaitVisitor {
/// Return `true` if a `Stmt` is a docstring.
pub fn is_docstring_stmt(stmt: &Stmt) -> bool {
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt {
if let Stmt::Expr(ast::StmtExpr {
value,
range: _,
node_index: _,
}) = stmt
{
value.is_string_literal_expr()
} else {
false
@ -1039,7 +1112,12 @@ pub fn on_conditional_branch<'a>(parents: &mut impl Iterator<Item = &'a Stmt>) -
if matches!(parent, Stmt::If(_) | Stmt::While(_) | Stmt::Match(_)) {
return true;
}
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = parent {
if let Stmt::Expr(ast::StmtExpr {
value,
range: _,
node_index: _,
}) = parent
{
if value.is_if_expr() {
return true;
}
@ -1480,6 +1558,7 @@ pub fn pep_604_optional(expr: &Expr) -> Expr {
op: Operator::BitOr,
right: Box::new(Expr::NoneLiteral(ast::ExprNoneLiteral::default())),
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
}
.into()
}
@ -1491,6 +1570,7 @@ pub fn pep_604_union(elts: &[Expr]) -> Expr {
elts: vec![],
ctx: ExprContext::Load,
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
parenthesized: true,
}),
[Expr::Tuple(ast::ExprTuple { elts, .. })] => pep_604_union(elts),
@ -1500,6 +1580,7 @@ pub fn pep_604_union(elts: &[Expr]) -> Expr {
op: Operator::BitOr,
right: Box::new(pep_604_union(&[elt.clone()])),
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
}),
}
}
@ -1510,11 +1591,13 @@ pub fn typing_optional(elt: Expr, binding: Name) -> Expr {
value: Box::new(Expr::Name(ast::ExprName {
id: binding,
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
ctx: ExprContext::Load,
})),
slice: Box::new(elt),
ctx: ExprContext::Load,
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
})
}
@ -1527,16 +1610,19 @@ pub fn typing_union(elts: &[Expr], binding: Name) -> Expr {
value: Box::new(Expr::Name(ast::ExprName {
id: binding,
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
ctx: ExprContext::Load,
})),
slice: Box::new(Expr::Tuple(ast::ExprTuple {
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
elts: elts.to_vec(),
ctx: ExprContext::Load,
parenthesized: false,
})),
ctx: ExprContext::Load,
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
})
}
@ -1624,9 +1710,9 @@ mod tests {
use crate::helpers::{any_over_stmt, any_over_type_param, resolve_imported_module_path};
use crate::{
Expr, ExprContext, ExprName, ExprNumberLiteral, Identifier, Int, Number, Stmt,
StmtTypeAlias, TypeParam, TypeParamParamSpec, TypeParamTypeVar, TypeParamTypeVarTuple,
TypeParams,
AtomicNodeIndex, Expr, ExprContext, ExprName, ExprNumberLiteral, Identifier, Int, Number,
Stmt, StmtTypeAlias, TypeParam, TypeParamParamSpec, TypeParamTypeVar,
TypeParamTypeVarTuple, TypeParams,
};
#[test]
@ -1669,28 +1755,34 @@ mod tests {
let name = Expr::Name(ExprName {
id: "x".into(),
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
ctx: ExprContext::Load,
});
let constant_one = Expr::NumberLiteral(ExprNumberLiteral {
value: Number::Int(Int::from(1u8)),
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
});
let constant_two = Expr::NumberLiteral(ExprNumberLiteral {
value: Number::Int(Int::from(2u8)),
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
});
let constant_three = Expr::NumberLiteral(ExprNumberLiteral {
value: Number::Int(Int::from(3u8)),
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
});
let type_var_one = TypeParam::TypeVar(TypeParamTypeVar {
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
bound: Some(Box::new(constant_one.clone())),
default: None,
name: Identifier::new("x", TextRange::default()),
});
let type_var_two = TypeParam::TypeVar(TypeParamTypeVar {
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
bound: None,
default: Some(Box::new(constant_two.clone())),
name: Identifier::new("x", TextRange::default()),
@ -1700,9 +1792,11 @@ mod tests {
type_params: Some(Box::new(TypeParams {
type_params: vec![type_var_one, type_var_two],
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
})),
value: Box::new(constant_three.clone()),
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
});
assert!(!any_over_stmt(&type_alias, &|expr| {
seen.borrow_mut().push(expr.clone());
@ -1718,6 +1812,7 @@ mod tests {
fn any_over_type_param_type_var() {
let type_var_no_bound = TypeParam::TypeVar(TypeParamTypeVar {
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
bound: None,
default: None,
name: Identifier::new("x", TextRange::default()),
@ -1727,10 +1822,12 @@ mod tests {
let constant = Expr::NumberLiteral(ExprNumberLiteral {
value: Number::Int(Int::ONE),
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
});
let type_var_with_bound = TypeParam::TypeVar(TypeParamTypeVar {
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
bound: Some(Box::new(constant.clone())),
default: None,
name: Identifier::new("x", TextRange::default()),
@ -1748,6 +1845,7 @@ mod tests {
let type_var_with_default = TypeParam::TypeVar(TypeParamTypeVar {
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
default: Some(Box::new(constant.clone())),
bound: None,
name: Identifier::new("x", TextRange::default()),
@ -1768,6 +1866,7 @@ mod tests {
fn any_over_type_param_type_var_tuple() {
let type_var_tuple = TypeParam::TypeVarTuple(TypeParamTypeVarTuple {
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
name: Identifier::new("x", TextRange::default()),
default: None,
});
@ -1779,10 +1878,12 @@ mod tests {
let constant = Expr::NumberLiteral(ExprNumberLiteral {
value: Number::Int(Int::ONE),
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
});
let type_var_tuple_with_default = TypeParam::TypeVarTuple(TypeParamTypeVarTuple {
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
default: Some(Box::new(constant.clone())),
name: Identifier::new("x", TextRange::default()),
});
@ -1802,6 +1903,7 @@ mod tests {
fn any_over_type_param_param_spec() {
let type_param_spec = TypeParam::ParamSpec(TypeParamParamSpec {
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
name: Identifier::new("x", TextRange::default()),
default: None,
});
@ -1813,10 +1915,12 @@ mod tests {
let constant = Expr::NumberLiteral(ExprNumberLiteral {
value: Number::Int(Int::ONE),
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
});
let param_spec_with_default = TypeParam::TypeVarTuple(TypeParamTypeVarTuple {
range: TextRange::default(),
node_index: AtomicNodeIndex::dummy(),
default: Some(Box::new(constant.clone())),
name: Identifier::new("x", TextRange::default()),
});

View file

@ -4,6 +4,7 @@ use std::path::Path;
pub use expression::*;
pub use generated::*;
pub use int::*;
pub use node_index::*;
pub use nodes::*;
pub use operator_precedence::*;
pub use python_version::*;
@ -17,6 +18,7 @@ pub mod identifier;
mod int;
pub mod name;
mod node;
mod node_index;
mod nodes;
pub mod operator_precedence;
pub mod parenthesize;

View file

@ -13,6 +13,7 @@ impl ast::ElifElseClause {
{
let ast::ElifElseClause {
range: _,
node_index: _,
test,
body,
} = self;
@ -28,7 +29,11 @@ impl ast::ExprDict {
where
V: SourceOrderVisitor<'a> + ?Sized,
{
let ast::ExprDict { items, range: _ } = self;
let ast::ExprDict {
items,
range: _,
node_index: _,
} = self;
for ast::DictItem { key, value } in items {
if let Some(key) = key {
@ -48,6 +53,7 @@ impl ast::ExprBoolOp {
op,
values,
range: _,
node_index: _,
} = self;
match values.as_slice() {
[left, rest @ ..] => {
@ -74,6 +80,7 @@ impl ast::ExprCompare {
ops,
comparators,
range: _,
node_index: _,
} = self;
visitor.visit_expr(left);
@ -121,7 +128,11 @@ impl ast::InterpolatedStringLiteralElement {
where
V: SourceOrderVisitor<'a> + ?Sized,
{
let ast::InterpolatedStringLiteralElement { range: _, value: _ } = self;
let ast::InterpolatedStringLiteralElement {
range: _,
node_index: _,
value: _,
} = self;
}
}
@ -130,7 +141,11 @@ impl ast::ExprFString {
where
V: SourceOrderVisitor<'a> + ?Sized,
{
let ast::ExprFString { value, range: _ } = self;
let ast::ExprFString {
value,
range: _,
node_index: _,
} = self;
for f_string_part in value {
match f_string_part {
@ -150,7 +165,11 @@ impl ast::ExprTString {
where
V: SourceOrderVisitor<'a> + ?Sized,
{
let ast::ExprTString { value, range: _ } = self;
let ast::ExprTString {
value,
range: _,
node_index: _,
} = self;
for t_string_part in value {
match t_string_part {
@ -173,7 +192,11 @@ impl ast::ExprStringLiteral {
where
V: SourceOrderVisitor<'a> + ?Sized,
{
let ast::ExprStringLiteral { value, range: _ } = self;
let ast::ExprStringLiteral {
value,
range: _,
node_index: _,
} = self;
for string_literal in value {
visitor.visit_string_literal(string_literal);
@ -186,7 +209,11 @@ impl ast::ExprBytesLiteral {
where
V: SourceOrderVisitor<'a> + ?Sized,
{
let ast::ExprBytesLiteral { value, range: _ } = self;
let ast::ExprBytesLiteral {
value,
range: _,
node_index: _,
} = self;
for bytes_literal in value {
visitor.visit_bytes_literal(bytes_literal);
@ -201,6 +228,7 @@ impl ast::ExceptHandlerExceptHandler {
{
let ast::ExceptHandlerExceptHandler {
range: _,
node_index: _,
type_,
name,
body,
@ -222,7 +250,11 @@ impl ast::PatternMatchValue {
where
V: SourceOrderVisitor<'a> + ?Sized,
{
let ast::PatternMatchValue { value, range: _ } = self;
let ast::PatternMatchValue {
value,
range: _,
node_index: _,
} = self;
visitor.visit_expr(value);
}
}
@ -232,7 +264,11 @@ impl ast::PatternMatchSingleton {
where
V: SourceOrderVisitor<'a> + ?Sized,
{
let ast::PatternMatchSingleton { value, range: _ } = self;
let ast::PatternMatchSingleton {
value,
range: _,
node_index: _,
} = self;
visitor.visit_singleton(value);
}
}
@ -242,7 +278,11 @@ impl ast::PatternMatchSequence {
where
V: SourceOrderVisitor<'a> + ?Sized,
{
let ast::PatternMatchSequence { patterns, range: _ } = self;
let ast::PatternMatchSequence {
patterns,
range: _,
node_index: _,
} = self;
for pattern in patterns {
visitor.visit_pattern(pattern);
}
@ -259,6 +299,7 @@ impl ast::PatternMatchMapping {
patterns,
rest,
range: _,
node_index: _,
} = self;
let mut rest = rest.as_ref();
@ -289,6 +330,7 @@ impl ast::PatternMatchClass {
cls,
arguments: parameters,
range: _,
node_index: _,
} = self;
visitor.visit_expr(cls);
visitor.visit_pattern_arguments(parameters);
@ -300,7 +342,11 @@ impl ast::PatternMatchStar {
where
V: SourceOrderVisitor<'a> + ?Sized,
{
let ast::PatternMatchStar { range: _, name } = self;
let ast::PatternMatchStar {
range: _,
node_index: _,
name,
} = self;
if let Some(name) = name {
visitor.visit_identifier(name);
@ -316,6 +362,7 @@ impl ast::PatternMatchAs {
let ast::PatternMatchAs {
pattern,
range: _,
node_index: _,
name,
} = self;
if let Some(pattern) = pattern {
@ -333,7 +380,11 @@ impl ast::PatternMatchOr {
where
V: SourceOrderVisitor<'a> + ?Sized,
{
let ast::PatternMatchOr { patterns, range: _ } = self;
let ast::PatternMatchOr {
patterns,
range: _,
node_index: _,
} = self;
for pattern in patterns {
visitor.visit_pattern(pattern);
}
@ -347,6 +398,7 @@ impl ast::PatternArguments {
{
let PatternArguments {
range: _,
node_index: _,
patterns,
keywords,
} = self;
@ -368,6 +420,7 @@ impl ast::PatternKeyword {
{
let PatternKeyword {
range: _,
node_index: _,
attr,
pattern,
} = self;
@ -384,6 +437,7 @@ impl ast::Comprehension {
{
let ast::Comprehension {
range: _,
node_index: _,
target,
iter,
ifs,
@ -435,6 +489,7 @@ impl ast::Parameter {
{
let ast::Parameter {
range: _,
node_index: _,
name,
annotation,
} = self;
@ -453,6 +508,7 @@ impl ast::ParameterWithDefault {
{
let ast::ParameterWithDefault {
range: _,
node_index: _,
parameter,
default,
} = self;
@ -470,6 +526,7 @@ impl ast::Keyword {
{
let ast::Keyword {
range: _,
node_index: _,
arg,
value,
} = self;
@ -488,6 +545,7 @@ impl Alias {
{
let ast::Alias {
range: _,
node_index: _,
name,
asname,
} = self;
@ -506,6 +564,7 @@ impl ast::WithItem {
{
let ast::WithItem {
range: _,
node_index: _,
context_expr,
optional_vars,
} = self;
@ -525,6 +584,7 @@ impl ast::MatchCase {
{
let ast::MatchCase {
range: _,
node_index: _,
pattern,
guard,
body,
@ -545,6 +605,7 @@ impl ast::Decorator {
{
let ast::Decorator {
range: _,
node_index: _,
expression,
} = self;
@ -559,6 +620,7 @@ impl ast::TypeParams {
{
let ast::TypeParams {
range: _,
node_index: _,
type_params,
} = self;
@ -578,6 +640,7 @@ impl ast::TypeParamTypeVar {
default,
name,
range: _,
node_index: _,
} = self;
visitor.visit_identifier(name);
@ -598,6 +661,7 @@ impl ast::TypeParamTypeVarTuple {
{
let ast::TypeParamTypeVarTuple {
range: _,
node_index: _,
name,
default,
} = self;
@ -616,6 +680,7 @@ impl ast::TypeParamParamSpec {
{
let ast::TypeParamParamSpec {
range: _,
node_index: _,
name,
default,
} = self;
@ -634,6 +699,7 @@ impl ast::FString {
let ast::FString {
elements,
range: _,
node_index: _,
flags: _,
} = self;
@ -651,6 +717,7 @@ impl ast::TString {
let ast::TString {
elements,
range: _,
node_index: _,
flags: _,
} = self;
@ -668,6 +735,7 @@ impl ast::StringLiteral {
{
let ast::StringLiteral {
range: _,
node_index: _,
value: _,
flags: _,
} = self;
@ -682,6 +750,7 @@ impl ast::BytesLiteral {
{
let ast::BytesLiteral {
range: _,
node_index: _,
value: _,
flags: _,
} = self;
@ -694,7 +763,11 @@ impl ast::Identifier {
where
V: SourceOrderVisitor<'a> + ?Sized,
{
let ast::Identifier { range: _, id: _ } = self;
let ast::Identifier {
range: _,
node_index: _,
id: _,
} = self;
}
}

View file

@ -0,0 +1,98 @@
use std::sync::atomic::{AtomicU32, Ordering};
/// An AST node that has an index.
pub trait HasNodeIndex {
/// Returns the [`AtomicNodeIndex`] for this node.
fn node_index(&self) -> &AtomicNodeIndex;
}
impl<T> HasNodeIndex for &T
where
T: HasNodeIndex,
{
fn node_index(&self) -> &AtomicNodeIndex {
T::node_index(*self)
}
}
/// A unique index for a node within an AST.
///
/// This type is interiorly mutable to allow assigning node indices
/// on-demand after parsing.
#[derive(Default)]
pub struct AtomicNodeIndex(AtomicU32);
impl AtomicNodeIndex {
/// Returns a placeholder `AtomicNodeIndex`.
pub fn dummy() -> AtomicNodeIndex {
AtomicNodeIndex(AtomicU32::from(u32::MAX))
}
/// Load the current value of the `AtomicNodeIndex`.
pub fn load(&self) -> NodeIndex {
NodeIndex(self.0.load(Ordering::Relaxed))
}
/// Set the value of the `AtomicNodeIndex`.
pub fn set(&self, value: u32) {
self.0.store(value, Ordering::Relaxed);
}
}
/// A unique index for a node within an AST.
#[derive(PartialEq, Eq, Debug, PartialOrd, Ord, Clone, Copy, Hash)]
pub struct NodeIndex(u32);
impl NodeIndex {
pub fn as_usize(self) -> usize {
self.0 as _
}
}
impl From<u32> for AtomicNodeIndex {
fn from(value: u32) -> Self {
AtomicNodeIndex(AtomicU32::from(value))
}
}
impl std::fmt::Debug for AtomicNodeIndex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if *self == AtomicNodeIndex::dummy() {
f.debug_tuple("AtomicNodeIndex").finish_non_exhaustive()
} else {
f.debug_tuple("AtomicNodeIndex").field(&self.0).finish()
}
}
}
impl std::hash::Hash for AtomicNodeIndex {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.load().hash(state);
}
}
impl PartialOrd for AtomicNodeIndex {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for AtomicNodeIndex {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.load().cmp(&other.load())
}
}
impl Eq for AtomicNodeIndex {}
impl PartialEq for AtomicNodeIndex {
fn eq(&self, other: &Self) -> bool {
self.load() == other.load()
}
}
impl Clone for AtomicNodeIndex {
fn clone(&self) -> Self {
Self(AtomicU32::from(self.0.load(Ordering::Relaxed)))
}
}

View file

@ -1,5 +1,6 @@
#![allow(clippy::derive_partial_eq_without_eq)]
use crate::AtomicNodeIndex;
use crate::generated::{
ExprBytesLiteral, ExprDict, ExprFString, ExprList, ExprName, ExprSet, ExprStringLiteral,
ExprTString, ExprTuple, StmtClassDef,
@ -48,6 +49,7 @@ impl StmtClassDef {
#[derive(Clone, Debug, PartialEq)]
pub struct ElifElseClause {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub test: Option<Expr>,
pub body: Vec<Stmt>,
}
@ -316,6 +318,7 @@ impl<'a> IntoIterator for &'a ExprSet {
#[derive(Clone, Debug, PartialEq)]
pub struct InterpolatedStringFormatSpec {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub elements: InterpolatedStringElements,
}
@ -323,6 +326,7 @@ pub struct InterpolatedStringFormatSpec {
#[derive(Clone, Debug, PartialEq)]
pub struct InterpolatedElement {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub expression: Box<Expr>,
pub debug_text: Option<DebugText>,
pub conversion: ConversionFlag,
@ -333,6 +337,7 @@ pub struct InterpolatedElement {
#[derive(Clone, Debug, PartialEq)]
pub struct InterpolatedStringLiteralElement {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub value: Box<str>,
}
@ -1105,6 +1110,7 @@ impl fmt::Debug for TStringFlags {
#[derive(Clone, Debug, PartialEq)]
pub struct FString {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub elements: InterpolatedStringElements,
pub flags: FStringFlags,
}
@ -1112,6 +1118,7 @@ pub struct FString {
impl From<FString> for Expr {
fn from(payload: FString) -> Self {
ExprFString {
node_index: payload.node_index.clone(),
range: payload.range,
value: FStringValue::single(payload),
}
@ -1183,6 +1190,7 @@ impl fmt::Debug for InterpolatedStringElements {
#[derive(Clone, Debug, PartialEq)]
pub struct TString {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub elements: InterpolatedStringElements,
pub flags: TStringFlags,
}
@ -1190,6 +1198,7 @@ pub struct TString {
impl From<TString> for Expr {
fn from(payload: TString) -> Self {
ExprTString {
node_index: payload.node_index.clone(),
range: payload.range,
value: TStringValue::single(payload),
}
@ -1553,6 +1562,7 @@ impl fmt::Debug for StringLiteralFlags {
#[derive(Clone, Debug, PartialEq)]
pub struct StringLiteral {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub value: Box<str>,
pub flags: StringLiteralFlags,
}
@ -1576,6 +1586,7 @@ impl StringLiteral {
Self {
range,
value: "".into(),
node_index: AtomicNodeIndex::dummy(),
flags: StringLiteralFlags::empty().with_invalid(),
}
}
@ -1595,6 +1606,7 @@ impl From<StringLiteral> for Expr {
fn from(payload: StringLiteral) -> Self {
ExprStringLiteral {
range: payload.range,
node_index: AtomicNodeIndex::dummy(),
value: StringLiteralValue::single(payload),
}
.into()
@ -1941,6 +1953,7 @@ impl fmt::Debug for BytesLiteralFlags {
#[derive(Clone, Debug, PartialEq)]
pub struct BytesLiteral {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub value: Box<[u8]>,
pub flags: BytesLiteralFlags,
}
@ -1964,6 +1977,7 @@ impl BytesLiteral {
Self {
range,
value: Box::new([]),
node_index: AtomicNodeIndex::dummy(),
flags: BytesLiteralFlags::empty().with_invalid(),
}
}
@ -1973,6 +1987,7 @@ impl From<BytesLiteral> for Expr {
fn from(payload: BytesLiteral) -> Self {
ExprBytesLiteral {
range: payload.range,
node_index: AtomicNodeIndex::dummy(),
value: BytesLiteralValue::single(payload),
}
.into()
@ -2573,6 +2588,7 @@ impl fmt::Display for CmpOp {
#[derive(Clone, Debug, PartialEq)]
pub struct Comprehension {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub target: Expr,
pub iter: Expr,
pub ifs: Vec<Expr>,
@ -2583,6 +2599,7 @@ pub struct Comprehension {
#[derive(Clone, Debug, PartialEq)]
pub struct ExceptHandlerExceptHandler {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub type_: Option<Box<Expr>>,
pub name: Option<Identifier>,
pub body: Vec<Stmt>,
@ -2592,6 +2609,7 @@ pub struct ExceptHandlerExceptHandler {
#[derive(Clone, Debug, PartialEq)]
pub struct Parameter {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub name: Identifier,
pub annotation: Option<Box<Expr>>,
}
@ -2610,6 +2628,7 @@ impl Parameter {
#[derive(Clone, Debug, PartialEq)]
pub struct Keyword {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub arg: Option<Identifier>,
pub value: Expr,
}
@ -2618,6 +2637,7 @@ pub struct Keyword {
#[derive(Clone, Debug, PartialEq)]
pub struct Alias {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub name: Identifier,
pub asname: Option<Identifier>,
}
@ -2626,6 +2646,7 @@ pub struct Alias {
#[derive(Clone, Debug, PartialEq)]
pub struct WithItem {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub context_expr: Expr,
pub optional_vars: Option<Box<Expr>>,
}
@ -2634,6 +2655,7 @@ pub struct WithItem {
#[derive(Clone, Debug, PartialEq)]
pub struct MatchCase {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub pattern: Pattern,
pub guard: Option<Box<Expr>>,
pub body: Vec<Stmt>,
@ -2654,16 +2676,19 @@ impl Pattern {
pattern,
name,
range,
node_index,
}) => match pattern {
Some(pattern) => pattern.irrefutable_pattern(),
None => match name {
Some(name) => Some(IrrefutablePattern {
kind: IrrefutablePatternKind::Name(name.id.clone()),
range: *range,
node_index: node_index.clone(),
}),
None => Some(IrrefutablePattern {
kind: IrrefutablePatternKind::Wildcard,
range: *range,
node_index: node_index.clone(),
}),
},
},
@ -2701,6 +2726,7 @@ impl Pattern {
pub struct IrrefutablePattern {
pub kind: IrrefutablePatternKind,
pub range: TextRange,
pub node_index: AtomicNodeIndex,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -2713,6 +2739,7 @@ pub enum IrrefutablePatternKind {
#[derive(Clone, Debug, PartialEq)]
pub struct PatternMatchValue {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub value: Box<Expr>,
}
@ -2720,6 +2747,7 @@ pub struct PatternMatchValue {
#[derive(Clone, Debug, PartialEq)]
pub struct PatternMatchSingleton {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub value: Singleton,
}
@ -2727,6 +2755,7 @@ pub struct PatternMatchSingleton {
#[derive(Clone, Debug, PartialEq)]
pub struct PatternMatchSequence {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub patterns: Vec<Pattern>,
}
@ -2734,6 +2763,7 @@ pub struct PatternMatchSequence {
#[derive(Clone, Debug, PartialEq)]
pub struct PatternMatchMapping {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub keys: Vec<Expr>,
pub patterns: Vec<Pattern>,
pub rest: Option<Identifier>,
@ -2743,6 +2773,7 @@ pub struct PatternMatchMapping {
#[derive(Clone, Debug, PartialEq)]
pub struct PatternMatchClass {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub cls: Box<Expr>,
pub arguments: PatternArguments,
}
@ -2754,6 +2785,7 @@ pub struct PatternMatchClass {
#[derive(Clone, Debug, PartialEq)]
pub struct PatternArguments {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub patterns: Vec<Pattern>,
pub keywords: Vec<PatternKeyword>,
}
@ -2765,6 +2797,7 @@ pub struct PatternArguments {
#[derive(Clone, Debug, PartialEq)]
pub struct PatternKeyword {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub attr: Identifier,
pub pattern: Pattern,
}
@ -2773,6 +2806,7 @@ pub struct PatternKeyword {
#[derive(Clone, Debug, PartialEq)]
pub struct PatternMatchStar {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub name: Option<Identifier>,
}
@ -2780,6 +2814,7 @@ pub struct PatternMatchStar {
#[derive(Clone, Debug, PartialEq)]
pub struct PatternMatchAs {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub pattern: Option<Box<Pattern>>,
pub name: Option<Identifier>,
}
@ -2788,6 +2823,7 @@ pub struct PatternMatchAs {
#[derive(Clone, Debug, PartialEq)]
pub struct PatternMatchOr {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub patterns: Vec<Pattern>,
}
@ -2813,6 +2849,7 @@ impl TypeParam {
#[derive(Clone, Debug, PartialEq)]
pub struct TypeParamTypeVar {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub name: Identifier,
pub bound: Option<Box<Expr>>,
pub default: Option<Box<Expr>>,
@ -2822,6 +2859,7 @@ pub struct TypeParamTypeVar {
#[derive(Clone, Debug, PartialEq)]
pub struct TypeParamParamSpec {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub name: Identifier,
pub default: Option<Box<Expr>>,
}
@ -2830,6 +2868,7 @@ pub struct TypeParamParamSpec {
#[derive(Clone, Debug, PartialEq)]
pub struct TypeParamTypeVarTuple {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub name: Identifier,
pub default: Option<Box<Expr>>,
}
@ -2838,6 +2877,7 @@ pub struct TypeParamTypeVarTuple {
#[derive(Clone, Debug, PartialEq)]
pub struct Decorator {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub expression: Expr,
}
@ -2911,6 +2951,7 @@ impl Ranged for AnyParameterRef<'_> {
#[derive(Clone, Debug, PartialEq, Default)]
pub struct Parameters {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub posonlyargs: Vec<ParameterWithDefault>,
pub args: Vec<ParameterWithDefault>,
pub vararg: Option<Box<Parameter>>,
@ -2945,6 +2986,7 @@ impl Parameters {
pub fn len(&self) -> usize {
let Parameters {
range: _,
node_index: _,
posonlyargs,
args,
vararg,
@ -2993,6 +3035,7 @@ impl<'a> ParametersIterator<'a> {
fn new(parameters: &'a Parameters) -> Self {
let Parameters {
range: _,
node_index: _,
posonlyargs,
args,
vararg,
@ -3127,6 +3170,7 @@ impl<'a> IntoIterator for &'a Box<Parameters> {
#[derive(Clone, Debug, PartialEq)]
pub struct ParameterWithDefault {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub parameter: Parameter,
pub default: Option<Box<Expr>>,
}
@ -3170,6 +3214,7 @@ impl ParameterWithDefault {
#[derive(Clone, Debug, PartialEq)]
pub struct Arguments {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub args: Box<[Expr]>,
pub keywords: Box<[Keyword]>,
}
@ -3319,6 +3364,7 @@ impl Arguments {
#[derive(Clone, Debug, PartialEq)]
pub struct TypeParams {
pub range: TextRange,
pub node_index: AtomicNodeIndex,
pub type_params: Vec<TypeParam>,
}
@ -3433,6 +3479,7 @@ impl IpyEscapeKind {
pub struct Identifier {
pub id: Name,
pub range: TextRange,
pub node_index: AtomicNodeIndex,
}
impl Identifier {
@ -3440,6 +3487,7 @@ impl Identifier {
pub fn new(id: impl Into<Name>, range: TextRange) -> Self {
Self {
id: id.into(),
node_index: AtomicNodeIndex::dummy(),
range,
}
}
@ -3527,45 +3575,44 @@ mod tests {
#[test]
#[cfg(target_pointer_width = "64")]
fn size() {
assert!(std::mem::size_of::<Stmt>() <= 120);
assert!(std::mem::size_of::<StmtFunctionDef>() <= 120);
assert!(std::mem::size_of::<StmtClassDef>() <= 104);
assert!(std::mem::size_of::<StmtTry>() <= 112);
assert!(std::mem::size_of::<Mod>() <= 32);
assert!(matches!(std::mem::size_of::<Pattern>(), 88));
assert_eq!(std::mem::size_of::<Expr>(), 64);
assert_eq!(std::mem::size_of::<ExprAttribute>(), 56);
assert_eq!(std::mem::size_of::<ExprAwait>(), 16);
assert_eq!(std::mem::size_of::<Stmt>(), 128);
assert_eq!(std::mem::size_of::<StmtFunctionDef>(), 128);
assert_eq!(std::mem::size_of::<StmtClassDef>(), 120);
assert_eq!(std::mem::size_of::<StmtTry>(), 112);
assert_eq!(std::mem::size_of::<Mod>(), 40);
assert_eq!(std::mem::size_of::<Pattern>(), 104);
assert_eq!(std::mem::size_of::<Expr>(), 80);
assert_eq!(std::mem::size_of::<ExprAttribute>(), 64);
assert_eq!(std::mem::size_of::<ExprAwait>(), 24);
assert_eq!(std::mem::size_of::<ExprBinOp>(), 32);
assert_eq!(std::mem::size_of::<ExprBoolOp>(), 40);
assert_eq!(std::mem::size_of::<ExprBooleanLiteral>(), 12);
assert_eq!(std::mem::size_of::<ExprBytesLiteral>(), 40);
assert_eq!(std::mem::size_of::<ExprCall>(), 56);
assert_eq!(std::mem::size_of::<ExprCompare>(), 48);
assert_eq!(std::mem::size_of::<ExprDict>(), 32);
assert_eq!(std::mem::size_of::<ExprDictComp>(), 48);
assert_eq!(std::mem::size_of::<ExprEllipsisLiteral>(), 8);
assert!(matches!(std::mem::size_of::<ExprFString>(), 48));
assert_eq!(std::mem::size_of::<ExprBooleanLiteral>(), 16);
assert_eq!(std::mem::size_of::<ExprBytesLiteral>(), 48);
assert_eq!(std::mem::size_of::<ExprCall>(), 72);
assert_eq!(std::mem::size_of::<ExprCompare>(), 56);
assert_eq!(std::mem::size_of::<ExprDict>(), 40);
assert_eq!(std::mem::size_of::<ExprDictComp>(), 56);
assert_eq!(std::mem::size_of::<ExprEllipsisLiteral>(), 12);
assert_eq!(std::mem::size_of::<ExprFString>(), 56);
assert_eq!(std::mem::size_of::<ExprGenerator>(), 48);
assert_eq!(std::mem::size_of::<ExprIf>(), 32);
assert_eq!(std::mem::size_of::<ExprIf>(), 40);
assert_eq!(std::mem::size_of::<ExprIpyEscapeCommand>(), 32);
assert_eq!(std::mem::size_of::<ExprLambda>(), 24);
assert_eq!(std::mem::size_of::<ExprLambda>(), 32);
assert_eq!(std::mem::size_of::<ExprList>(), 40);
assert_eq!(std::mem::size_of::<ExprListComp>(), 40);
assert_eq!(std::mem::size_of::<ExprListComp>(), 48);
assert_eq!(std::mem::size_of::<ExprName>(), 40);
assert_eq!(std::mem::size_of::<ExprNamed>(), 24);
assert_eq!(std::mem::size_of::<ExprNoneLiteral>(), 8);
assert_eq!(std::mem::size_of::<ExprNumberLiteral>(), 32);
assert_eq!(std::mem::size_of::<ExprSet>(), 32);
assert_eq!(std::mem::size_of::<ExprSetComp>(), 40);
assert_eq!(std::mem::size_of::<ExprSlice>(), 32);
assert_eq!(std::mem::size_of::<ExprNamed>(), 32);
assert_eq!(std::mem::size_of::<ExprNoneLiteral>(), 12);
assert_eq!(std::mem::size_of::<ExprNumberLiteral>(), 40);
assert_eq!(std::mem::size_of::<ExprSet>(), 40);
assert_eq!(std::mem::size_of::<ExprSetComp>(), 48);
assert_eq!(std::mem::size_of::<ExprSlice>(), 40);
assert_eq!(std::mem::size_of::<ExprStarred>(), 24);
assert_eq!(std::mem::size_of::<ExprStringLiteral>(), 56);
assert_eq!(std::mem::size_of::<ExprStringLiteral>(), 64);
assert_eq!(std::mem::size_of::<ExprSubscript>(), 32);
assert_eq!(std::mem::size_of::<ExprTuple>(), 40);
assert_eq!(std::mem::size_of::<ExprUnaryOp>(), 24);
assert_eq!(std::mem::size_of::<ExprYield>(), 16);
assert_eq!(std::mem::size_of::<ExprYieldFrom>(), 16);
assert_eq!(std::mem::size_of::<ExprYield>(), 24);
assert_eq!(std::mem::size_of::<ExprYieldFrom>(), 24);
}
}

View file

@ -87,10 +87,10 @@ impl Transformer for Relocator {
Expr::BooleanLiteral(ast::ExprBooleanLiteral { range, .. }) => {
*range = self.range;
}
Expr::NoneLiteral(ast::ExprNoneLiteral { range }) => {
Expr::NoneLiteral(ast::ExprNoneLiteral { range, .. }) => {
*range = self.range;
}
Expr::EllipsisLiteral(ast::ExprEllipsisLiteral { range }) => {
Expr::EllipsisLiteral(ast::ExprEllipsisLiteral { range, .. }) => {
*range = self.range;
}
Expr::Attribute(ast::ExprAttribute { range, .. }) => {

View file

@ -172,18 +172,27 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
}
visitor.visit_body(body);
}
Stmt::Return(ast::StmtReturn { value, range: _ }) => {
Stmt::Return(ast::StmtReturn {
value,
range: _,
node_index: _,
}) => {
if let Some(expr) = value {
visitor.visit_expr(expr);
}
}
Stmt::Delete(ast::StmtDelete { targets, range: _ }) => {
Stmt::Delete(ast::StmtDelete {
targets,
range: _,
node_index: _,
}) => {
for expr in targets {
visitor.visit_expr(expr);
}
}
Stmt::TypeAlias(ast::StmtTypeAlias {
range: _,
node_index: _,
name,
type_params,
value,
@ -205,6 +214,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
op,
value,
range: _,
node_index: _,
}) => {
visitor.visit_expr(value);
visitor.visit_operator(op);
@ -239,6 +249,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
body,
orelse,
range: _,
node_index: _,
}) => {
visitor.visit_expr(test);
visitor.visit_body(body);
@ -249,6 +260,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
body,
elif_else_clauses,
range: _,
node_index: _,
}) => {
visitor.visit_expr(test);
visitor.visit_body(body);
@ -269,6 +281,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
subject,
cases,
range: _,
node_index: _,
}) => {
visitor.visit_expr(subject);
for match_case in cases {
@ -279,6 +292,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
exc,
cause,
range: _,
node_index: _,
}) => {
if let Some(expr) = exc {
visitor.visit_expr(expr);
@ -294,6 +308,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
finalbody,
is_star: _,
range: _,
node_index: _,
}) => {
visitor.visit_body(body);
for except_handler in handlers {
@ -306,13 +321,18 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
test,
msg,
range: _,
node_index: _,
}) => {
visitor.visit_expr(test);
if let Some(expr) = msg {
visitor.visit_expr(expr);
}
}
Stmt::Import(ast::StmtImport { names, range: _ }) => {
Stmt::Import(ast::StmtImport {
names,
range: _,
node_index: _,
}) => {
for alias in names {
visitor.visit_alias(alias);
}
@ -324,7 +344,11 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
}
Stmt::Global(_) => {}
Stmt::Nonlocal(_) => {}
Stmt::Expr(ast::StmtExpr { value, range: _ }) => visitor.visit_expr(value),
Stmt::Expr(ast::StmtExpr {
value,
range: _,
node_index: _,
}) => visitor.visit_expr(value),
Stmt::Pass(_) | Stmt::Break(_) | Stmt::Continue(_) | Stmt::IpyEscapeCommand(_) => {}
}
}
@ -343,6 +367,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
op,
values,
range: _,
node_index: _,
}) => {
visitor.visit_bool_op(op);
for expr in values {
@ -353,6 +378,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
target,
value,
range: _,
node_index: _,
}) => {
visitor.visit_expr(value);
visitor.visit_expr(target);
@ -362,6 +388,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
op,
right,
range: _,
node_index: _,
}) => {
visitor.visit_expr(left);
visitor.visit_operator(op);
@ -371,6 +398,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
op,
operand,
range: _,
node_index: _,
}) => {
visitor.visit_unary_op(op);
visitor.visit_expr(operand);
@ -379,6 +407,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
parameters,
body,
range: _,
node_index: _,
}) => {
if let Some(parameters) = parameters {
visitor.visit_parameters(parameters);
@ -390,12 +419,17 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
body,
orelse,
range: _,
node_index: _,
}) => {
visitor.visit_expr(test);
visitor.visit_expr(body);
visitor.visit_expr(orelse);
}
Expr::Dict(ast::ExprDict { items, range: _ }) => {
Expr::Dict(ast::ExprDict {
items,
range: _,
node_index: _,
}) => {
for ast::DictItem { key, value } in items {
if let Some(key) = key {
visitor.visit_expr(key);
@ -403,7 +437,11 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
visitor.visit_expr(value);
}
}
Expr::Set(ast::ExprSet { elts, range: _ }) => {
Expr::Set(ast::ExprSet {
elts,
range: _,
node_index: _,
}) => {
for expr in elts {
visitor.visit_expr(expr);
}
@ -412,6 +450,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
elt,
generators,
range: _,
node_index: _,
}) => {
for comprehension in generators {
visitor.visit_comprehension(comprehension);
@ -422,6 +461,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
elt,
generators,
range: _,
node_index: _,
}) => {
for comprehension in generators {
visitor.visit_comprehension(comprehension);
@ -433,6 +473,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
value,
generators,
range: _,
node_index: _,
}) => {
for comprehension in generators {
visitor.visit_comprehension(comprehension);
@ -444,6 +485,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
elt,
generators,
range: _,
node_index: _,
parenthesized: _,
}) => {
for comprehension in generators {
@ -451,18 +493,31 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
}
visitor.visit_expr(elt);
}
Expr::Await(ast::ExprAwait { value, range: _ }) => visitor.visit_expr(value),
Expr::Yield(ast::ExprYield { value, range: _ }) => {
Expr::Await(ast::ExprAwait {
value,
range: _,
node_index: _,
}) => visitor.visit_expr(value),
Expr::Yield(ast::ExprYield {
value,
range: _,
node_index: _,
}) => {
if let Some(expr) = value {
visitor.visit_expr(expr);
}
}
Expr::YieldFrom(ast::ExprYieldFrom { value, range: _ }) => visitor.visit_expr(value),
Expr::YieldFrom(ast::ExprYieldFrom {
value,
range: _,
node_index: _,
}) => visitor.visit_expr(value),
Expr::Compare(ast::ExprCompare {
left,
ops,
comparators,
range: _,
node_index: _,
}) => {
visitor.visit_expr(left);
for cmp_op in ops {
@ -476,6 +531,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
func,
arguments,
range: _,
node_index: _,
}) => {
visitor.visit_expr(func);
visitor.visit_arguments(arguments);
@ -524,6 +580,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
slice,
ctx,
range: _,
node_index: _,
}) => {
visitor.visit_expr(value);
visitor.visit_expr(slice);
@ -533,6 +590,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
value,
ctx,
range: _,
node_index: _,
}) => {
visitor.visit_expr(value);
visitor.visit_expr_context(ctx);
@ -544,6 +602,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
elts,
ctx,
range: _,
node_index: _,
}) => {
for expr in elts {
visitor.visit_expr(expr);
@ -554,6 +613,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
elts,
ctx,
range: _,
node_index: _,
parenthesized: _,
}) => {
for expr in elts {
@ -566,6 +626,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
upper,
step,
range: _,
node_index: _,
}) => {
if let Some(expr) = lower {
visitor.visit_expr(expr);
@ -662,6 +723,7 @@ pub fn walk_type_param<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, type_param:
default,
name: _,
range: _,
node_index: _,
}) => {
if let Some(expr) = bound {
visitor.visit_expr(expr);
@ -674,6 +736,7 @@ pub fn walk_type_param<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, type_param:
default,
name: _,
range: _,
node_index: _,
}) => {
if let Some(expr) = default {
visitor.visit_expr(expr);
@ -683,6 +746,7 @@ pub fn walk_type_param<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, type_param:
default,
name: _,
range: _,
node_index: _,
}) => {
if let Some(expr) = default {
visitor.visit_expr(expr);

View file

@ -159,18 +159,27 @@ pub fn walk_stmt<V: Transformer + ?Sized>(visitor: &V, stmt: &mut Stmt) {
}
visitor.visit_body(body);
}
Stmt::Return(ast::StmtReturn { value, range: _ }) => {
Stmt::Return(ast::StmtReturn {
value,
range: _,
node_index: _,
}) => {
if let Some(expr) = value {
visitor.visit_expr(expr);
}
}
Stmt::Delete(ast::StmtDelete { targets, range: _ }) => {
Stmt::Delete(ast::StmtDelete {
targets,
range: _,
node_index: _,
}) => {
for expr in targets {
visitor.visit_expr(expr);
}
}
Stmt::TypeAlias(ast::StmtTypeAlias {
range: _,
node_index: _,
name,
type_params,
value,
@ -192,6 +201,7 @@ pub fn walk_stmt<V: Transformer + ?Sized>(visitor: &V, stmt: &mut Stmt) {
op,
value,
range: _,
node_index: _,
}) => {
visitor.visit_expr(value);
visitor.visit_operator(op);
@ -226,6 +236,7 @@ pub fn walk_stmt<V: Transformer + ?Sized>(visitor: &V, stmt: &mut Stmt) {
body,
orelse,
range: _,
node_index: _,
}) => {
visitor.visit_expr(test);
visitor.visit_body(body);
@ -236,6 +247,7 @@ pub fn walk_stmt<V: Transformer + ?Sized>(visitor: &V, stmt: &mut Stmt) {
body,
elif_else_clauses,
range: _,
node_index: _,
}) => {
visitor.visit_expr(test);
visitor.visit_body(body);
@ -253,6 +265,7 @@ pub fn walk_stmt<V: Transformer + ?Sized>(visitor: &V, stmt: &mut Stmt) {
subject,
cases,
range: _,
node_index: _,
}) => {
visitor.visit_expr(subject);
for match_case in cases {
@ -263,6 +276,7 @@ pub fn walk_stmt<V: Transformer + ?Sized>(visitor: &V, stmt: &mut Stmt) {
exc,
cause,
range: _,
node_index: _,
}) => {
if let Some(expr) = exc {
visitor.visit_expr(expr);
@ -278,6 +292,7 @@ pub fn walk_stmt<V: Transformer + ?Sized>(visitor: &V, stmt: &mut Stmt) {
finalbody,
is_star: _,
range: _,
node_index: _,
}) => {
visitor.visit_body(body);
for except_handler in handlers {
@ -290,13 +305,18 @@ pub fn walk_stmt<V: Transformer + ?Sized>(visitor: &V, stmt: &mut Stmt) {
test,
msg,
range: _,
node_index: _,
}) => {
visitor.visit_expr(test);
if let Some(expr) = msg {
visitor.visit_expr(expr);
}
}
Stmt::Import(ast::StmtImport { names, range: _ }) => {
Stmt::Import(ast::StmtImport {
names,
range: _,
node_index: _,
}) => {
for alias in names {
visitor.visit_alias(alias);
}
@ -308,7 +328,11 @@ pub fn walk_stmt<V: Transformer + ?Sized>(visitor: &V, stmt: &mut Stmt) {
}
Stmt::Global(_) => {}
Stmt::Nonlocal(_) => {}
Stmt::Expr(ast::StmtExpr { value, range: _ }) => visitor.visit_expr(value),
Stmt::Expr(ast::StmtExpr {
value,
range: _,
node_index: _,
}) => visitor.visit_expr(value),
Stmt::Pass(_) | Stmt::Break(_) | Stmt::Continue(_) | Stmt::IpyEscapeCommand(_) => {}
}
}
@ -327,6 +351,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
op,
values,
range: _,
node_index: _,
}) => {
visitor.visit_bool_op(op);
for expr in values {
@ -337,6 +362,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
target,
value,
range: _,
node_index: _,
}) => {
visitor.visit_expr(value);
visitor.visit_expr(target);
@ -346,6 +372,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
op,
right,
range: _,
node_index: _,
}) => {
visitor.visit_expr(left);
visitor.visit_operator(op);
@ -355,6 +382,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
op,
operand,
range: _,
node_index: _,
}) => {
visitor.visit_unary_op(op);
visitor.visit_expr(operand);
@ -363,6 +391,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
parameters,
body,
range: _,
node_index: _,
}) => {
if let Some(parameters) = parameters {
visitor.visit_parameters(parameters);
@ -374,12 +403,17 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
body,
orelse,
range: _,
node_index: _,
}) => {
visitor.visit_expr(test);
visitor.visit_expr(body);
visitor.visit_expr(orelse);
}
Expr::Dict(ast::ExprDict { items, range: _ }) => {
Expr::Dict(ast::ExprDict {
items,
range: _,
node_index: _,
}) => {
for ast::DictItem { key, value } in items {
if let Some(key) = key {
visitor.visit_expr(key);
@ -387,7 +421,11 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
visitor.visit_expr(value);
}
}
Expr::Set(ast::ExprSet { elts, range: _ }) => {
Expr::Set(ast::ExprSet {
elts,
range: _,
node_index: _,
}) => {
for expr in elts {
visitor.visit_expr(expr);
}
@ -396,6 +434,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
elt,
generators,
range: _,
node_index: _,
}) => {
for comprehension in generators {
visitor.visit_comprehension(comprehension);
@ -406,6 +445,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
elt,
generators,
range: _,
node_index: _,
}) => {
for comprehension in generators {
visitor.visit_comprehension(comprehension);
@ -417,6 +457,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
value,
generators,
range: _,
node_index: _,
}) => {
for comprehension in generators {
visitor.visit_comprehension(comprehension);
@ -428,6 +469,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
elt,
generators,
range: _,
node_index: _,
parenthesized: _,
}) => {
for comprehension in generators {
@ -435,18 +477,31 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
}
visitor.visit_expr(elt);
}
Expr::Await(ast::ExprAwait { value, range: _ }) => visitor.visit_expr(value),
Expr::Yield(ast::ExprYield { value, range: _ }) => {
Expr::Await(ast::ExprAwait {
value,
range: _,
node_index: _,
}) => visitor.visit_expr(value),
Expr::Yield(ast::ExprYield {
value,
range: _,
node_index: _,
}) => {
if let Some(expr) = value {
visitor.visit_expr(expr);
}
}
Expr::YieldFrom(ast::ExprYieldFrom { value, range: _ }) => visitor.visit_expr(value),
Expr::YieldFrom(ast::ExprYieldFrom {
value,
range: _,
node_index: _,
}) => visitor.visit_expr(value),
Expr::Compare(ast::ExprCompare {
left,
ops,
comparators,
range: _,
node_index: _,
}) => {
visitor.visit_expr(left);
for cmp_op in &mut **ops {
@ -460,6 +515,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
func,
arguments,
range: _,
node_index: _,
}) => {
visitor.visit_expr(func);
visitor.visit_arguments(arguments);
@ -514,6 +570,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
slice,
ctx,
range: _,
node_index: _,
}) => {
visitor.visit_expr(value);
visitor.visit_expr(slice);
@ -523,6 +580,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
value,
ctx,
range: _,
node_index: _,
}) => {
visitor.visit_expr(value);
visitor.visit_expr_context(ctx);
@ -534,6 +592,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
elts,
ctx,
range: _,
node_index: _,
}) => {
for expr in elts {
visitor.visit_expr(expr);
@ -544,6 +603,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
elts,
ctx,
range: _,
node_index: _,
parenthesized: _,
}) => {
for expr in elts {
@ -556,6 +616,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
upper,
step,
range: _,
node_index: _,
}) => {
if let Some(expr) = lower {
visitor.visit_expr(expr);
@ -670,6 +731,7 @@ pub fn walk_type_param<V: Transformer + ?Sized>(visitor: &V, type_param: &mut Ty
default,
name: _,
range: _,
node_index: _,
}) => {
if let Some(expr) = bound {
visitor.visit_expr(expr);
@ -682,6 +744,7 @@ pub fn walk_type_param<V: Transformer + ?Sized>(visitor: &V, type_param: &mut Ty
default,
name: _,
range: _,
node_index: _,
}) => {
if let Some(expr) = default {
visitor.visit_expr(expr);
@ -691,6 +754,7 @@ pub fn walk_type_param<V: Transformer + ?Sized>(visitor: &V, type_param: &mut Ty
default,
name: _,
range: _,
node_index: _,
}) => {
if let Some(expr) = default {
visitor.visit_expr(expr);