Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(traverse): add generate_uid_in_current_hoist_scope method #7423

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
19 changes: 17 additions & 2 deletions crates/oxc_traverse/scripts/lib/walk.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,26 @@ function generateWalkForStruct(type, types) {
// but we don't take that into account.
// Visitor should not do that though, so maybe it's OK.
// In final version, we should not make `scope_id` fields `Cell`s to prevent this.

enterScopeCode = `
let previous_scope_id = ctx.current_scope_id();
ctx.set_current_scope_id((*(${makeFieldCode(scopeIdField)})).get().unwrap());
let current_scope_id = (*(${makeFieldCode(scopeIdField)})).get().unwrap();
ctx.set_current_scope_id(current_scope_id);
`;
exitScopeCode = `ctx.set_current_scope_id(previous_scope_id);`;

exitScopeCode = 'ctx.set_current_scope_id(previous_scope_id);';

// const Var = Self::Top.bits() | Self::Function.bits() | Self::ClassStaticBlock.bits() | Self::TsModuleBlock.bits();
// `Function` type is a special case as its flags are set dynamically depending on the parent.
let isVarHoistingScope = type.name == 'Function' ||
['Top', 'Function', 'ClassStaticBlock', 'TsModuleBlock'].some(flag => scopeArgs.flags.includes(flag));
if (isVarHoistingScope) {
enterScopeCode += `
let previous_hoist_scope_id = ctx.current_hoist_scope_id();
ctx.set_current_hoist_scope_id(current_scope_id);
`;
exitScopeCode += 'ctx.set_current_hoist_scope_id(previous_hoist_scope_id);';
}
}

const fieldsCodes = visitedFields.map((field, index) => {
Expand Down
34 changes: 26 additions & 8 deletions crates/oxc_traverse/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use oxc_ast::{
ast::{Expression, IdentifierReference, Statement},
AstBuilder,
};
use oxc_semantic::{NodeId, ScopeTree, SymbolTable};
use oxc_span::{Atom, CompactStr, Span, SPAN};
use oxc_semantic::{ScopeTree, SymbolTable};
use oxc_span::{Atom, CompactStr, Span};
use oxc_syntax::{
reference::{ReferenceFlags, ReferenceId},
scope::{ScopeFlags, ScopeId},
Expand Down Expand Up @@ -186,6 +186,14 @@ impl<'a> TraverseCtx<'a> {
self.scoping.current_scope_id()
}

/// Get current var hoisting scope ID.
///
/// Shortcut for `ctx.scoping.current_hoist_scope_id`.
#[inline]
pub fn current_hoist_scope_id(&self) -> ScopeId {
self.scoping.current_hoist_scope_id()
}

/// Get current scope flags.
///
/// Shortcut for `ctx.scoping.current_scope_flags`.
Expand Down Expand Up @@ -356,12 +364,7 @@ impl<'a> TraverseCtx<'a> {
// Get name for UID
let name = self.generate_uid_name(name);
let name_atom = self.ast.atom(&name);

// Add binding to scope
let symbol_id =
self.symbols_mut().create_symbol(SPAN, name.clone(), flags, scope_id, NodeId::DUMMY);
self.scopes_mut().add_binding(scope_id, name, symbol_id);

let symbol_id = self.scoping.add_binding(name, scope_id, flags);
BoundIdentifier::new(name_atom, symbol_id)
}

Expand Down Expand Up @@ -421,6 +424,15 @@ impl<'a> TraverseCtx<'a> {
self.generate_uid_based_on_node(node, self.current_scope_id(), flags)
}

/// Generate UID in current hoist scope.
///
/// See also comments on [`TraverseScoping::generate_uid_name`] for important information
/// on how UIDs are generated. There are some potential "gotchas".
#[inline]
pub fn generate_uid_in_current_hoist_scope(&mut self, name: &str) -> BoundIdentifier<'a> {
self.generate_uid(name, self.current_hoist_scope_id(), SymbolFlags::FunctionScopedVariable)
}

/// Create a reference bound to a `SymbolId`.
///
/// This is a shortcut for `ctx.scoping.create_bound_reference`.
Expand Down Expand Up @@ -623,4 +635,10 @@ impl<'a> TraverseCtx<'a> {
pub(crate) fn set_current_scope_id(&mut self, scope_id: ScopeId) {
self.scoping.set_current_scope_id(scope_id);
}

/// Shortcut for `ctx.scoping.set_current_hoist_scope_id`, to make `walk_*` methods less verbose.
#[inline]
pub(crate) fn set_current_hoist_scope_id(&mut self, scope_id: ScopeId) {
self.scoping.set_current_hoist_scope_id(scope_id);
}
}
39 changes: 31 additions & 8 deletions crates/oxc_traverse/src/context/scoping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct TraverseScoping {
symbols: SymbolTable,
uid_names: Option<FxHashSet<CompactStr>>,
current_scope_id: ScopeId,
current_hoist_scope_id: ScopeId,
}

// Public methods
Expand All @@ -40,6 +41,12 @@ impl TraverseScoping {
self.current_scope_id
}

/// Get current var hoisting scope ID
#[inline]
pub(crate) fn current_hoist_scope_id(&self) -> ScopeId {
self.current_hoist_scope_id
}

/// Get current scope flags
#[inline]
pub fn current_scope_flags(&self) -> ScopeFlags {
Expand Down Expand Up @@ -164,6 +171,21 @@ impl TraverseScoping {
self.scopes.delete_scope(scope_id);
}

/// Add binding to [`ScopeTree`] and [`SymbolTable`].
#[inline]
pub(crate) fn add_binding(
&mut self,
name: CompactStr,
scope_id: ScopeId,
flags: SymbolFlags,
) -> SymbolId {
let symbol_id =
self.symbols.create_symbol(SPAN, name.clone(), flags, scope_id, NodeId::DUMMY);
self.scopes.add_binding(scope_id, name, symbol_id);

symbol_id
}

/// Generate binding.
///
/// Creates a symbol with the provided name and flags and adds it to the specified scope.
Expand All @@ -173,13 +195,7 @@ impl TraverseScoping {
scope_id: ScopeId,
flags: SymbolFlags,
) -> BoundIdentifier<'a> {
let owned_name = name.to_compact_str();

// Add binding to scope
let symbol_id =
self.symbols.create_symbol(SPAN, owned_name.clone(), flags, scope_id, NodeId::DUMMY);
self.scopes.add_binding(scope_id, owned_name, symbol_id);

let symbol_id = self.add_binding(name.to_compact_str(), scope_id, flags);
BoundIdentifier::new(name, symbol_id)
}

Expand Down Expand Up @@ -386,8 +402,9 @@ impl TraverseScoping {
scopes,
symbols,
uid_names: None,
// Dummy value. Immediately overwritten in `walk_program`.
// Dummy values. Both immediately overwritten in `walk_program`.
current_scope_id: ScopeId::new(0),
current_hoist_scope_id: ScopeId::new(0),
}
}

Expand All @@ -397,6 +414,12 @@ impl TraverseScoping {
self.current_scope_id = scope_id;
}

/// Set current hoist scope ID
#[inline]
pub(crate) fn set_current_hoist_scope_id(&mut self, scope_id: ScopeId) {
self.current_hoist_scope_id = scope_id;
}

/// Get `uid_names`.
///
/// Iterate through all symbols and unresolved references in AST and identify any var names
Expand Down
Loading
Loading