diff --git a/crates/oxc_ast/src/generated/visit.rs b/crates/oxc_ast/src/generated/visit.rs index 4fcfdde11dbb0..6a633fd00e763 100644 --- a/crates/oxc_ast/src/generated/visit.rs +++ b/crates/oxc_ast/src/generated/visit.rs @@ -16,8 +16,10 @@ clippy::match_wildcard_for_single_variants )] +use std::cell::Cell; + use oxc_allocator::Vec; -use oxc_syntax::scope::ScopeFlags; +use oxc_syntax::scope::{ScopeFlags, ScopeId}; use crate::{ast::*, ast_kind::AstKind}; @@ -28,7 +30,7 @@ pub trait Visit<'a>: Sized { fn enter_node(&mut self, kind: AstKind<'a>) {} fn leave_node(&mut self, kind: AstKind<'a>) {} - fn enter_scope(&mut self, flags: ScopeFlags) {} + fn enter_scope(&mut self, flags: ScopeFlags, scope_id: &Cell>) {} fn leave_scope(&mut self) {} #[inline] @@ -1350,13 +1352,17 @@ pub mod walk { #[inline] pub fn walk_program<'a, V: Visit<'a>>(visitor: &mut V, it: &Program<'a>) { - visitor.enter_scope({ - let mut flags = ScopeFlags::Top; - if it.source_type.is_strict() || it.directives.iter().any(Directive::is_use_strict) { - flags |= ScopeFlags::StrictMode; - } - flags - }); + visitor.enter_scope( + { + let mut flags = ScopeFlags::Top; + if it.source_type.is_strict() || it.directives.iter().any(Directive::is_use_strict) + { + flags |= ScopeFlags::StrictMode; + } + flags + }, + &it.scope_id, + ); let kind = AstKind::Program(visitor.alloc(it)); visitor.enter_node(kind); visitor.visit_directives(&it.directives); @@ -1433,7 +1439,7 @@ pub mod walk { #[inline] pub fn walk_block_statement<'a, V: Visit<'a>>(visitor: &mut V, it: &BlockStatement<'a>) { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); let kind = AstKind::BlockStatement(visitor.alloc(it)); visitor.enter_node(kind); visitor.visit_statements(&it.body); @@ -1699,13 +1705,16 @@ pub mod walk { visitor: &mut V, it: &ArrowFunctionExpression<'a>, ) { - visitor.enter_scope({ - let mut flags = ScopeFlags::Function | ScopeFlags::Arrow; - if it.body.has_use_strict_directive() { - flags |= ScopeFlags::StrictMode; - } - flags - }); + visitor.enter_scope( + { + let mut flags = ScopeFlags::Function | ScopeFlags::Arrow; + if it.body.has_use_strict_directive() { + flags |= ScopeFlags::StrictMode; + } + flags + }, + &it.scope_id, + ); let kind = AstKind::ArrowFunctionExpression(visitor.alloc(it)); visitor.enter_node(kind); visitor.visit_formal_parameters(&it.params); @@ -2064,7 +2073,7 @@ pub mod walk { #[inline] pub fn walk_ts_type_parameter<'a, V: Visit<'a>>(visitor: &mut V, it: &TSTypeParameter<'a>) { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); let kind = AstKind::TSTypeParameter(visitor.alloc(it)); visitor.enter_node(kind); visitor.visit_binding_identifier(&it.name); @@ -2916,7 +2925,7 @@ pub mod walk { let kind = AstKind::Class(visitor.alloc(it)); visitor.enter_node(kind); visitor.visit_decorators(&it.decorators); - visitor.enter_scope(ScopeFlags::StrictMode); + visitor.enter_scope(ScopeFlags::StrictMode, &it.scope_id); if let Some(id) = &it.id { visitor.visit_binding_identifier(id); } @@ -2972,7 +2981,7 @@ pub mod walk { #[inline] pub fn walk_static_block<'a, V: Visit<'a>>(visitor: &mut V, it: &StaticBlock<'a>) { - visitor.enter_scope(ScopeFlags::ClassStaticBlock); + visitor.enter_scope(ScopeFlags::ClassStaticBlock, &it.scope_id); let kind = AstKind::StaticBlock(visitor.alloc(it)); visitor.enter_node(kind); visitor.visit_statements(&it.body); @@ -3003,13 +3012,16 @@ pub mod walk { it: &Function<'a>, flags: Option, ) { - visitor.enter_scope({ - let mut flags = flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function; - if it.body.as_ref().is_some_and(|body| body.has_use_strict_directive()) { - flags |= ScopeFlags::StrictMode; - } - flags - }); + visitor.enter_scope( + { + let mut flags = flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function; + if it.body.as_ref().is_some_and(|body| body.has_use_strict_directive()) { + flags |= ScopeFlags::StrictMode; + } + flags + }, + &it.scope_id, + ); let kind = AstKind::Function(visitor.alloc(it)); visitor.enter_node(kind); if let Some(id) = &it.id { @@ -3473,7 +3485,7 @@ pub mod walk { pub fn walk_for_in_statement<'a, V: Visit<'a>>(visitor: &mut V, it: &ForInStatement<'a>) { let scope_events_cond = it.left.is_lexical_declaration(); if scope_events_cond { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); } let kind = AstKind::ForInStatement(visitor.alloc(it)); visitor.enter_node(kind); @@ -3544,7 +3556,7 @@ pub mod walk { pub fn walk_for_of_statement<'a, V: Visit<'a>>(visitor: &mut V, it: &ForOfStatement<'a>) { let scope_events_cond = it.left.is_lexical_declaration(); if scope_events_cond { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); } let kind = AstKind::ForOfStatement(visitor.alloc(it)); visitor.enter_node(kind); @@ -3562,7 +3574,7 @@ pub mod walk { let scope_events_cond = it.init.as_ref().is_some_and(ForStatementInit::is_lexical_declaration); if scope_events_cond { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); } let kind = AstKind::ForStatement(visitor.alloc(it)); visitor.enter_node(kind); @@ -3630,7 +3642,7 @@ pub mod walk { let kind = AstKind::SwitchStatement(visitor.alloc(it)); visitor.enter_node(kind); visitor.visit_expression(&it.discriminant); - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); visitor.visit_switch_cases(&it.cases); visitor.leave_node(kind); visitor.leave_scope(); @@ -3680,7 +3692,7 @@ pub mod walk { pub fn walk_catch_clause<'a, V: Visit<'a>>(visitor: &mut V, it: &CatchClause<'a>) { let scope_events_cond = it.param.is_some(); if scope_events_cond { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); } let kind = AstKind::CatchClause(visitor.alloc(it)); visitor.enter_node(kind); @@ -3704,7 +3716,7 @@ pub mod walk { #[inline] pub fn walk_finally_clause<'a, V: Visit<'a>>(visitor: &mut V, it: &BlockStatement<'a>) { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); let kind = AstKind::FinallyClause(visitor.alloc(it)); visitor.enter_node(kind); visitor.visit_statements(&it.body); @@ -3817,7 +3829,7 @@ pub mod walk { let kind = AstKind::TSEnumDeclaration(visitor.alloc(it)); visitor.enter_node(kind); visitor.visit_binding_identifier(&it.id); - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); visitor.visit_ts_enum_members(&it.members); visitor.leave_node(kind); visitor.leave_scope(); @@ -3859,13 +3871,16 @@ pub mod walk { let kind = AstKind::TSModuleDeclaration(visitor.alloc(it)); visitor.enter_node(kind); visitor.visit_ts_module_declaration_name(&it.id); - visitor.enter_scope({ - let mut flags = ScopeFlags::TsModuleBlock; - if it.body.as_ref().is_some_and(TSModuleDeclarationBody::is_strict) { - flags |= ScopeFlags::StrictMode; - } - flags - }); + visitor.enter_scope( + { + let mut flags = ScopeFlags::TsModuleBlock; + if it.body.as_ref().is_some_and(TSModuleDeclarationBody::is_strict) { + flags |= ScopeFlags::StrictMode; + } + flags + }, + &it.scope_id, + ); if let Some(body) = &it.body { visitor.visit_ts_module_declaration_body(body); } diff --git a/crates/oxc_ast/src/generated/visit_mut.rs b/crates/oxc_ast/src/generated/visit_mut.rs index 307c7962733d3..2103a64a556c7 100644 --- a/crates/oxc_ast/src/generated/visit_mut.rs +++ b/crates/oxc_ast/src/generated/visit_mut.rs @@ -16,19 +16,21 @@ clippy::match_wildcard_for_single_variants )] +use std::cell::Cell; + use oxc_allocator::Vec; -use oxc_syntax::scope::ScopeFlags; +use oxc_syntax::scope::{ScopeFlags, ScopeId}; use crate::{ast::*, ast_kind::AstType}; use walk_mut::*; -/// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in place. +/// Syntax tree traversal pub trait VisitMut<'a>: Sized { - fn enter_node(&mut self, ty: AstType) {} - fn leave_node(&mut self, ty: AstType) {} + fn enter_node(&mut self, kind: AstType) {} + fn leave_node(&mut self, kind: AstType) {} - fn enter_scope(&mut self, flags: ScopeFlags) {} + fn enter_scope(&mut self, flags: ScopeFlags, scope_id: &Cell>) {} fn leave_scope(&mut self) {} #[inline] @@ -1342,13 +1344,17 @@ pub mod walk_mut { #[inline] pub fn walk_program<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut Program<'a>) { - visitor.enter_scope({ - let mut flags = ScopeFlags::Top; - if it.source_type.is_strict() || it.directives.iter().any(Directive::is_use_strict) { - flags |= ScopeFlags::StrictMode; - } - flags - }); + visitor.enter_scope( + { + let mut flags = ScopeFlags::Top; + if it.source_type.is_strict() || it.directives.iter().any(Directive::is_use_strict) + { + flags |= ScopeFlags::StrictMode; + } + flags + }, + &it.scope_id, + ); let kind = AstType::Program; visitor.enter_node(kind); visitor.visit_directives(&mut it.directives); @@ -1425,7 +1431,7 @@ pub mod walk_mut { #[inline] pub fn walk_block_statement<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut BlockStatement<'a>) { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); let kind = AstType::BlockStatement; visitor.enter_node(kind); visitor.visit_statements(&mut it.body); @@ -1718,13 +1724,16 @@ pub mod walk_mut { visitor: &mut V, it: &mut ArrowFunctionExpression<'a>, ) { - visitor.enter_scope({ - let mut flags = ScopeFlags::Function | ScopeFlags::Arrow; - if it.body.has_use_strict_directive() { - flags |= ScopeFlags::StrictMode; - } - flags - }); + visitor.enter_scope( + { + let mut flags = ScopeFlags::Function | ScopeFlags::Arrow; + if it.body.has_use_strict_directive() { + flags |= ScopeFlags::StrictMode; + } + flags + }, + &it.scope_id, + ); let kind = AstType::ArrowFunctionExpression; visitor.enter_node(kind); visitor.visit_formal_parameters(&mut it.params); @@ -2125,7 +2134,7 @@ pub mod walk_mut { visitor: &mut V, it: &mut TSTypeParameter<'a>, ) { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); let kind = AstType::TSTypeParameter; visitor.enter_node(kind); visitor.visit_binding_identifier(&mut it.name); @@ -3040,7 +3049,7 @@ pub mod walk_mut { let kind = AstType::Class; visitor.enter_node(kind); visitor.visit_decorators(&mut it.decorators); - visitor.enter_scope(ScopeFlags::StrictMode); + visitor.enter_scope(ScopeFlags::StrictMode, &it.scope_id); if let Some(id) = &mut it.id { visitor.visit_binding_identifier(id); } @@ -3099,7 +3108,7 @@ pub mod walk_mut { #[inline] pub fn walk_static_block<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut StaticBlock<'a>) { - visitor.enter_scope(ScopeFlags::ClassStaticBlock); + visitor.enter_scope(ScopeFlags::ClassStaticBlock, &it.scope_id); let kind = AstType::StaticBlock; visitor.enter_node(kind); visitor.visit_statements(&mut it.body); @@ -3133,13 +3142,16 @@ pub mod walk_mut { it: &mut Function<'a>, flags: Option, ) { - visitor.enter_scope({ - let mut flags = flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function; - if it.body.as_ref().is_some_and(|body| body.has_use_strict_directive()) { - flags |= ScopeFlags::StrictMode; - } - flags - }); + visitor.enter_scope( + { + let mut flags = flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function; + if it.body.as_ref().is_some_and(|body| body.has_use_strict_directive()) { + flags |= ScopeFlags::StrictMode; + } + flags + }, + &it.scope_id, + ); let kind = AstType::Function; visitor.enter_node(kind); if let Some(id) = &mut it.id { @@ -3654,7 +3666,7 @@ pub mod walk_mut { ) { let scope_events_cond = it.left.is_lexical_declaration(); if scope_events_cond { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); } let kind = AstType::ForInStatement; visitor.enter_node(kind); @@ -3734,7 +3746,7 @@ pub mod walk_mut { ) { let scope_events_cond = it.left.is_lexical_declaration(); if scope_events_cond { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); } let kind = AstType::ForOfStatement; visitor.enter_node(kind); @@ -3752,7 +3764,7 @@ pub mod walk_mut { let scope_events_cond = it.init.as_ref().is_some_and(ForStatementInit::is_lexical_declaration); if scope_events_cond { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); } let kind = AstType::ForStatement; visitor.enter_node(kind); @@ -3832,7 +3844,7 @@ pub mod walk_mut { let kind = AstType::SwitchStatement; visitor.enter_node(kind); visitor.visit_expression(&mut it.discriminant); - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); visitor.visit_switch_cases(&mut it.cases); visitor.leave_node(kind); visitor.leave_scope(); @@ -3885,7 +3897,7 @@ pub mod walk_mut { pub fn walk_catch_clause<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut CatchClause<'a>) { let scope_events_cond = it.param.is_some(); if scope_events_cond { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); } let kind = AstType::CatchClause; visitor.enter_node(kind); @@ -3909,7 +3921,7 @@ pub mod walk_mut { #[inline] pub fn walk_finally_clause<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut BlockStatement<'a>) { - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); let kind = AstType::FinallyClause; visitor.enter_node(kind); visitor.visit_statements(&mut it.body); @@ -4028,7 +4040,7 @@ pub mod walk_mut { let kind = AstType::TSEnumDeclaration; visitor.enter_node(kind); visitor.visit_binding_identifier(&mut it.id); - visitor.enter_scope(ScopeFlags::empty()); + visitor.enter_scope(ScopeFlags::empty(), &it.scope_id); visitor.visit_ts_enum_members(&mut it.members); visitor.leave_node(kind); visitor.leave_scope(); @@ -4076,13 +4088,16 @@ pub mod walk_mut { let kind = AstType::TSModuleDeclaration; visitor.enter_node(kind); visitor.visit_ts_module_declaration_name(&mut it.id); - visitor.enter_scope({ - let mut flags = ScopeFlags::TsModuleBlock; - if it.body.as_ref().is_some_and(TSModuleDeclarationBody::is_strict) { - flags |= ScopeFlags::StrictMode; - } - flags - }); + visitor.enter_scope( + { + let mut flags = ScopeFlags::TsModuleBlock; + if it.body.as_ref().is_some_and(TSModuleDeclarationBody::is_strict) { + flags |= ScopeFlags::StrictMode; + } + flags + }, + &it.scope_id, + ); if let Some(body) = &mut it.body { visitor.visit_ts_module_declaration_body(body); } diff --git a/crates/oxc_isolated_declarations/src/declaration.rs b/crates/oxc_isolated_declarations/src/declaration.rs index 0c638bc3d7dcb..111f50cf6aa08 100644 --- a/crates/oxc_isolated_declarations/src/declaration.rs +++ b/crates/oxc_isolated_declarations/src/declaration.rs @@ -1,3 +1,5 @@ +use std::cell::Cell; + use oxc_allocator::Box; #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; @@ -135,7 +137,8 @@ impl<'a> IsolatedDeclarations<'a> { block: &Box<'a, TSModuleBlock<'a>>, ) -> Box<'a, TSModuleBlock<'a>> { // We need to enter a new scope for the module block, avoid add binding to the parent scope - self.scope.enter_scope(ScopeFlags::TsModuleBlock); + // TODO: doesn't have a scope_id! + self.scope.enter_scope(ScopeFlags::TsModuleBlock, &Cell::default()); let stmts = self.transform_statements_on_demand(&block.body); self.scope.leave_scope(); self.ast.alloc_ts_module_block(SPAN, self.ast.vec(), stmts) diff --git a/crates/oxc_isolated_declarations/src/return_type.rs b/crates/oxc_isolated_declarations/src/return_type.rs index 2dd2958bbd16a..cc11943a610c0 100644 --- a/crates/oxc_isolated_declarations/src/return_type.rs +++ b/crates/oxc_isolated_declarations/src/return_type.rs @@ -1,3 +1,5 @@ +use std::cell::Cell; + use oxc_ast::{ ast::{ ArrowFunctionExpression, BindingIdentifier, Expression, Function, FunctionBody, @@ -6,7 +8,7 @@ use oxc_ast::{ AstBuilder, Visit, }; use oxc_span::{Atom, GetSpan, SPAN}; -use oxc_syntax::scope::ScopeFlags; +use oxc_syntax::scope::{ScopeFlags, ScopeId}; use crate::{diagnostics::type_containing_private_name, IsolatedDeclarations}; @@ -114,7 +116,7 @@ impl<'a> FunctionReturnType<'a> { } impl<'a> Visit<'a> for FunctionReturnType<'a> { - fn enter_scope(&mut self, _flags: ScopeFlags) { + fn enter_scope(&mut self, _flags: ScopeFlags, _: &Cell>) { self.scope_depth += 1; } diff --git a/crates/oxc_isolated_declarations/src/scope.rs b/crates/oxc_isolated_declarations/src/scope.rs index 4f349baca926d..2b3936be51a37 100644 --- a/crates/oxc_isolated_declarations/src/scope.rs +++ b/crates/oxc_isolated_declarations/src/scope.rs @@ -1,3 +1,5 @@ +use std::cell::Cell; + use oxc_allocator::{Allocator, Vec}; #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; @@ -5,7 +7,7 @@ use oxc_ast::AstBuilder; #[allow(clippy::wildcard_imports)] use oxc_ast::{visit::walk::*, Visit}; use oxc_span::Atom; -use oxc_syntax::scope::ScopeFlags; +use oxc_syntax::scope::{ScopeFlags, ScopeId}; use rustc_hash::FxHashSet; /// Declaration scope. @@ -100,7 +102,7 @@ impl<'a> ScopeTree<'a> { } impl<'a> Visit<'a> for ScopeTree<'a> { - fn enter_scope(&mut self, flags: ScopeFlags) { + fn enter_scope(&mut self, flags: ScopeFlags, _: &Cell>) { let scope = Scope::new(flags); self.levels.push(scope); } @@ -216,7 +218,8 @@ impl<'a> Visit<'a> for ScopeTree<'a> { /// Because the type parameter is can be used in following nodes /// until the end of the function. So we leave the scope in the parent node (Function) fn visit_ts_type_parameter_declaration(&mut self, decl: &TSTypeParameterDeclaration<'a>) { - self.enter_scope(ScopeFlags::empty()); + // TODO: doesn't have a scope_id! + self.enter_scope(ScopeFlags::empty(), &Cell::default()); decl.params.iter().for_each(|param| self.visit_ts_type_parameter(param)); // exit scope in parent AST node } @@ -291,8 +294,9 @@ impl<'a> Visit<'a> for ScopeTree<'a> { /// ^^^^^^^^^^^^^^^^^^^^ /// We need to add both `T` and `K` to the scope fn visit_ts_mapped_type(&mut self, ty: &TSMappedType<'a>) { + // TODO: doesn't have a scope_id! + self.enter_scope(ScopeFlags::empty(), &Cell::default()); // copy from walk_ts_mapped_type - self.enter_scope(ScopeFlags::empty()); self.visit_ts_type_parameter(&ty.type_parameter); if let Some(name) = &ty.name_type { self.visit_ts_type(name); @@ -308,7 +312,8 @@ impl<'a> Visit<'a> for ScopeTree<'a> { /// `Item` is a type parameter /// We need to add `Item` to the scope fn visit_conditional_expression(&mut self, expr: &ConditionalExpression<'a>) { - self.enter_scope(ScopeFlags::empty()); + // TODO: doesn't have a scope_id! + self.enter_scope(ScopeFlags::empty(), &Cell::default()); walk_conditional_expression(self, expr); self.leave_scope(); } diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index b075ec945e720..710ec475a9249 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -1,6 +1,10 @@ //! Semantic Builder -use std::{cell::RefCell, path::PathBuf, sync::Arc}; +use std::{ + cell::{Cell, RefCell}, + path::PathBuf, + sync::Arc, +}; #[allow(clippy::wildcard_imports)] use oxc_ast::{ast::*, AstKind, Trivias, Visit}; @@ -417,7 +421,7 @@ impl<'a> SemanticBuilder<'a> { } impl<'a> Visit<'a> for SemanticBuilder<'a> { - fn enter_scope(&mut self, flags: ScopeFlags) { + fn enter_scope(&mut self, flags: ScopeFlags, _: &Cell>) { let parent_scope_id = if flags.contains(ScopeFlags::Top) { None } else { Some(self.current_scope_id) }; @@ -456,13 +460,16 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { fn visit_program(&mut self, program: &Program<'a>) { let kind = AstKind::Program(self.alloc(program)); - self.enter_scope({ - let mut flags = ScopeFlags::Top; - if program.is_strict() { - flags |= ScopeFlags::StrictMode; - } - flags - }); + self.enter_scope( + { + let mut flags = ScopeFlags::Top; + if program.is_strict() { + flags |= ScopeFlags::StrictMode; + } + flags + }, + &program.scope_id, + ); program.scope_id.set(Some(self.current_scope_id)); /* cfg */ @@ -491,7 +498,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { fn visit_block_statement(&mut self, stmt: &BlockStatement<'a>) { let kind = AstKind::BlockStatement(self.alloc(stmt)); - self.enter_scope(ScopeFlags::empty()); + self.enter_scope(ScopeFlags::empty(), &stmt.scope_id); stmt.scope_id.set(Some(self.current_scope_id)); self.enter_node(kind); @@ -759,7 +766,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { let is_lexical_declaration = stmt.init.as_ref().is_some_and(ForStatementInit::is_lexical_declaration); if is_lexical_declaration { - self.enter_scope(ScopeFlags::empty()); + self.enter_scope(ScopeFlags::empty(), &stmt.scope_id); stmt.scope_id.set(Some(self.current_scope_id)); } self.enter_node(kind); @@ -845,7 +852,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { let kind = AstKind::ForInStatement(self.alloc(stmt)); let is_lexical_declaration = stmt.left.is_lexical_declaration(); if is_lexical_declaration { - self.enter_scope(ScopeFlags::empty()); + self.enter_scope(ScopeFlags::empty(), &stmt.scope_id); stmt.scope_id.set(Some(self.current_scope_id)); } self.enter_node(kind); @@ -910,7 +917,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { let kind = AstKind::ForOfStatement(self.alloc(stmt)); let is_lexical_declaration = stmt.left.is_lexical_declaration(); if is_lexical_declaration { - self.enter_scope(ScopeFlags::empty()); + self.enter_scope(ScopeFlags::empty(), &stmt.scope_id); stmt.scope_id.set(Some(self.current_scope_id)); } self.enter_node(kind); @@ -1096,7 +1103,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { let kind = AstKind::SwitchStatement(self.alloc(stmt)); self.enter_node(kind); self.visit_expression(&stmt.discriminant); - self.enter_scope(ScopeFlags::empty()); + self.enter_scope(ScopeFlags::empty(), &stmt.scope_id); stmt.scope_id.set(Some(self.current_scope_id)); /* cfg */ @@ -1343,7 +1350,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { fn visit_catch_clause(&mut self, clause: &CatchClause<'a>) { let kind = AstKind::CatchClause(self.alloc(clause)); - self.enter_scope(ScopeFlags::empty()); + self.enter_scope(ScopeFlags::empty(), &clause.scope_id); clause.scope_id.set(Some(self.current_scope_id)); self.enter_node(kind); if let Some(param) = &clause.param { @@ -1356,7 +1363,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { fn visit_finally_clause(&mut self, clause: &BlockStatement<'a>) { let kind = AstKind::FinallyClause(self.alloc(clause)); - self.enter_scope(ScopeFlags::empty()); + self.enter_scope(ScopeFlags::empty(), &clause.scope_id); clause.scope_id.set(Some(self.current_scope_id)); self.enter_node(kind); self.visit_statements(&clause.body); @@ -1441,13 +1448,16 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { fn visit_function(&mut self, func: &Function<'a>, flags: Option) { let kind = AstKind::Function(self.alloc(func)); - self.enter_scope({ - let mut flags = flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function; - if func.is_strict() { - flags |= ScopeFlags::StrictMode; - } - flags - }); + self.enter_scope( + { + let mut flags = flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function; + if func.is_strict() { + flags |= ScopeFlags::StrictMode; + } + flags + }, + &func.scope_id, + ); func.scope_id.set(Some(self.current_scope_id)); /* cfg */ @@ -1516,7 +1526,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { if is_class_expr { // Class expressions create a temporary scope with the class name as its only variable // E.g., `let c = class A { foo() { console.log(A) } }` - self.enter_scope(ScopeFlags::empty()); + self.enter_scope(ScopeFlags::empty(), &class.scope_id); class.scope_id.set(Some(self.current_scope_id)); } @@ -1545,7 +1555,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { fn visit_static_block(&mut self, block: &StaticBlock<'a>) { let kind = AstKind::StaticBlock(self.alloc(block)); - self.enter_scope(ScopeFlags::ClassStaticBlock); + self.enter_scope(ScopeFlags::ClassStaticBlock, &block.scope_id); block.scope_id.set(Some(self.current_scope_id)); self.enter_node(kind); self.visit_statements(&block.body); @@ -1555,7 +1565,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { fn visit_arrow_function_expression(&mut self, expr: &ArrowFunctionExpression<'a>) { let kind = AstKind::ArrowFunctionExpression(self.alloc(expr)); - self.enter_scope(ScopeFlags::Function | ScopeFlags::Arrow); + self.enter_scope(ScopeFlags::Function | ScopeFlags::Arrow, &expr.scope_id); expr.scope_id.set(Some(self.current_scope_id)); /* cfg */ @@ -1605,7 +1615,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { let kind = AstKind::TSEnumDeclaration(self.alloc(decl)); self.enter_node(kind); self.visit_binding_identifier(&decl.id); - self.enter_scope(ScopeFlags::empty()); + self.enter_scope(ScopeFlags::empty(), &decl.scope_id); decl.scope_id.set(Some(self.current_scope_id)); for member in &decl.members { self.visit_ts_enum_member(member); @@ -1621,7 +1631,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { TSModuleDeclarationName::Identifier(ident) => self.visit_identifier_name(ident), TSModuleDeclarationName::StringLiteral(lit) => self.visit_string_literal(lit), } - self.enter_scope(ScopeFlags::TsModuleBlock); + self.enter_scope(ScopeFlags::TsModuleBlock, &decl.scope_id); decl.scope_id.set(Some(self.current_scope_id)); match &decl.body { Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => { @@ -1638,7 +1648,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { fn visit_ts_type_parameter(&mut self, ty: &TSTypeParameter<'a>) { let kind = AstKind::TSTypeParameter(self.alloc(ty)); - self.enter_scope(ScopeFlags::empty()); + self.enter_scope(ScopeFlags::empty(), &ty.scope_id); ty.scope_id.set(Some(self.current_scope_id)); self.enter_node(kind); if let Some(constraint) = &ty.constraint { diff --git a/tasks/ast_codegen/src/generators/visit.rs b/tasks/ast_codegen/src/generators/visit.rs index 9c29e6aa7031b..f73962dc45dde 100644 --- a/tasks/ast_codegen/src/generators/visit.rs +++ b/tasks/ast_codegen/src/generators/visit.rs @@ -37,7 +37,7 @@ impl Generator for VisitGenerator { } fn generate(&mut self, ctx: &CodegenCtx) -> GeneratorOutput { - GeneratorOutput::Stream(("visit", generate_visit(ctx))) + GeneratorOutput::Stream(("visit", generate_visit::(ctx))) } } @@ -47,11 +47,11 @@ impl Generator for VisitMutGenerator { } fn generate(&mut self, ctx: &CodegenCtx) -> GeneratorOutput { - GeneratorOutput::Stream(("visit_mut", generate_visit_mut(ctx))) + GeneratorOutput::Stream(("visit_mut", generate_visit::(ctx))) } } -static CLIPPY_ALLOW: &str = "\ +const CLIPPY_ALLOW: &str = "\ unused_variables,\ clippy::extra_unused_type_parameters,\ clippy::explicit_iter_loop,\ @@ -59,7 +59,7 @@ static CLIPPY_ALLOW: &str = "\ clippy::semicolon_if_nothing_returned,\ clippy::match_wildcard_for_single_variants"; -fn generate_visit(ctx: &CodegenCtx) -> TokenStream { +fn generate_visit(ctx: &CodegenCtx) -> TokenStream { let header = generated_header!(); // we evaluate it outside of quote to take advantage of expression evaluation // otherwise the `\n\` wouldn't work! @@ -71,41 +71,18 @@ fn generate_visit(ctx: &CodegenCtx) -> TokenStream { //! * [rustc visitor](https://github.com/rust-lang/rust/blob/master/compiler/rustc_ast/src/visit.rs)\n\ "}; - let (visits, walks) = VisitBuilder::new(ctx, false).build(); + let (visits, walks) = VisitBuilder::new(ctx, MUT).build(); let clippy_attr = insert!("#![allow({})]", CLIPPY_ALLOW); - quote! { - #header - #file_docs - #clippy_attr - - endl!(); - - use oxc_allocator::Vec; - use oxc_syntax::scope::ScopeFlags; - - endl!(); - - use crate::{ast::*, ast_kind::AstKind}; - - endl!(); - - use walk::*; - - endl!(); - - /// Syntax tree traversal - pub trait Visit<'a>: Sized { - fn enter_node(&mut self, kind: AstKind<'a>) {} - fn leave_node(&mut self, kind: AstKind<'a>) {} - - endl!(); - - fn enter_scope(&mut self, flags: ScopeFlags) {} - fn leave_scope(&mut self) {} - - endl!(); + let walk_mod = if MUT { quote!(walk_mut) } else { quote!(walk) }; + let trait_name = if MUT { quote!(VisitMut) } else { quote!(Visit) }; + let ast_kind_type = if MUT { quote!(AstType) } else { quote!(AstKind) }; + let ast_kind_life = if MUT { TokenStream::default() } else { quote!(<'a>) }; + let may_alloc = if MUT { + TokenStream::default() + } else { + quote! { #[inline] fn alloc(&self, t: &T) -> &'a T { insert!("// SAFETY:"); @@ -116,35 +93,8 @@ fn generate_visit(ctx: &CodegenCtx) -> TokenStream { std::mem::transmute(t) } } - - #(#visits)* } - - endl!(); - - pub mod walk { - use super::*; - - #(#walks)* - - } - } -} - -fn generate_visit_mut(ctx: &CodegenCtx) -> TokenStream { - let header = generated_header!(); - // we evaluate it outside of quote to take advantage of expression evaluation - // otherwise the `\n\` wouldn't work! - let file_docs = insert! {"\ - //! Visitor Pattern\n\ - //!\n\ - //! See:\n\ - //! * [visitor pattern](https://rust-unofficial.github.io/patterns/patterns/behavioural/visitor.html)\n\ - //! * [rustc visitor](https://github.com/rust-lang/rust/blob/master/compiler/rustc_ast/src/visit.rs)\n\ - "}; - - let (visits, walks) = VisitBuilder::new(ctx, true).build(); - let clippy_attr = insert!("#![allow({})]", CLIPPY_ALLOW); + }; quote! { #header @@ -153,37 +103,43 @@ fn generate_visit_mut(ctx: &CodegenCtx) -> TokenStream { endl!(); + use std::cell::Cell; + + endl!(); + use oxc_allocator::Vec; - use oxc_syntax::scope::ScopeFlags; + use oxc_syntax::scope::{ScopeFlags, ScopeId}; endl!(); - use crate::{ast::*, ast_kind::AstType}; + use crate::{ast::*, ast_kind::#ast_kind_type}; endl!(); - use walk_mut::*; + use #walk_mod::*; endl!(); - /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in place. - pub trait VisitMut<'a>: Sized { - fn enter_node(&mut self, ty: AstType) {} - fn leave_node(&mut self, ty: AstType) {} + /// Syntax tree traversal + pub trait #trait_name <'a>: Sized { + fn enter_node(&mut self, kind: #ast_kind_type #ast_kind_life) {} + fn leave_node(&mut self, kind: #ast_kind_type #ast_kind_life) {} endl!(); - fn enter_scope(&mut self, flags: ScopeFlags) {} + fn enter_scope(&mut self, flags: ScopeFlags, scope_id: &Cell>) {} fn leave_scope(&mut self) {} endl!(); + #may_alloc + #(#visits)* } endl!(); - pub mod walk_mut { + pub mod #walk_mod { use super::*; #(#walks)* @@ -533,7 +489,7 @@ impl<'a> VisitBuilder<'a> { let flags = scope_args .flags .map_or_else(|| quote!(ScopeFlags::empty()), |it| it.to_token_stream()); - let args = if let Some(strict_if) = scope_args.strict_if { + let flags = if let Some(strict_if) = scope_args.strict_if { let strict_if = strict_if.to_token_stream().replace_ident("self", &format_ident!("it")); quote! {{ @@ -547,7 +503,7 @@ impl<'a> VisitBuilder<'a> { flags }; let mut enter = cond.as_ref().into_token_stream(); - enter.extend(maybe_conditional(quote!(visitor.enter_scope(#args);))); + enter.extend(maybe_conditional(quote!(visitor.enter_scope(#flags, &it.scope_id);))); let leave = maybe_conditional(quote!(visitor.leave_scope();)); (enter, leave) },