Find AstNode/node declaration by ReferenceId from Traverse #11107
-
Hello guys 👋, Is there currently a way to access AstNodes from TraverseCtx/Traverse, or otherwise retrieve the node declaration corresponding to a I'm trying to implement a transformation based on semantic information. For example, I want to find all call expressions where the callee is a specific function (imported from a specific module) and modify its arguments based on type arguments. Is there a way to achieve this? One idea I had was to store AstNodes in my visitor struct, but due to Rust's borrowing rules, that doesn't seem viable. The compiler complains about borrowing the Program mutably while it is still borrowed immutably via Semantic. Maybe there's a Rust solution I'm missing? 🤔 Here’s a simplified version of the code: struct MyVisitor<'a> {
nodes: AstNodes<'a>,
}
impl<'a> Traverse<'a> for MyVisitor<'a> {
fn enter_call_expression(&mut self, node: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) {
match &node.callee {
Expression::Identifier(identifier) => {
if identifier.name == "getType" {
if let Some(reference_id) = identifier.reference_id.get() {
let symbol_table = ctx.scoping.scoping();
let symbol_id = symbol_table.get_reference(reference_id).symbol_id();
// TODO: Get AstNode
// semantic.nodes().get_node(symbol_table.symbol_declaration(symbol_id))
}
}
}
_ => {}
}
}
}
pub fn test(
file_path: String,
source_code: String,
transformer_context: TransformerContext,
) {
let source_code = Arc::new(source_code);
let path = Path::new(&file_path);
let source_type = SourceType::from_path(path).unwrap();
let allocator = Allocator::default();
let parser_ret = Parser::new(&allocator, &source_code, source_type).parse();
let mut program = parser_ret.program;
let semantic = SemanticBuilder::new().with_check_syntax_error(true).build(&program);
let (scoping, nodes) = semantic.semantic.into_scoping_and_nodes();
let mut my_visitor = MyVisitor {
nodes
};
traverse_mut(&mut my_visitor, &allocator, &mut program, scoping);
// ^^^^
// Rust error here: cannot borrow `program` as mutable because it is also borrowed as immutable
} The key issue is that Semantic::build borrows program immutably, and that borrow lives on in nodes, making it impossible to later mutate program during traversal. Any guidance or workarounds would be greatly appreciated! It would be nice to have AstNodes in TraverseCtx. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 5 replies
-
I'm afraid it's not possible to have
So I'm sorry to say, this isn't going to be possible. Out of interest, can I ask what is it that you're trying to do? What's the purpose for which you need to get hold of the symbol's declaration node? |
Beta Was this translation helpful? Give feedback.
I'm afraid it's not possible to have
AstNodes
in traverse. The 2 are fundamentally incompatible, becauseAstNodes
contains&
references to all AST nodes, and traverse provides&mut
references to nodes (so you can mutate the AST).Traverse
pulls some tricks to allow reading back up the tree by carefully ensuring you can never obtain a&
and&mut
ref to same node at the same time. But it's not possible to generalize to an ability to get hold of any node at any time, the wayAstNodes
allows. This would be a violation of Rust's aliasing rules.So I'm sorry to say, this isn't going to be possible.
Out of interest, can I ask what is it that you're trying to do? What's the purpose for which you …