Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 11 additions & 18 deletions crates/oxc_semantic/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ impl<'a> SemanticBuilder<'a> {
/// # Panics
pub fn build(mut self, program: &Program<'a>) -> SemanticBuilderReturn<'a> {
if self.source_type.is_typescript_definition() {
let scope_id = self.scope.add_scope(None, ScopeFlags::Top);
let scope_id = self.scope.add_scope(None, AstNodeId::dummy(), ScopeFlags::Top);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not self.current_node_id here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. I guess we could do that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please feel free to submit a PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't build semantic for .d.ts file now. So we haven't current_node_id. We may need to build semantic for d.ts in the future. Rolldown needs this to bundle types to one entry point.

program.scope_id.set(Some(scope_id));
} else {
self.visit_program(program);
Expand Down Expand Up @@ -449,7 +449,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
flags = self.scope.get_new_scope_flags(flags, parent_scope_id);
}

self.current_scope_id = self.scope.add_scope(parent_scope_id, flags);
self.current_scope_id = self.scope.add_scope(parent_scope_id, self.current_node_id, flags);
scope_id.set(Some(self.current_scope_id));

if let Some(parent_scope_id) = parent_scope_id {
Expand All @@ -471,8 +471,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
if !flags.is_top() {
self.bind_function_or_class_expression();
}

self.add_current_node_id_to_current_scope();
}

fn leave_scope(&mut self) {
Expand Down Expand Up @@ -501,6 +499,15 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {

fn visit_program(&mut self, program: &Program<'a>) {
let kind = AstKind::Program(self.alloc(program));
/* cfg */
let error_harness = control_flow!(|self, cfg| {
let error_harness = cfg.attach_error_harness(ErrorEdgeKind::Implicit);
let _program_basic_block = cfg.new_basic_block_normal();
error_harness
});
/* cfg - must be above directives as directives are in cfg */

self.enter_node(kind);
self.enter_scope(
{
let mut flags = ScopeFlags::Top;
Expand All @@ -512,16 +519,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
&program.scope_id,
);

/* cfg */
let error_harness = control_flow!(|self, cfg| {
let error_harness = cfg.attach_error_harness(ErrorEdgeKind::Implicit);
let _program_basic_block = cfg.new_basic_block_normal();
error_harness
});
/* cfg - must be above directives as directives are in cfg */

self.enter_node(kind);

for directive in &program.directives {
self.visit_directive(directive);
}
Expand Down Expand Up @@ -1778,10 +1775,6 @@ impl<'a> SemanticBuilder<'a> {
}
}

fn add_current_node_id_to_current_scope(&mut self) {
self.scope.set_node_id(self.current_scope_id, self.current_node_id);
}

fn make_all_namespaces_valuelike(&mut self) {
for symbol_id in &self.namespace_stack {
// Ambient modules cannot be value modules
Expand Down
13 changes: 7 additions & 6 deletions crates/oxc_semantic/src/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,17 @@ impl ScopeTree {
&mut self.bindings[scope_id]
}

pub fn add_scope(&mut self, parent_id: Option<ScopeId>, flags: ScopeFlags) -> ScopeId {
pub fn add_scope(
&mut self,
parent_id: Option<ScopeId>,
node_id: AstNodeId,
flags: ScopeFlags,
) -> ScopeId {
let scope_id = self.parent_ids.push(parent_id);
_ = self.child_ids.push(vec![]);
_ = self.flags.push(flags);
_ = self.bindings.push(Bindings::default());
_ = self.node_ids.push(AstNodeId::dummy());
_ = self.node_ids.push(node_id);

// Set this scope as child of parent scope.
if let Some(parent_id) = parent_id {
Expand All @@ -194,10 +199,6 @@ impl ScopeTree {
scope_id
}

pub(crate) fn set_node_id(&mut self, scope_id: ScopeId, node_id: AstNodeId) {
self.node_ids[scope_id] = node_id;
}

pub fn add_binding(&mut self, scope_id: ScopeId, name: CompactStr, symbol_id: SymbolId) {
self.bindings[scope_id].insert(name, symbol_id);
}
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_traverse/src/context/scoping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ impl TraverseScoping {
/// `flags` provided are amended to inherit from parent scope's flags.
pub fn create_scope_child_of_current(&mut self, flags: ScopeFlags) -> ScopeId {
let flags = self.scopes.get_new_scope_flags(flags, self.current_scope_id);
self.scopes.add_scope(Some(self.current_scope_id), flags)
self.scopes.add_scope(Some(self.current_scope_id), AstNodeId::dummy(), flags)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will result in multiple scopes having the same node ID (0), is this a bug in the logic?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can answer this one. Traverse is a mutating visitor. For this reason, it does not use all of Semantic. It can't use AstNodes because that contains AstKinds which contain references to all actual AST nodes. Holding that would be a violation of Rust's aliasing rules, because visitor functions also get passed &mut references to AST nodes => would result in having a live & and &mut reference to same AST node simultaneously.

So... long story short... Traverse uses only an incomplete subset of Semantic and that doesn't include AstNodes, so it uses dummy AstNodeIds.

This is part of what I hope to look at when I review Semantic. We need some way to merge the 2 paradigms.

}

/// Insert a scope into scope tree below a statement.
Expand Down