Revert "perf(semantic): use Atom<'a> for References" (#3974)

Reverts oxc-project/oxc#3972

@DonIsaac As it turns out we can't have lifetimes on these structures because semantic data is exposed to downstream users to use freely, detached from the ast and allocator.
This commit is contained in:
Boshen 2024-06-29 15:55:04 +00:00
parent dbbb6fca56
commit 54c653ebd4
12 changed files with 88 additions and 88 deletions

View file

@ -66,9 +66,7 @@ impl Rule for NoGlobalAssign {
let reference = symbol_table.get_reference(reference_id);
if reference.is_write() {
let name = reference.name();
// Vec::contains isn't working here, but this has the same
// effect and time complexity.
if !self.excludes.iter().any(|e| e == name) && ctx.env_contains_var(name) {
if !self.excludes.contains(name) && ctx.env_contains_var(name) {
ctx.diagnostic(no_global_assign_diagnostic(name, reference.span()));
}
}

View file

@ -7,11 +7,11 @@ use oxc_span::CompactStr;
type Slot = usize;
#[derive(Debug)]
pub struct Mangler<'a> {
symbol_table: SymbolTable<'a>,
pub struct Mangler {
symbol_table: SymbolTable,
}
impl<'a> Mangler<'a> {
impl Mangler {
pub fn get_symbol_name(&self, symbol_id: SymbolId) -> &str {
self.symbol_table.get_name(symbol_id)
}

View file

@ -9,7 +9,7 @@ use oxc_cfg::{
IterationInstructionKind, ReturnInstructionKind,
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{Atom, CompactStr, SourceType, Span};
use oxc_span::{CompactStr, SourceType, Span};
use oxc_syntax::{module_record::ModuleRecord, operator::AssignmentOperator};
use crate::{
@ -63,8 +63,8 @@ pub struct SemanticBuilder<'a> {
// builders
pub nodes: AstNodes<'a>,
pub scope: ScopeTree<'a>,
pub symbols: SymbolTable<'a>,
pub scope: ScopeTree,
pub symbols: SymbolTable,
pub(crate) module_record: Arc<ModuleRecord>,
@ -315,7 +315,7 @@ impl<'a> SemanticBuilder<'a> {
pub fn declare_reference(
&mut self,
reference: Reference<'a>,
reference: Reference,
add_unresolved_reference: bool,
) -> ReferenceId {
let reference_name = reference.name().clone();
@ -327,7 +327,7 @@ impl<'a> SemanticBuilder<'a> {
reference_id,
);
} else {
self.resolve_reference_ids(reference_name, vec![reference_id]);
self.resolve_reference_ids(reference_name.clone(), vec![reference_id]);
}
reference_id
}
@ -361,7 +361,7 @@ impl<'a> SemanticBuilder<'a> {
}
}
fn resolve_reference_ids(&mut self, name: Atom<'a>, reference_ids: Vec<ReferenceId>) {
fn resolve_reference_ids(&mut self, name: CompactStr, reference_ids: Vec<ReferenceId>) {
let parent_scope_id =
self.scope.get_parent_id(self.current_scope_id).unwrap_or(self.current_scope_id);
@ -1884,9 +1884,9 @@ impl<'a> SemanticBuilder<'a> {
}
}
fn reference_identifier(&mut self, ident: &IdentifierReference<'a>) {
fn reference_identifier(&mut self, ident: &IdentifierReference) {
let flag = self.resolve_reference_usages();
let name = ident.name.clone();
let name = ident.name.to_compact_str();
let reference = Reference::new(ident.span, name, self.current_node_id, flag);
// `function foo({bar: identifier_reference}) {}`
// ^^^^^^^^^^^^^^^^^^^^ Parameter initializer must be resolved immediately
@ -1905,7 +1905,7 @@ impl<'a> SemanticBuilder<'a> {
}
}
fn reference_jsx_identifier(&mut self, ident: &JSXIdentifier<'a>) {
fn reference_jsx_identifier(&mut self, ident: &JSXIdentifier) {
match self.nodes.parent_kind(self.current_node_id) {
Some(AstKind::JSXElementName(_)) => {
if !ident.name.chars().next().is_some_and(char::is_uppercase) {
@ -1917,7 +1917,7 @@ impl<'a> SemanticBuilder<'a> {
}
let reference = Reference::new(
ident.span,
ident.name.clone(),
ident.name.to_compact_str(),
self.current_node_id,
ReferenceFlag::read(),
);

View file

@ -42,9 +42,9 @@ pub struct Semantic<'a> {
nodes: AstNodes<'a>,
scopes: ScopeTree<'a>,
scopes: ScopeTree,
symbols: SymbolTable<'a>,
symbols: SymbolTable,
classes: ClassTable,
@ -60,7 +60,7 @@ pub struct Semantic<'a> {
}
impl<'a> Semantic<'a> {
pub fn into_symbol_table_and_scope_tree(self) -> (SymbolTable<'a>, ScopeTree<'a>) {
pub fn into_symbol_table_and_scope_tree(self) -> (SymbolTable, ScopeTree) {
(self.symbols, self.scopes)
}
@ -84,7 +84,7 @@ impl<'a> Semantic<'a> {
&self.classes
}
pub fn scopes_mut(&mut self) -> &mut ScopeTree<'a> {
pub fn scopes_mut(&mut self) -> &mut ScopeTree {
&mut self.scopes
}

View file

@ -1,7 +1,7 @@
// Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]`
#![allow(non_snake_case)]
use oxc_span::{Atom, Span};
use oxc_span::{CompactStr, Span};
pub use oxc_syntax::reference::{ReferenceFlag, ReferenceId};
#[cfg(feature = "serialize")]
use serde::Serialize;
@ -13,10 +13,10 @@ use crate::{symbol::SymbolId, AstNodeId};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
pub struct Reference<'a> {
pub struct Reference {
span: Span,
/// The name of the identifier that was referred to
name: Atom<'a>,
name: CompactStr,
node_id: AstNodeId,
symbol_id: Option<SymbolId>,
/// Describes how this referenced is used by other AST nodes. References can
@ -24,14 +24,14 @@ pub struct Reference<'a> {
flag: ReferenceFlag,
}
impl<'a> Reference<'a> {
pub fn new(span: Span, name: Atom<'a>, node_id: AstNodeId, flag: ReferenceFlag) -> Self {
impl Reference {
pub fn new(span: Span, name: CompactStr, node_id: AstNodeId, flag: ReferenceFlag) -> Self {
Self { span, name, node_id, symbol_id: None, flag }
}
pub fn new_with_symbol_id(
span: Span,
name: Atom<'a>,
name: CompactStr,
node_id: AstNodeId,
symbol_id: SymbolId,
flag: ReferenceFlag,
@ -43,7 +43,7 @@ impl<'a> Reference<'a> {
self.span
}
pub fn name(&self) -> &Atom<'a> {
pub fn name(&self) -> &CompactStr {
&self.name
}

View file

@ -2,7 +2,7 @@ use std::hash::BuildHasherDefault;
use indexmap::IndexMap;
use oxc_index::IndexVec;
use oxc_span::{Atom, CompactStr};
use oxc_span::CompactStr;
pub use oxc_syntax::scope::{ScopeFlags, ScopeId};
use rustc_hash::{FxHashMap, FxHasher};
@ -11,13 +11,13 @@ use crate::{reference::ReferenceId, symbol::SymbolId, AstNodeId};
type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>;
type Bindings = FxIndexMap<CompactStr, SymbolId>;
type UnresolvedReferences<'a> = FxHashMap<Atom<'a>, Vec<ReferenceId>>;
type UnresolvedReferences = FxHashMap<CompactStr, Vec<ReferenceId>>;
/// Scope Tree
///
/// `SoA` (Struct of Arrays) for memory efficiency.
#[derive(Debug, Default)]
pub struct ScopeTree<'a> {
pub struct ScopeTree {
/// Maps a scope to the parent scope it belongs in
parent_ids: IndexVec<ScopeId, Option<ScopeId>>,
@ -27,10 +27,10 @@ pub struct ScopeTree<'a> {
node_ids: FxHashMap<ScopeId, AstNodeId>,
flags: IndexVec<ScopeId, ScopeFlags>,
bindings: IndexVec<ScopeId, Bindings>,
unresolved_references: IndexVec<ScopeId, UnresolvedReferences<'a>>,
unresolved_references: IndexVec<ScopeId, UnresolvedReferences>,
}
impl<'a> ScopeTree<'a> {
impl ScopeTree {
pub fn len(&self) -> usize {
self.parent_ids.len()
}
@ -141,7 +141,7 @@ impl<'a> ScopeTree<'a> {
self.get_binding(self.root_scope_id(), name)
}
pub fn add_root_unresolved_reference(&mut self, name: Atom<'a>, reference_id: ReferenceId) {
pub fn add_root_unresolved_reference(&mut self, name: CompactStr, reference_id: ReferenceId) {
self.add_unresolved_reference(self.root_scope_id(), name, reference_id);
}
@ -208,7 +208,7 @@ impl<'a> ScopeTree<'a> {
pub(crate) fn add_unresolved_reference(
&mut self,
scope_id: ScopeId,
name: Atom<'a>,
name: CompactStr,
reference_id: ReferenceId,
) {
self.unresolved_references[scope_id].entry(name).or_default().push(reference_id);
@ -217,7 +217,7 @@ impl<'a> ScopeTree<'a> {
pub(crate) fn extend_unresolved_reference(
&mut self,
scope_id: ScopeId,
name: Atom<'a>,
name: CompactStr,
reference_ids: Vec<ReferenceId>,
) {
self.unresolved_references[scope_id].entry(name).or_default().extend(reference_ids);
@ -226,7 +226,7 @@ impl<'a> ScopeTree<'a> {
pub(crate) fn unresolved_references_mut(
&mut self,
scope_id: ScopeId,
) -> &mut UnresolvedReferences<'a> {
) -> &mut UnresolvedReferences {
&mut self.unresolved_references[scope_id]
}
}

View file

@ -28,7 +28,7 @@ export type IndexVec<I, T> = Array<T>;
/// `SoA` (Struct of Arrays) for memory efficiency.
#[derive(Debug, Default)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify), serde(rename_all = "camelCase"))]
pub struct SymbolTable<'a> {
pub struct SymbolTable {
pub spans: IndexVec<SymbolId, Span>,
pub names: IndexVec<SymbolId, CompactStr>,
pub flags: IndexVec<SymbolId, SymbolFlags>,
@ -36,11 +36,11 @@ pub struct SymbolTable<'a> {
/// Pointer to the AST Node where this symbol is declared
pub declarations: IndexVec<SymbolId, AstNodeId>,
pub resolved_references: IndexVec<SymbolId, Vec<ReferenceId>>,
pub references: IndexVec<ReferenceId, Reference<'a>>,
pub references: IndexVec<ReferenceId, Reference>,
pub redeclare_variables: IndexVec<SymbolId, Vec<Span>>,
}
impl<'a> SymbolTable<'a> {
impl SymbolTable {
pub fn len(&self) -> usize {
self.spans.len()
}
@ -136,15 +136,15 @@ impl<'a> SymbolTable<'a> {
self.redeclare_variables[symbol_id].push(span);
}
pub fn create_reference(&mut self, reference: Reference<'a>) -> ReferenceId {
pub fn create_reference(&mut self, reference: Reference) -> ReferenceId {
self.references.push(reference)
}
pub fn get_reference(&self, reference_id: ReferenceId) -> &Reference<'a> {
pub fn get_reference(&self, reference_id: ReferenceId) -> &Reference {
&self.references[reference_id]
}
pub fn get_reference_mut(&mut self, reference_id: ReferenceId) -> &mut Reference<'a> {
pub fn get_reference_mut(&mut self, reference_id: ReferenceId) -> &mut Reference {
&mut self.references[reference_id]
}

View file

@ -110,24 +110,18 @@ impl<'a> SymbolTester<'a> {
self
}
// Note: can't use `Reference::is_read()` due to error warning about overly
// generic FnMut impl.
#[must_use]
pub fn has_number_of_reads(self, ref_count: usize) -> Self {
#[allow(clippy::redundant_closure_for_method_calls)]
self.has_number_of_references_where(ref_count, |r| r.is_read())
self.has_number_of_references_where(ref_count, Reference::is_read)
}
#[must_use]
pub fn has_number_of_writes(self, ref_count: usize) -> Self {
#[allow(clippy::redundant_closure_for_method_calls)]
self.has_number_of_references_where(ref_count, |r| r.is_write())
self.has_number_of_references_where(ref_count, Reference::is_write)
}
#[must_use]
pub fn has_number_of_references(self, ref_count: usize) -> Self {
#[allow(clippy::redundant_closure_for_method_calls)]
self.has_number_of_references_where(ref_count, |_| true)
}

View file

@ -986,7 +986,8 @@ fn get_read_identifier_reference<'a>(
name: Atom<'a>,
ctx: &mut TraverseCtx<'a>,
) -> IdentifierReference<'a> {
let reference_id = ctx.create_reference_in_current_scope(name.clone(), ReferenceFlag::Read);
let reference_id =
ctx.create_reference_in_current_scope(name.to_compact_str(), ReferenceFlag::Read);
IdentifierReference::new_read(span, name, Some(reference_id))
}

View file

@ -540,8 +540,11 @@ struct Assignment<'a> {
impl<'a> Assignment<'a> {
// Creates `this.name = name`
fn create_this_property_assignment(&self, ctx: &mut TraverseCtx<'a>) -> Statement<'a> {
let reference_id =
ctx.create_bound_reference(self.name.clone(), self.symbol_id, ReferenceFlag::Read);
let reference_id = ctx.create_bound_reference(
self.name.to_compact_str(),
self.symbol_id,
ReferenceFlag::Read,
);
let id = IdentifierReference::new_read(self.span, self.name.clone(), Some(reference_id));
ctx.ast.expression_statement(

View file

@ -4,7 +4,7 @@ use oxc_ast::{
AstBuilder,
};
use oxc_semantic::{ScopeTree, SymbolTable};
use oxc_span::{Atom, Span};
use oxc_span::{Atom, CompactStr, Span};
use oxc_syntax::{
reference::{ReferenceFlag, ReferenceId},
scope::{ScopeFlags, ScopeId},
@ -106,7 +106,7 @@ pub use scoping::TraverseScoping;
/// [`alloc`]: `TraverseCtx::alloc`
pub struct TraverseCtx<'a> {
pub ancestry: TraverseAncestry<'a>,
pub scoping: TraverseScoping<'a>,
pub scoping: TraverseScoping,
pub ast: AstBuilder<'a>,
}
@ -120,11 +120,7 @@ pub enum FinderRet<T> {
// Public methods
impl<'a> TraverseCtx<'a> {
/// Create new traversal context.
pub(crate) fn new(
scopes: ScopeTree<'a>,
symbols: SymbolTable<'a>,
allocator: &'a Allocator,
) -> Self {
pub(crate) fn new(scopes: ScopeTree, symbols: SymbolTable, allocator: &'a Allocator) -> Self {
let ancestry = TraverseAncestry::new();
let scoping = TraverseScoping::new(scopes, symbols);
let ast = AstBuilder::new(allocator);
@ -228,7 +224,7 @@ impl<'a> TraverseCtx<'a> {
///
/// Shortcut for `ctx.scoping.scopes`.
#[inline]
pub fn scopes(&self) -> &ScopeTree<'a> {
pub fn scopes(&self) -> &ScopeTree {
self.scoping.scopes()
}
@ -236,7 +232,7 @@ impl<'a> TraverseCtx<'a> {
///
/// Shortcut for `ctx.scoping.scopes_mut`.
#[inline]
pub fn scopes_mut(&mut self) -> &mut ScopeTree<'a> {
pub fn scopes_mut(&mut self) -> &mut ScopeTree {
self.scoping.scopes_mut()
}
@ -244,7 +240,7 @@ impl<'a> TraverseCtx<'a> {
///
/// Shortcut for `ctx.scoping.symbols`.
#[inline]
pub fn symbols(&self) -> &SymbolTable<'a> {
pub fn symbols(&self) -> &SymbolTable {
self.scoping.symbols()
}
@ -252,7 +248,7 @@ impl<'a> TraverseCtx<'a> {
///
/// Shortcut for `ctx.scoping.symbols_mut`.
#[inline]
pub fn symbols_mut(&mut self) -> &mut SymbolTable<'a> {
pub fn symbols_mut(&mut self) -> &mut SymbolTable {
self.scoping.symbols_mut()
}
@ -355,7 +351,7 @@ impl<'a> TraverseCtx<'a> {
/// This is a shortcut for `ctx.scoping.create_bound_reference`.
pub fn create_bound_reference(
&mut self,
name: Atom<'a>,
name: CompactStr,
symbol_id: SymbolId,
flag: ReferenceFlag,
) -> ReferenceId {
@ -378,7 +374,11 @@ impl<'a> TraverseCtx<'a> {
/// Create an unbound reference.
///
/// This is a shortcut for `ctx.scoping.create_unbound_reference`.
pub fn create_unbound_reference(&mut self, name: Atom<'a>, flag: ReferenceFlag) -> ReferenceId {
pub fn create_unbound_reference(
&mut self,
name: CompactStr,
flag: ReferenceFlag,
) -> ReferenceId {
self.scoping.create_unbound_reference(name, flag)
}
@ -402,7 +402,7 @@ impl<'a> TraverseCtx<'a> {
/// This is a shortcut for `ctx.scoping.create_reference`.
pub fn create_reference(
&mut self,
name: Atom<'a>,
name: CompactStr,
symbol_id: Option<SymbolId>,
flag: ReferenceFlag,
) -> ReferenceId {
@ -430,7 +430,7 @@ impl<'a> TraverseCtx<'a> {
/// This is a shortcut for `ctx.scoping.create_reference_in_current_scope`.
pub fn create_reference_in_current_scope(
&mut self,
name: Atom<'a>,
name: CompactStr,
flag: ReferenceFlag,
) -> ReferenceId {
self.scoping.create_reference_in_current_scope(name, flag)

View file

@ -22,14 +22,14 @@ use super::FinderRet;
///
/// `current_scope_id` is the ID of current scope during traversal.
/// `walk_*` functions update this field when entering/exiting a scope.
pub struct TraverseScoping<'a> {
scopes: ScopeTree<'a>,
symbols: SymbolTable<'a>,
pub struct TraverseScoping {
scopes: ScopeTree,
symbols: SymbolTable,
current_scope_id: ScopeId,
}
// Public methods
impl<'a> TraverseScoping<'a> {
impl TraverseScoping {
/// Get current scope ID
#[inline]
pub fn current_scope_id(&self) -> ScopeId {
@ -44,25 +44,25 @@ impl<'a> TraverseScoping<'a> {
/// Get scopes tree
#[inline]
pub fn scopes(&self) -> &ScopeTree<'a> {
pub fn scopes(&self) -> &ScopeTree {
&self.scopes
}
/// Get mutable scopes tree
#[inline]
pub fn scopes_mut(&mut self) -> &mut ScopeTree<'a> {
pub fn scopes_mut(&mut self) -> &mut ScopeTree {
&mut self.scopes
}
/// Get symbols table
#[inline]
pub fn symbols(&self) -> &SymbolTable<'a> {
pub fn symbols(&self) -> &SymbolTable {
&self.symbols
}
/// Get mutable symbols table
#[inline]
pub fn symbols_mut(&mut self) -> &mut SymbolTable<'a> {
pub fn symbols_mut(&mut self) -> &mut SymbolTable {
&mut self.symbols
}
@ -259,7 +259,7 @@ impl<'a> TraverseScoping<'a> {
/// Create a reference bound to a `SymbolId`
pub fn create_bound_reference(
&mut self,
name: Atom<'a>,
name: CompactStr,
symbol_id: SymbolId,
flag: ReferenceFlag,
) -> ReferenceId {
@ -271,14 +271,14 @@ impl<'a> TraverseScoping<'a> {
}
/// Create an `IdentifierReference` bound to a `SymbolId`
pub fn create_bound_reference_id(
pub fn create_bound_reference_id<'a>(
&mut self,
span: Span,
name: Atom<'a>,
symbol_id: SymbolId,
flag: ReferenceFlag,
) -> IdentifierReference<'a> {
let reference_id = self.create_bound_reference(name.clone(), symbol_id, flag);
let reference_id = self.create_bound_reference(name.to_compact_str(), symbol_id, flag);
IdentifierReference {
span,
name,
@ -288,7 +288,11 @@ impl<'a> TraverseScoping<'a> {
}
/// Create an unbound reference
pub fn create_unbound_reference(&mut self, name: Atom<'a>, flag: ReferenceFlag) -> ReferenceId {
pub fn create_unbound_reference(
&mut self,
name: CompactStr,
flag: ReferenceFlag,
) -> ReferenceId {
let reference = Reference::new(SPAN, name.clone(), AstNodeId::dummy(), flag);
let reference_id = self.symbols.create_reference(reference);
self.scopes.add_root_unresolved_reference(name, reference_id);
@ -296,13 +300,13 @@ impl<'a> TraverseScoping<'a> {
}
/// Create an unbound `IdentifierReference`
pub fn create_unbound_reference_id(
pub fn create_unbound_reference_id<'a>(
&mut self,
span: Span,
name: Atom<'a>,
flag: ReferenceFlag,
) -> IdentifierReference<'a> {
let reference_id = self.create_unbound_reference(name.clone(), flag);
let reference_id = self.create_unbound_reference(name.to_compact_str(), flag);
IdentifierReference {
span,
name,
@ -317,12 +321,12 @@ impl<'a> TraverseScoping<'a> {
/// or `TraverseCtx::create_unbound_reference`.
pub fn create_reference(
&mut self,
name: Atom<'a>,
name: CompactStr,
symbol_id: Option<SymbolId>,
flag: ReferenceFlag,
) -> ReferenceId {
if let Some(symbol_id) = symbol_id {
self.create_bound_reference(name.clone(), symbol_id, flag)
self.create_bound_reference(name, symbol_id, flag)
} else {
self.create_unbound_reference(name, flag)
}
@ -332,7 +336,7 @@ impl<'a> TraverseScoping<'a> {
///
/// If you know if there's a `SymbolId` or not, prefer `TraverseCtx::create_bound_reference_id`
/// or `TraverseCtx::create_unbound_reference_id`.
pub fn create_reference_id(
pub fn create_reference_id<'a>(
&mut self,
span: Span,
name: Atom<'a>,
@ -349,7 +353,7 @@ impl<'a> TraverseScoping<'a> {
/// Create reference in current scope, looking up binding for `name`
pub fn create_reference_in_current_scope(
&mut self,
name: Atom<'a>,
name: CompactStr,
flag: ReferenceFlag,
) -> ReferenceId {
let symbol_id = self.scopes.find_binding(self.current_scope_id, name.as_str());
@ -358,9 +362,9 @@ impl<'a> TraverseScoping<'a> {
}
// Methods used internally within crate
impl<'a> TraverseScoping<'a> {
impl TraverseScoping {
/// Create new `TraverseScoping`
pub(super) fn new(scopes: ScopeTree<'a>, symbols: SymbolTable<'a>) -> Self {
pub(super) fn new(scopes: ScopeTree, symbols: SymbolTable) -> Self {
Self {
scopes,
symbols,