diff --git a/crates/oxc_ast_lower/src/lib.rs b/crates/oxc_ast_lower/src/lib.rs index 709d6efaf..56de46b0d 100644 --- a/crates/oxc_ast_lower/src/lib.rs +++ b/crates/oxc_ast_lower/src/lib.rs @@ -315,12 +315,12 @@ impl<'a> AstLower<'a> { ast::Expression::Super(expr) => self.lower_super(expr), ast::Expression::JSXElement(elem) => { // TODO: implement JSX - let ident = self.hir.identifier_reference(elem.span, "undefined".into()); + let ident = self.hir.identifier_reference(elem.span, "undefined".into(), None); self.hir.identifier_reference_expression(ident) } ast::Expression::JSXFragment(elem) => { // TODO: implement JSX - let ident = self.hir.identifier_reference(elem.span, "undefined".into()); + let ident = self.hir.identifier_reference(elem.span, "undefined".into(), None); self.hir.identifier_reference_expression(ident) } @@ -698,7 +698,7 @@ impl<'a> AstLower<'a> { } expr => { // return undefined because this is invalid syntax - let ident = self.hir.identifier_reference(expr.span(), "undefined".into()); + let ident = self.hir.identifier_reference(expr.span(), "undefined".into(), None); self.hir.assignment_target_identifier(ident) } } @@ -915,7 +915,8 @@ impl<'a> AstLower<'a> { &mut self, ident: &ast::IdentifierReference, ) -> hir::IdentifierReference { - self.hir.identifier_reference(ident.span, ident.name.clone()) + let symbol_id = self.semantic.enter_identifier_reference(&ident.name); + self.hir.identifier_reference(ident.span, ident.name.clone(), symbol_id) } fn lower_private_identifier( diff --git a/crates/oxc_hir/src/hir.rs b/crates/oxc_hir/src/hir.rs index 984d9bf2c..8cd8d20fc 100644 --- a/crates/oxc_hir/src/hir.rs +++ b/crates/oxc_hir/src/hir.rs @@ -370,6 +370,8 @@ pub struct IdentifierReference { #[cfg_attr(feature = "serde", serde(flatten))] pub span: Span, pub name: Atom, + #[cfg_attr(feature = "serde", serde(skip))] + pub symbol_id: Option, } /// Binding Identifier @@ -379,6 +381,7 @@ pub struct BindingIdentifier { #[cfg_attr(feature = "serde", serde(flatten))] pub span: Span, pub name: Atom, + #[cfg_attr(feature = "serde", serde(skip))] pub symbol_id: SymbolId, } diff --git a/crates/oxc_hir/src/hir_builder.rs b/crates/oxc_hir/src/hir_builder.rs index 782bb08cd..bf1b9623b 100644 --- a/crates/oxc_hir/src/hir_builder.rs +++ b/crates/oxc_hir/src/hir_builder.rs @@ -174,8 +174,13 @@ impl<'a> HirBuilder<'a> { IdentifierName { span, name } } - pub fn identifier_reference(&mut self, span: Span, name: Atom) -> IdentifierReference { - IdentifierReference { span, name } + pub fn identifier_reference( + &mut self, + span: Span, + name: Atom, + symbol_id: Option, + ) -> IdentifierReference { + IdentifierReference { span, name, symbol_id } } pub fn binding_identifier( diff --git a/crates/oxc_minifier/src/printer/gen.rs b/crates/oxc_minifier/src/printer/gen.rs index ece672e2c..f556af674 100644 --- a/crates/oxc_minifier/src/printer/gen.rs +++ b/crates/oxc_minifier/src/printer/gen.rs @@ -772,7 +772,11 @@ impl<'a> Gen for Expression<'a> { impl Gen for IdentifierReference { fn gen(&self, p: &mut Printer) { - p.print_str(self.name.as_bytes()); + if let Some(symbol_id) = self.symbol_id { + p.print_symbol(symbol_id, &self.name); + } else { + p.print_str(self.name.as_bytes()); + } } } diff --git a/crates/oxc_semantic2/src/builder.rs b/crates/oxc_semantic2/src/builder.rs index 82c82650f..03d398eac 100644 --- a/crates/oxc_semantic2/src/builder.rs +++ b/crates/oxc_semantic2/src/builder.rs @@ -62,11 +62,11 @@ impl SemanticBuilder { /// Declares a `Symbol` for the node, adds it to symbol table, and binds it to the scope. /// - /// includes: the SymbolFlags that node has in addition to its declaration type (eg: export, ambient, etc.) + /// includes: the `SymbolFlags` that node has in addition to its declaration type (eg: export, ambient, etc.) /// excludes: the flags which node cannot be declared alongside in a symbol table. Used to report forbidden declarations. /// /// Reports errors for conflicting identifier names. - pub fn declare_symbol( + fn declare_symbol( &mut self, span: Span, name: &Atom, @@ -77,6 +77,12 @@ impl SemanticBuilder { self.scope_tree.get_scope_mut(self.current_scope_id).add_symbol(name.clone(), symbol_id); symbol_id } + + fn resolve_reference(&mut self, name: &Atom) -> Option { + self.scope_tree + .ancestors(self.current_scope_id) + .find_map(|scope_id| self.scope_tree.get_scope(scope_id).get_binding(name)) + } } impl SemanticBuilder { @@ -85,4 +91,8 @@ impl SemanticBuilder { let excludes = SymbolFlags::FunctionScopedVariableExcludes; self.declare_symbol(span, name, includes, excludes) } + + pub fn enter_identifier_reference(&mut self, name: &Atom) -> Option { + self.resolve_reference(name) + } } diff --git a/crates/oxc_semantic2/src/scope.rs b/crates/oxc_semantic2/src/scope.rs index 3a1fced6a..2170ad2ba 100644 --- a/crates/oxc_semantic2/src/scope.rs +++ b/crates/oxc_semantic2/src/scope.rs @@ -77,6 +77,10 @@ impl Scope { self.flags.intersects(ScopeFlags::Function) } + pub fn get_binding(&self, name: &Atom) -> Option { + self.bindings.get(name).copied() + } + pub fn bindings_entry(&mut self, name: Atom) -> Entry { self.bindings.entry(name) } @@ -94,14 +98,14 @@ impl ScopeTree { Self(IndexVec::new()) } - pub fn get_scope(&self, scope_id: ScopeId) -> &Scope { - &self.0[scope_id] - } - pub fn root_scope(&self) -> &Scope { self.get_scope(ScopeId::new(0)) } + pub fn get_scope(&self, scope_id: ScopeId) -> &Scope { + &self.0[scope_id] + } + pub fn get_scope_mut(&mut self, scope_id: ScopeId) -> &mut Scope { &mut self.0[scope_id] } @@ -109,4 +113,8 @@ impl ScopeTree { pub fn add_scope(&mut self, scope: Scope) -> ScopeId { self.0.push(scope) } + + pub fn ancestors(&self, scope_id: ScopeId) -> impl Iterator + '_ { + std::iter::successors(Some(scope_id), |scope_id| self.get_scope(*scope_id).parent_id()) + } }