diff --git a/crates/oxc_ast/src/ast/js.rs b/crates/oxc_ast/src/ast/js.rs index 679190744119a..99c48b5fb5956 100644 --- a/crates/oxc_ast/src/ast/js.rs +++ b/crates/oxc_ast/src/ast/js.rs @@ -1193,6 +1193,7 @@ pub struct ParenthesizedExpression<'a> { #[derive(Debug, Hash)] #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[cfg_attr(feature = "serialize", serde(untagged))] +#[repr(u8)] pub enum Statement<'a> { // Statements BlockStatement(Box<'a, BlockStatement<'a>>), @@ -1215,7 +1216,19 @@ pub enum Statement<'a> { WithStatement(Box<'a, WithStatement<'a>>), ModuleDeclaration(Box<'a, ModuleDeclaration<'a>>), - Declaration(Declaration<'a>), + + // SAFETY: Discriminants and types here MUST match discriminants for same variants in `Declaration`, + // to allow transmuting between the two types + VariableDeclaration(Box<'a, VariableDeclaration<'a>>) = 32, + FunctionDeclaration(Box<'a, Function<'a>>) = 33, + ClassDeclaration(Box<'a, Class<'a>>) = 34, + UsingDeclaration(Box<'a, UsingDeclaration<'a>>) = 35, + + TSTypeAliasDeclaration(Box<'a, TSTypeAliasDeclaration<'a>>) = 36, + TSInterfaceDeclaration(Box<'a, TSInterfaceDeclaration<'a>>) = 37, + TSEnumDeclaration(Box<'a, TSEnumDeclaration<'a>>) = 38, + TSModuleDeclaration(Box<'a, TSModuleDeclaration<'a>>) = 39, + TSImportEqualsDeclaration(Box<'a, TSImportEqualsDeclaration<'a>>) = 40, } impl<'a> Statement<'a> { @@ -1229,6 +1242,46 @@ impl<'a> Statement<'a> { | Statement::WhileStatement(_) ) } + + #[inline] + pub fn is_declaration(&self) -> bool { + matches!( + self, + Self::VariableDeclaration(_) + | Self::FunctionDeclaration(_) + | Self::ClassDeclaration(_) + | Self::UsingDeclaration(_) + | Self::TSTypeAliasDeclaration(_) + | Self::TSInterfaceDeclaration(_) + | Self::TSEnumDeclaration(_) + | Self::TSModuleDeclaration(_) + | Self::TSImportEqualsDeclaration(_) + ) + } + + #[inline] + pub fn as_declaration(&self) -> Option<&Declaration<'a>> { + if self.is_declaration() { + #[allow(clippy::ptr_as_ptr)] + // SAFETY: Transmute is safe because discriminants + types are identical between + // `Statement` and `Declaration` for declaration variants + Some(unsafe { &*(self as *const _ as *const Declaration<'_>) }) + } else { + None + } + } + + #[inline] + pub fn as_declaration_mut(&mut self) -> Option<&mut Declaration<'a>> { + if self.is_declaration() { + #[allow(clippy::ptr_as_ptr)] + // SAFETY: Transmute is safe because discriminants + types are identical between + // `Statement` and `Declaration` for declaration variants + Some(unsafe { &mut *(self as *mut _ as *mut Declaration<'_>) }) + } else { + None + } + } } /// Directive Prologue @@ -1269,17 +1322,20 @@ pub struct BlockStatement<'a> { #[derive(Debug, Hash)] #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[cfg_attr(feature = "serialize", serde(untagged))] +#[repr(u8)] pub enum Declaration<'a> { - VariableDeclaration(Box<'a, VariableDeclaration<'a>>), - FunctionDeclaration(Box<'a, Function<'a>>), - ClassDeclaration(Box<'a, Class<'a>>), - UsingDeclaration(Box<'a, UsingDeclaration<'a>>), + // SAFETY: Discriminants and types here MUST match discriminants for same variants in `Statement`, + // to allow transmuting between the two types + VariableDeclaration(Box<'a, VariableDeclaration<'a>>) = 32, + FunctionDeclaration(Box<'a, Function<'a>>) = 33, + ClassDeclaration(Box<'a, Class<'a>>) = 34, + UsingDeclaration(Box<'a, UsingDeclaration<'a>>) = 35, - TSTypeAliasDeclaration(Box<'a, TSTypeAliasDeclaration<'a>>), - TSInterfaceDeclaration(Box<'a, TSInterfaceDeclaration<'a>>), - TSEnumDeclaration(Box<'a, TSEnumDeclaration<'a>>), - TSModuleDeclaration(Box<'a, TSModuleDeclaration<'a>>), - TSImportEqualsDeclaration(Box<'a, TSImportEqualsDeclaration<'a>>), + TSTypeAliasDeclaration(Box<'a, TSTypeAliasDeclaration<'a>>) = 36, + TSInterfaceDeclaration(Box<'a, TSInterfaceDeclaration<'a>>) = 37, + TSEnumDeclaration(Box<'a, TSEnumDeclaration<'a>>) = 38, + TSModuleDeclaration(Box<'a, TSModuleDeclaration<'a>>) = 39, + TSImportEqualsDeclaration(Box<'a, TSImportEqualsDeclaration<'a>>) = 40, } impl<'a> Declaration<'a> { @@ -1305,6 +1361,26 @@ impl<'a> Declaration<'a> { } } +impl<'a> From> for Statement<'a> { + fn from(val: Declaration<'a>) -> Self { + // Compiler should implement this as zero-cost transmute as discriminants + // for `Declaration` and `Statement` are aligned + match val { + Declaration::VariableDeclaration(decl) => Statement::VariableDeclaration(decl), + Declaration::FunctionDeclaration(decl) => Statement::FunctionDeclaration(decl), + Declaration::ClassDeclaration(decl) => Statement::ClassDeclaration(decl), + Declaration::UsingDeclaration(decl) => Statement::UsingDeclaration(decl), + Declaration::TSTypeAliasDeclaration(decl) => Statement::TSTypeAliasDeclaration(decl), + Declaration::TSInterfaceDeclaration(decl) => Statement::TSInterfaceDeclaration(decl), + Declaration::TSEnumDeclaration(decl) => Statement::TSEnumDeclaration(decl), + Declaration::TSModuleDeclaration(decl) => Statement::TSModuleDeclaration(decl), + Declaration::TSImportEqualsDeclaration(decl) => { + Statement::TSImportEqualsDeclaration(decl) + } + } + } +} + /// Variable Declaration #[derive(Debug, Hash)] #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] diff --git a/crates/oxc_ast/src/ast_builder.rs b/crates/oxc_ast/src/ast_builder.rs index 8950a34fb3290..704b346c3968d 100644 --- a/crates/oxc_ast/src/ast_builder.rs +++ b/crates/oxc_ast/src/ast_builder.rs @@ -261,11 +261,7 @@ impl<'a> AstBuilder<'a> { declarations: Vec<'a, VariableDeclarator<'a>>, is_await: bool, ) -> Statement<'a> { - Statement::Declaration(Declaration::UsingDeclaration(self.alloc(UsingDeclaration { - span, - is_await, - declarations, - }))) + Statement::UsingDeclaration(self.alloc(UsingDeclaration { span, is_await, declarations })) } pub fn do_while_statement( @@ -806,7 +802,7 @@ impl<'a> AstBuilder<'a> { /* ---------- Functions ---------- */ pub fn function_declaration(&self, func: Box<'a, Function<'a>>) -> Statement<'a> { - Statement::Declaration(Declaration::FunctionDeclaration(func)) + Statement::FunctionDeclaration(func) } pub fn formal_parameters( @@ -916,7 +912,7 @@ impl<'a> AstBuilder<'a> { } pub fn class_declaration(&self, class: Box<'a, Class<'a>>) -> Statement<'a> { - Statement::Declaration(Declaration::ClassDeclaration(class)) + Statement::ClassDeclaration(class) } pub fn static_block(&self, span: Span, body: Vec<'a, Statement<'a>>) -> ClassElement<'a> { diff --git a/crates/oxc_ast/src/span.rs b/crates/oxc_ast/src/span.rs index 99187f9a14d76..a537ae7aa547c 100644 --- a/crates/oxc_ast/src/span.rs +++ b/crates/oxc_ast/src/span.rs @@ -24,7 +24,15 @@ impl<'a> GetSpan for Statement<'a> { Self::WhileStatement(stmt) => stmt.span, Self::WithStatement(stmt) => stmt.span, Self::ModuleDeclaration(decl) => decl.span(), - Self::Declaration(decl) => decl.span(), + Self::VariableDeclaration(decl) => decl.span, + Self::FunctionDeclaration(decl) => decl.span, + Self::ClassDeclaration(decl) => decl.span, + Self::UsingDeclaration(decl) => decl.span, + Self::TSTypeAliasDeclaration(decl) => decl.span, + Self::TSInterfaceDeclaration(decl) => decl.span, + Self::TSEnumDeclaration(decl) => decl.span, + Self::TSModuleDeclaration(decl) => decl.span, + Self::TSImportEqualsDeclaration(decl) => decl.span, } } } diff --git a/crates/oxc_ast/src/visit/visit.rs b/crates/oxc_ast/src/visit/visit.rs index 467d94e81aa86..f1ba8ae0b5e4b 100644 --- a/crates/oxc_ast/src/visit/visit.rs +++ b/crates/oxc_ast/src/visit/visit.rs @@ -846,6 +846,7 @@ pub mod walk { } } + #[allow(clippy::missing_panics_doc)] pub fn walk_statement<'a, V: Visit<'a>>(visitor: &mut V, stmt: &Statement<'a>) { match stmt { Statement::BlockStatement(stmt) => visitor.visit_block_statement(stmt), @@ -868,7 +869,19 @@ pub mod walk { Statement::WithStatement(stmt) => visitor.visit_with_statement(stmt), Statement::ModuleDeclaration(decl) => visitor.visit_module_declaration(decl), - Statement::Declaration(decl) => visitor.visit_declaration(decl), + + Statement::VariableDeclaration(_) + | Statement::FunctionDeclaration(_) + | Statement::ClassDeclaration(_) + | Statement::UsingDeclaration(_) + | Statement::TSTypeAliasDeclaration(_) + | Statement::TSInterfaceDeclaration(_) + | Statement::TSEnumDeclaration(_) + | Statement::TSModuleDeclaration(_) + | Statement::TSImportEqualsDeclaration(_) => { + let decl = stmt.as_declaration().unwrap(); + visitor.visit_declaration(decl); + } } } diff --git a/crates/oxc_ast/src/visit/visit_mut.rs b/crates/oxc_ast/src/visit/visit_mut.rs index 3bcad9c8fb6be..6b80bab8e9344 100644 --- a/crates/oxc_ast/src/visit/visit_mut.rs +++ b/crates/oxc_ast/src/visit/visit_mut.rs @@ -855,6 +855,7 @@ pub mod walk_mut { } } + #[allow(clippy::missing_panics_doc)] pub fn walk_statement_mut<'a, V: VisitMut<'a>>(visitor: &mut V, stmt: &mut Statement<'a>) { match stmt { Statement::BlockStatement(stmt) => visitor.visit_block_statement(stmt), @@ -877,7 +878,19 @@ pub mod walk_mut { Statement::WithStatement(stmt) => visitor.visit_with_statement(stmt), Statement::ModuleDeclaration(decl) => visitor.visit_module_declaration(decl), - Statement::Declaration(decl) => visitor.visit_declaration(decl), + + Statement::VariableDeclaration(_) + | Statement::FunctionDeclaration(_) + | Statement::ClassDeclaration(_) + | Statement::UsingDeclaration(_) + | Statement::TSTypeAliasDeclaration(_) + | Statement::TSInterfaceDeclaration(_) + | Statement::TSEnumDeclaration(_) + | Statement::TSModuleDeclaration(_) + | Statement::TSImportEqualsDeclaration(_) => { + let decl = stmt.as_declaration_mut().unwrap(); + visitor.visit_declaration(decl); + } } } diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index fa790017b6d64..a7af91214ee3e 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -88,7 +88,6 @@ impl<'a, const MINIFY: bool> Gen for Statement<'a> { Self::BreakStatement(stmt) => stmt.gen(p, ctx), Self::ContinueStatement(stmt) => stmt.gen(p, ctx), Self::DebuggerStatement(stmt) => stmt.gen(p, ctx), - Self::Declaration(decl) => decl.gen(p, ctx), Self::DoWhileStatement(stmt) => stmt.gen(p, ctx), Self::EmptyStatement(stmt) => stmt.gen(p, ctx), Self::ExpressionStatement(stmt) => stmt.gen(p, ctx), @@ -104,6 +103,19 @@ impl<'a, const MINIFY: bool> Gen for Statement<'a> { Self::TryStatement(stmt) => stmt.gen(p, ctx), Self::WhileStatement(stmt) => stmt.gen(p, ctx), Self::WithStatement(stmt) => stmt.gen(p, ctx), + + Self::VariableDeclaration(_) + | Self::FunctionDeclaration(_) + | Self::ClassDeclaration(_) + | Self::UsingDeclaration(_) + | Self::TSTypeAliasDeclaration(_) + | Self::TSInterfaceDeclaration(_) + | Self::TSEnumDeclaration(_) + | Self::TSModuleDeclaration(_) + | Self::TSImportEqualsDeclaration(_) => { + let decl = self.as_declaration().unwrap(); + decl.gen(p, ctx); + } } } } diff --git a/crates/oxc_codegen/src/lib.rs b/crates/oxc_codegen/src/lib.rs index 2db18baead09b..8eb8c6403e924 100644 --- a/crates/oxc_codegen/src/lib.rs +++ b/crates/oxc_codegen/src/lib.rs @@ -390,7 +390,7 @@ impl Codegen { } } for stmt in statements { - if let Statement::Declaration(decl) = stmt { + if let Some(decl) = stmt.as_declaration() { if decl.is_typescript_syntax() && !self.options.enable_typescript && !matches!(decl, Declaration::TSEnumDeclaration(_)) diff --git a/crates/oxc_linter/src/rules/eslint/array_callback_return/return_checker.rs b/crates/oxc_linter/src/rules/eslint/array_callback_return/return_checker.rs index fb3ec528c5007..925a8c208210c 100644 --- a/crates/oxc_linter/src/rules/eslint/array_callback_return/return_checker.rs +++ b/crates/oxc_linter/src/rules/eslint/array_callback_return/return_checker.rs @@ -245,7 +245,7 @@ pub fn check_block_statement(block: &BlockStatement) -> StatementReturnStatus { #[cfg(test)] mod tests { use oxc_allocator::Allocator; - use oxc_ast::ast::{Declaration, Program}; + use oxc_ast::ast::Program; use oxc_parser::Parser; use oxc_span::SourceType; @@ -262,9 +262,7 @@ mod tests { let program = ret.program; let Program { body, .. } = program; let stmt = body.first().unwrap(); - let Statement::Declaration(Declaration::FunctionDeclaration(func)) = stmt else { - unreachable!() - }; + let Statement::FunctionDeclaration(func) = stmt else { unreachable!() }; let first_statement = &func.body.as_ref().unwrap().statements[0]; diff --git a/crates/oxc_linter/src/rules/eslint/no_case_declarations.rs b/crates/oxc_linter/src/rules/eslint/no_case_declarations.rs index 8623e0be408f0..1a74a8044ac37 100644 --- a/crates/oxc_linter/src/rules/eslint/no_case_declarations.rs +++ b/crates/oxc_linter/src/rules/eslint/no_case_declarations.rs @@ -1,5 +1,5 @@ use oxc_ast::{ - ast::{Declaration, Statement, VariableDeclarationKind}, + ast::{Statement, VariableDeclarationKind}, AstKind, }; use oxc_diagnostics::{ @@ -54,31 +54,29 @@ impl Rule for NoCaseDeclarations { let consequent = &switch_case.consequent; for stmt in consequent { - if let Statement::Declaration(dcl) = stmt { - match dcl { - Declaration::FunctionDeclaration(d) => { - let start = d.span.start; - let end = start + 8; - ctx.diagnostic(NoCaseDeclarationsDiagnostic(Span::new(start, end))); - } - Declaration::ClassDeclaration(d) => { - let start = d.span.start; - let end = start + 5; - ctx.diagnostic(NoCaseDeclarationsDiagnostic(Span::new(start, end))); - } - Declaration::VariableDeclaration(var) if var.kind.is_lexical() => { - let start = var.span.start; - let end = match var.kind { - VariableDeclarationKind::Var => unreachable!(), - VariableDeclarationKind::Const => 5, - VariableDeclarationKind::Let => 3, - }; - let end = start + end; - ctx.diagnostic(NoCaseDeclarationsDiagnostic(Span::new(start, end))); - } - _ => {} + match stmt { + Statement::FunctionDeclaration(d) => { + let start = d.span.start; + let end = start + 8; + ctx.diagnostic(NoCaseDeclarationsDiagnostic(Span::new(start, end))); } - }; + Statement::ClassDeclaration(d) => { + let start = d.span.start; + let end = start + 5; + ctx.diagnostic(NoCaseDeclarationsDiagnostic(Span::new(start, end))); + } + Statement::VariableDeclaration(var) if var.kind.is_lexical() => { + let start = var.span.start; + let end = match var.kind { + VariableDeclarationKind::Var => unreachable!(), + VariableDeclarationKind::Const => 5, + VariableDeclarationKind::Let => 3, + }; + let end = start + end; + ctx.diagnostic(NoCaseDeclarationsDiagnostic(Span::new(start, end))); + } + _ => {} + } } } } diff --git a/crates/oxc_linter/src/rules/typescript/adjacent_overload_signatures.rs b/crates/oxc_linter/src/rules/typescript/adjacent_overload_signatures.rs index dbffaf0ccffdf..7202dae5913a3 100644 --- a/crates/oxc_linter/src/rules/typescript/adjacent_overload_signatures.rs +++ b/crates/oxc_linter/src/rules/typescript/adjacent_overload_signatures.rs @@ -241,8 +241,10 @@ impl GetMethod for Statement<'_> { fn get_method(&self) -> Option { match self { Statement::ModuleDeclaration(decl) => decl.get_method(), - Statement::Declaration(decl) => decl.get_method(), - _ => None, + _ => match self.as_declaration() { + Some(decl) => decl.get_method(), + None => None, + }, } } } diff --git a/crates/oxc_linter/src/rules/typescript/triple_slash_reference.rs b/crates/oxc_linter/src/rules/typescript/triple_slash_reference.rs index b61212234656a..19fbfa98e1f71 100644 --- a/crates/oxc_linter/src/rules/typescript/triple_slash_reference.rs +++ b/crates/oxc_linter/src/rules/typescript/triple_slash_reference.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use oxc_ast::{ - ast::{Declaration, ModuleDeclaration, Statement, TSModuleReference}, + ast::{ModuleDeclaration, Statement, TSModuleReference}, AstKind, }; use oxc_diagnostics::{ @@ -133,21 +133,18 @@ impl Rule for TripleSlashReference { if !refs_for_import.is_empty() { for stmt in &program.body { match stmt { - Statement::Declaration(Declaration::TSImportEqualsDeclaration(decl)) => { - match *decl.module_reference { - TSModuleReference::ExternalModuleReference(ref mod_ref) => { - if let Some(v) = - refs_for_import.get(mod_ref.expression.value.as_str()) - { - ctx.diagnostic(TripleSlashReferenceDiagnostic( - mod_ref.expression.value.to_string(), - *v, - )); - } + Statement::TSImportEqualsDeclaration(decl) => match *decl.module_reference { + TSModuleReference::ExternalModuleReference(ref mod_ref) => { + if let Some(v) = refs_for_import.get(mod_ref.expression.value.as_str()) + { + ctx.diagnostic(TripleSlashReferenceDiagnostic( + mod_ref.expression.value.to_string(), + *v, + )); } - TSModuleReference::TypeName(_) => {} } - } + TSModuleReference::TypeName(_) => {} + }, Statement::ModuleDeclaration(st) => { if let ModuleDeclaration::ImportDeclaration(ref decl) = **st { if let Some(v) = refs_for_import.get(decl.source.value.as_str()) { diff --git a/crates/oxc_minifier/src/compressor/mod.rs b/crates/oxc_minifier/src/compressor/mod.rs index f5faeafe88a0d..07cc899d17470 100644 --- a/crates/oxc_minifier/src/compressor/mod.rs +++ b/crates/oxc_minifier/src/compressor/mod.rs @@ -63,7 +63,7 @@ impl<'a> Compressor<'a> { if let Statement::BlockStatement(block) = stmt { // Avoid compressing `if (x) { var x = 1 }` to `if (x) var x = 1` due to different // semantics according to AnnexB, which lead to different semantics. - if block.body.len() == 1 && !matches!(&block.body[0], Statement::Declaration(_)) { + if block.body.len() == 1 && !block.body[0].is_declaration() { *stmt = block.body.remove(0); self.compress_block(stmt); } @@ -103,8 +103,8 @@ impl<'a> Compressor<'a> { for window in stmts.windows(2) { let [prev, cur] = window else { unreachable!() }; if let ( - Statement::Declaration(Declaration::VariableDeclaration(cur_decl)), - Statement::Declaration(Declaration::VariableDeclaration(prev_decl)), + Statement::VariableDeclaration(cur_decl), + Statement::VariableDeclaration(prev_decl), ) = (cur, prev) { if cur_decl.kind == prev_decl.kind { @@ -130,12 +130,8 @@ impl<'a> Compressor<'a> { let mut new_stmts = self.ast.new_vec_with_capacity(stmts.len() - capacity); for (i, stmt) in stmts.drain(..).enumerate() { if i > 0 && ranges.iter().any(|range| range.contains(&(i - 1)) && range.contains(&i)) { - if let Statement::Declaration(Declaration::VariableDeclaration(prev_decl)) = - new_stmts.last_mut().unwrap() - { - if let Statement::Declaration(Declaration::VariableDeclaration(mut cur_decl)) = - stmt - { + if let Statement::VariableDeclaration(prev_decl) = new_stmts.last_mut().unwrap() { + if let Statement::VariableDeclaration(mut cur_decl) = stmt { prev_decl.declarations.append(&mut cur_decl.declarations); } } diff --git a/crates/oxc_module_lexer/src/lib.rs b/crates/oxc_module_lexer/src/lib.rs index 699007ac9bc62..1abd30db39537 100644 --- a/crates/oxc_module_lexer/src/lib.rs +++ b/crates/oxc_module_lexer/src/lib.rs @@ -115,7 +115,8 @@ impl<'a> ModuleLexer<'a> { impl<'a> Visit<'a> for ModuleLexer<'a> { fn visit_statement(&mut self, stmt: &Statement<'a>) { if self.facade - && !matches!(stmt, Statement::ModuleDeclaration(..) | Statement::Declaration(..)) + && !matches!(stmt, Statement::ModuleDeclaration(..)) + && !stmt.is_declaration() { self.facade = false; } diff --git a/crates/oxc_parser/src/js/declaration.rs b/crates/oxc_parser/src/js/declaration.rs index ccf0ecc12c6c4..e2ffb5f60786d 100644 --- a/crates/oxc_parser/src/js/declaration.rs +++ b/crates/oxc_parser/src/js/declaration.rs @@ -51,7 +51,7 @@ impl<'a> ParserImpl<'a> { self.asi()?; - Ok(Statement::Declaration(Declaration::UsingDeclaration(self.ast.alloc(using_decl)))) + Ok(Statement::UsingDeclaration(self.ast.alloc(using_decl))) } pub(crate) fn parse_variable_declaration( diff --git a/crates/oxc_parser/src/js/module.rs b/crates/oxc_parser/src/js/module.rs index 8ddc492a323f2..8865e1f2e973b 100644 --- a/crates/oxc_parser/src/js/module.rs +++ b/crates/oxc_parser/src/js/module.rs @@ -43,7 +43,7 @@ impl<'a> ParserImpl<'a> { && self.nth_at(2, Kind::Eq))) { let decl = self.parse_ts_import_equals_declaration(span)?; - return Ok(Statement::Declaration(decl)); + return Ok(Statement::from(decl)); } // `import type ...` diff --git a/crates/oxc_parser/src/js/statement.rs b/crates/oxc_parser/src/js/statement.rs index 27b9f459e1cae..0a2f3d46e79e6 100644 --- a/crates/oxc_parser/src/js/statement.rs +++ b/crates/oxc_parser/src/js/statement.rs @@ -191,7 +191,7 @@ impl<'a> ParserImpl<'a> { self.error(diagnostics::LexicalDeclarationSingleStatement(decl.span)); } - Ok(Statement::Declaration(Declaration::VariableDeclaration(decl))) + Ok(Statement::VariableDeclaration(decl)) } /// Section 14.4 Empty Statement diff --git a/crates/oxc_parser/src/ts/statement.rs b/crates/oxc_parser/src/ts/statement.rs index 1b665545c8034..b34b068c05859 100644 --- a/crates/oxc_parser/src/ts/statement.rs +++ b/crates/oxc_parser/src/ts/statement.rs @@ -265,7 +265,7 @@ impl<'a> ParserImpl<'a> { self.ctx = self.ctx.union_ambient_if(flags.declare()).and_await(flags.r#async()); let result = self.parse_declaration(start_span, modifiers); self.ctx = reserved_ctx; - result.map(Statement::Declaration) + result.map(Statement::from) } pub(crate) fn parse_declaration( diff --git a/crates/oxc_prettier/src/format/mod.rs b/crates/oxc_prettier/src/format/mod.rs index dd5426eb1dcb1..0a54ac4e303d2 100644 --- a/crates/oxc_prettier/src/format/mod.rs +++ b/crates/oxc_prettier/src/format/mod.rs @@ -123,7 +123,15 @@ impl<'a> Format<'a> for Statement<'a> { Self::TryStatement(stmt) => stmt.format(p), Self::WhileStatement(stmt) => stmt.format(p), Self::WithStatement(stmt) => stmt.format(p), - Self::Declaration(decl) => decl.format(p), + Self::VariableDeclaration(decl) => decl.format(p), + Self::FunctionDeclaration(decl) => decl.format(p), + Self::ClassDeclaration(decl) => decl.format(p), + Self::UsingDeclaration(decl) => decl.format(p), + Self::TSTypeAliasDeclaration(decl) => decl.format(p), + Self::TSInterfaceDeclaration(decl) => decl.format(p), + Self::TSEnumDeclaration(decl) => decl.format(p), + Self::TSModuleDeclaration(decl) => decl.format(p), + Self::TSImportEqualsDeclaration(decl) => decl.format(p), } } } diff --git a/crates/oxc_semantic/src/checker/javascript.rs b/crates/oxc_semantic/src/checker/javascript.rs index b14b1a9c6545c..dea762d67e4ac 100644 --- a/crates/oxc_semantic/src/checker/javascript.rs +++ b/crates/oxc_semantic/src/checker/javascript.rs @@ -579,7 +579,7 @@ fn check_function_declaration<'a>( struct FunctionDeclarationNonStrict(#[label] Span); // Function declaration not allowed in statement position - if let Statement::Declaration(Declaration::FunctionDeclaration(decl)) = stmt { + if let Statement::FunctionDeclaration(decl) = stmt { if ctx.strict_mode() { ctx.error(FunctionDeclarationStrict(decl.span)); } else if !is_if_stmt_or_labeled_stmt { diff --git a/crates/oxc_transformer/src/es2015/arrow_functions.rs b/crates/oxc_transformer/src/es2015/arrow_functions.rs index 173e1c43ee0df..efa8b9adbc4a0 100644 --- a/crates/oxc_transformer/src/es2015/arrow_functions.rs +++ b/crates/oxc_transformer/src/es2015/arrow_functions.rs @@ -96,7 +96,7 @@ impl<'a> ArrowFunctions<'a> { self.ast.new_vec_single(variable_declarator), Modifiers::empty(), ); - stmts.insert(0, Statement::Declaration(Declaration::VariableDeclaration(stmt))); + stmts.insert(0, Statement::VariableDeclaration(stmt)); self.insert = false; } diff --git a/crates/oxc_transformer/src/proposals/decorators.rs b/crates/oxc_transformer/src/proposals/decorators.rs index cad9125964561..889be1c30e97b 100644 --- a/crates/oxc_transformer/src/proposals/decorators.rs +++ b/crates/oxc_transformer/src/proposals/decorators.rs @@ -232,7 +232,7 @@ impl<'a> Decorators<'a> { let new_declaration = self.transform_class(class, class_name); if has_decorator { - return Some(Statement::Declaration(new_declaration)); + return Some(Statement::from(new_declaration)); } *declaration = new_declaration; return None; @@ -284,7 +284,7 @@ impl<'a> Decorators<'a> { )); } - Some(Statement::Declaration(self.transform_class(class, class_name))) + Some(Statement::from(self.transform_class(class, class_name))) } else { None } @@ -423,9 +423,7 @@ impl<'a> Decorators<'a> { declarations, Modifiers::empty(), ); - self.top_statements.push(Statement::Declaration(Declaration::VariableDeclaration( - variable_declaration, - ))); + self.top_statements.push(Statement::VariableDeclaration(variable_declaration)); } c_elements.push(self.get_assignment_target_maybe_default(&class_name)); @@ -684,10 +682,7 @@ impl<'a> Decorators<'a> { Modifiers::empty(), ); - self.top_statements.insert( - 0, - Statement::Declaration(Declaration::VariableDeclaration(variable_declaration)), - ); + self.top_statements.insert(0, Statement::VariableDeclaration(variable_declaration)); } { @@ -831,8 +826,7 @@ impl<'a> Decorators<'a> { self.ctx.ast.new_vec_single(self.get_variable_declarator(&class_identifier_name)), Modifiers::empty(), ); - self.top_statements - .push(Statement::Declaration(Declaration::VariableDeclaration(decl))); + self.top_statements.push(Statement::VariableDeclaration(decl)); let left = self.ctx.ast.simple_assignment_target_identifier(class_identifier.clone()); let right = self.ctx.ast.class_expression(self.ctx.ast.copy(class)); diff --git a/crates/oxc_transformer/src/react_jsx/mod.rs b/crates/oxc_transformer/src/react_jsx/mod.rs index a1bbac5b36900..d96fd17fbf11d 100644 --- a/crates/oxc_transformer/src/react_jsx/mod.rs +++ b/crates/oxc_transformer/src/react_jsx/mod.rs @@ -351,7 +351,7 @@ impl<'a> ReactJsx<'a> { decl, Modifiers::empty(), ); - let stmt = Statement::Declaration(Declaration::VariableDeclaration(variable_declaration)); + let stmt = Statement::VariableDeclaration(variable_declaration); if front { self.imports.insert(0, stmt); diff --git a/crates/oxc_transformer/src/typescript/mod.rs b/crates/oxc_transformer/src/typescript/mod.rs index 3e28326155228..795d9188d43e2 100644 --- a/crates/oxc_transformer/src/typescript/mod.rs +++ b/crates/oxc_transformer/src/typescript/mod.rs @@ -79,7 +79,7 @@ impl<'a> TypeScript<'a> { None } } - Statement::Declaration(Declaration::TSModuleDeclaration(ts_module_decl)) => { + Statement::TSModuleDeclaration(ts_module_decl) => { if ts_module_decl.modifiers.is_contains_declare() { None } else { @@ -323,8 +323,7 @@ impl<'a> TypeScript<'a> { decls }; let decl = self.ctx.ast.variable_declaration(SPAN, kind, decls, Modifiers::empty()); - let stmt: Statement<'_> = - Statement::Declaration(Declaration::VariableDeclaration(decl)); + let stmt = Statement::VariableDeclaration(decl); statements.push(stmt); } @@ -578,7 +577,7 @@ impl<'a> TypeScript<'a> { return None; } - Some(Statement::Declaration(self.ctx.ast.move_declaration(declaration))) + Some(Statement::from(self.ctx.ast.move_declaration(declaration))) } /// Insert let declaration for ts module block @@ -587,7 +586,7 @@ impl<'a> TypeScript<'a> { for (index, stmt) in stmts.iter().enumerate() { match stmt { - Statement::Declaration(Declaration::TSModuleDeclaration(decl)) => { + Statement::TSModuleDeclaration(decl) => { if !decl.modifiers.is_contains_declare() { insert_var_decl.push((index, decl.id.name().clone(), false)); } @@ -632,7 +631,7 @@ impl<'a> TypeScript<'a> { ), )) } else { - Statement::Declaration(decl) + Statement::from(decl) }; stmts.insert(index, stmt); } diff --git a/crates/oxc_transformer/src/utils.rs b/crates/oxc_transformer/src/utils.rs index 902c3b8509d6d..8aa97adc51654 100644 --- a/crates/oxc_transformer/src/utils.rs +++ b/crates/oxc_transformer/src/utils.rs @@ -21,7 +21,7 @@ pub trait CreateVars<'a> { let kind = VariableDeclarationKind::Var; let decl = self.ctx().ast.variable_declaration(Span::default(), kind, decls, Modifiers::empty()); - let stmt = Statement::Declaration(Declaration::VariableDeclaration(decl)); + let stmt = Statement::VariableDeclaration(decl); stmts.insert(0, stmt); }