diff --git a/crates/oxc_ast/src/ast/js.rs b/crates/oxc_ast/src/ast/js.rs index 10aa58bf1b4a2e..546957ebd077e9 100644 --- a/crates/oxc_ast/src/ast/js.rs +++ b/crates/oxc_ast/src/ast/js.rs @@ -1436,6 +1436,7 @@ pub struct Function<'a> { pub id: Option>, pub generator: bool, pub r#async: bool, + pub declare: bool, pub type_parameters: Option>>, /// Declaring `this` in a Function /// @@ -1456,8 +1457,6 @@ pub struct Function<'a> { pub params: Box<'a, FormalParameters<'a>>, pub body: Option>>, pub return_type: Option>>, - /// Valid modifiers: `export`, `default`, `async` - pub modifiers: Modifiers<'a>, pub scope_id: Cell>, } diff --git a/crates/oxc_ast/src/ast_builder.rs b/crates/oxc_ast/src/ast_builder.rs index 31fe3d2e81cbd0..0afc747317d5e2 100644 --- a/crates/oxc_ast/src/ast_builder.rs +++ b/crates/oxc_ast/src/ast_builder.rs @@ -953,19 +953,7 @@ impl<'a> AstBuilder<'a> { params: Box<'a, FormalParameters<'a>>, body: Option>>, ) -> Box<'a, Function<'a>> { - self.function( - r#type, - span, - id, - false, - false, - None, - params, - body, - None, - None, - Modifiers::empty(), - ) + self.function(r#type, span, id, false, false, false, None, params, body, None, None) } #[inline] @@ -976,12 +964,12 @@ impl<'a> AstBuilder<'a> { id: Option>, generator: bool, r#async: bool, + declare: bool, this_param: Option>, params: Box<'a, FormalParameters<'a>>, body: Option>>, type_parameters: Option>>, return_type: Option>>, - modifiers: Modifiers<'a>, ) -> Box<'a, Function<'a>> { self.alloc(Function::new( r#type, @@ -989,12 +977,12 @@ impl<'a> AstBuilder<'a> { id, generator, r#async, + declare, this_param, params, body, type_parameters, return_type, - modifiers, )) } diff --git a/crates/oxc_ast/src/ast_impl/js.rs b/crates/oxc_ast/src/ast_impl/js.rs index 4f741414b76492..08f56d10dc4e2e 100644 --- a/crates/oxc_ast/src/ast_impl/js.rs +++ b/crates/oxc_ast/src/ast_impl/js.rs @@ -708,7 +708,7 @@ impl<'a> Declaration<'a> { pub fn declare(&self) -> bool { match self { Declaration::VariableDeclaration(decl) => decl.declare, - Declaration::FunctionDeclaration(decl) => decl.modifiers.is_contains_declare(), + Declaration::FunctionDeclaration(decl) => decl.declare, Declaration::ClassDeclaration(decl) => decl.declare, Declaration::TSEnumDeclaration(decl) => decl.modifiers.is_contains_declare(), Declaration::TSTypeAliasDeclaration(decl) => decl.modifiers.is_contains_declare(), @@ -946,12 +946,12 @@ impl<'a> Function<'a> { id: Option>, generator: bool, r#async: bool, + declare: bool, this_param: Option>, params: Box<'a, FormalParameters<'a>>, body: Option>>, type_parameters: Option>>, return_type: Option>>, - modifiers: Modifiers<'a>, ) -> Self { Self { r#type, @@ -959,12 +959,12 @@ impl<'a> Function<'a> { id, generator, r#async, + declare, this_param, params, body, type_parameters, return_type, - modifiers, scope_id: Cell::default(), } } @@ -974,7 +974,7 @@ impl<'a> Function<'a> { self.r#type, FunctionType::TSDeclareFunction | FunctionType::TSEmptyBodyFunctionExpression ) || self.body.is_none() - || self.modifiers.contains(ModifierKind::Declare) + || self.declare } pub fn is_expression(&self) -> bool { @@ -1004,12 +1004,12 @@ impl<'a> Hash for Function<'a> { self.id.hash(state); self.generator.hash(state); self.r#async.hash(state); + self.declare.hash(state); self.this_param.hash(state); self.params.hash(state); self.body.hash(state); self.type_parameters.hash(state); self.return_type.hash(state); - self.modifiers.hash(state); } } diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index 016b02fa5760fc..a09e6d2ad3ba4b 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -628,7 +628,7 @@ impl<'a, const MINIFY: bool> Gen for Function<'a> { let n = p.code_len(); let wrap = self.is_expression() && (p.start_of_stmt == n || p.start_of_default_export == n); p.wrap(wrap, |p| { - if self.modifiers.contains(ModifierKind::Declare) { + if self.declare { p.print_str(b"declare "); } if self.r#async { diff --git a/crates/oxc_isolated_declarations/src/class.rs b/crates/oxc_isolated_declarations/src/class.rs index 3f6a4356128224..9e32442a75abe6 100644 --- a/crates/oxc_isolated_declarations/src/class.rs +++ b/crates/oxc_isolated_declarations/src/class.rs @@ -108,12 +108,12 @@ impl<'a> IsolatedDeclarations<'a> { self.ast.copy(&function.id), function.generator, function.r#async, + false, self.ast.copy(&function.this_param), params, None, self.ast.copy(&function.type_parameters), return_type, - Modifiers::empty(), ); self.ast.class_method( diff --git a/crates/oxc_isolated_declarations/src/function.rs b/crates/oxc_isolated_declarations/src/function.rs index 389ffa959bbc89..808e9e79cdb843 100644 --- a/crates/oxc_isolated_declarations/src/function.rs +++ b/crates/oxc_isolated_declarations/src/function.rs @@ -18,7 +18,7 @@ impl<'a> IsolatedDeclarations<'a> { func: &Function<'a>, modifiers: Option>, ) -> Option>> { - if func.modifiers.is_contains_declare() { + if func.declare { None } else { let return_type = self.infer_function_return_type(func); @@ -32,12 +32,12 @@ impl<'a> IsolatedDeclarations<'a> { self.ast.copy(&func.id), false, false, + modifiers.unwrap_or_else(|| self.modifiers_declare()).is_contains_declare(), self.ast.copy(&func.this_param), params, None, self.ast.copy(&func.type_parameters), return_type, - modifiers.unwrap_or_else(|| self.modifiers_declare()), )) } } diff --git a/crates/oxc_parser/src/js/function.rs b/crates/oxc_parser/src/js/function.rs index 6637b69d95a0c7..d2ec4e684f7be2 100644 --- a/crates/oxc_parser/src/js/function.rs +++ b/crates/oxc_parser/src/js/function.rs @@ -57,7 +57,7 @@ impl<'a> ParserImpl<'a> { r#async: bool, generator: bool, func_kind: FunctionKind, - modifiers: Modifiers<'a>, + modifiers: &Modifiers<'a>, ) -> Result>> { let ctx = self.ctx; self.ctx = self.ctx.and_in(true).and_await(r#async).and_yield(generator); @@ -102,18 +102,27 @@ impl<'a> ParserImpl<'a> { self.asi()?; } + for modifier in modifiers.iter() { + if !matches!(modifier.kind, ModifierKind::Declare | ModifierKind::Async) { + self.error(diagnostics::modifiers_cannot_appear( + modifier.span, + modifier.kind.as_str(), + )); + } + } + Ok(self.ast.function( function_type, self.end_span(span), id, generator, r#async, + modifiers.is_contains_declare(), this_param, params, body, type_parameters, return_type, - modifiers, )) } @@ -152,7 +161,7 @@ impl<'a> ParserImpl<'a> { self.expect(Kind::Function)?; let generator = self.eat(Kind::Star); let id = self.parse_function_id(func_kind, r#async, generator)?; - self.parse_function(span, id, r#async, generator, func_kind, Modifiers::empty()) + self.parse_function(span, id, r#async, generator, func_kind, &Modifiers::empty()) } /// Parse function implementation in Typescript, cursor @@ -161,7 +170,7 @@ impl<'a> ParserImpl<'a> { &mut self, start_span: Span, func_kind: FunctionKind, - modifiers: Modifiers<'a>, + modifiers: &Modifiers<'a>, ) -> Result>> { let r#async = modifiers.contains(ModifierKind::Async); self.expect(Kind::Function)?; @@ -182,7 +191,7 @@ impl<'a> ParserImpl<'a> { let generator = self.eat(Kind::Star); let id = self.parse_function_id(func_kind, r#async, generator)?; let function = - self.parse_function(span, id, r#async, generator, func_kind, Modifiers::empty())?; + self.parse_function(span, id, r#async, generator, func_kind, &Modifiers::empty())?; Ok(self.ast.function_expression(function)) } @@ -207,7 +216,7 @@ impl<'a> ParserImpl<'a> { r#async, generator, FunctionKind::Expression, - Modifiers::empty(), + &Modifiers::empty(), ) } diff --git a/crates/oxc_parser/src/ts/statement.rs b/crates/oxc_parser/src/ts/statement.rs index 7ef044322c61a8..283b7155705164 100644 --- a/crates/oxc_parser/src/ts/statement.rs +++ b/crates/oxc_parser/src/ts/statement.rs @@ -310,10 +310,10 @@ impl<'a> ParserImpl<'a> { _ if self.at_function_with_async() => { let declare = modifiers.contains(ModifierKind::Declare); if declare { - self.parse_ts_declare_function(start_span, modifiers) + self.parse_ts_declare_function(start_span, &modifiers) .map(Declaration::FunctionDeclaration) } else if self.ts_enabled() { - self.parse_ts_function_impl(start_span, FunctionKind::Declaration, modifiers) + self.parse_ts_function_impl(start_span, FunctionKind::Declaration, &modifiers) .map(Declaration::FunctionDeclaration) } else { self.parse_function_impl(FunctionKind::Declaration) @@ -327,7 +327,7 @@ impl<'a> ParserImpl<'a> { pub(crate) fn parse_ts_declare_function( &mut self, start_span: Span, - modifiers: Modifiers<'a>, + modifiers: &Modifiers<'a>, ) -> Result>> { let r#async = modifiers.contains(ModifierKind::Async); self.expect(Kind::Function)?; diff --git a/crates/oxc_semantic/src/checker/mod.rs b/crates/oxc_semantic/src/checker/mod.rs index 236cba6dfbb1fa..76798224500b2a 100644 --- a/crates/oxc_semantic/src/checker/mod.rs +++ b/crates/oxc_semantic/src/checker/mod.rs @@ -34,7 +34,6 @@ pub fn check<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) { AstKind::RegExpLiteral(lit) => js::check_regexp_literal(lit, ctx), AstKind::Directive(dir) => js::check_directive(dir, ctx), - AstKind::Function(func) => ts::check_function(func, node, ctx), AstKind::ModuleDeclaration(decl) => { js::check_module_declaration(decl, node, ctx); } diff --git a/crates/oxc_semantic/src/checker/typescript.rs b/crates/oxc_semantic/src/checker/typescript.rs index b6423831e852be..353a25db4200ca 100644 --- a/crates/oxc_semantic/src/checker/typescript.rs +++ b/crates/oxc_semantic/src/checker/typescript.rs @@ -173,10 +173,6 @@ fn check_declaration_modifiers<'a>( } } -pub fn check_function<'a>(function: &Function<'a>, node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) { - check_declaration_modifiers(&function.modifiers, node, ctx); -} - pub fn check_ts_type_alias_declaration<'a>( decl: &TSTypeAliasDeclaration<'a>, node: &AstNode<'a>, diff --git a/crates/oxc_transformer/src/es2015/arrow_functions.rs b/crates/oxc_transformer/src/es2015/arrow_functions.rs index 86ffad21c090e3..ee5abaf2e0b9ca 100644 --- a/crates/oxc_transformer/src/es2015/arrow_functions.rs +++ b/crates/oxc_transformer/src/es2015/arrow_functions.rs @@ -219,12 +219,12 @@ impl<'a> ArrowFunctions<'a> { id: None, generator: false, r#async: arrow_function_expr.r#async, + declare: false, this_param: None, params: self.ctx.ast.copy(&arrow_function_expr.params), body: Some(body), type_parameters: self.ctx.ast.copy(&arrow_function_expr.type_parameters), return_type: self.ctx.ast.copy(&arrow_function_expr.return_type), - modifiers: Modifiers::empty(), scope_id: Cell::new(scope_id), }; diff --git a/crates/oxc_traverse/src/ancestor.rs b/crates/oxc_traverse/src/ancestor.rs index d1308878fa249a..4d2069d2f52b8d 100644 --- a/crates/oxc_traverse/src/ancestor.rs +++ b/crates/oxc_traverse/src/ancestor.rs @@ -5173,12 +5173,12 @@ pub(crate) const OFFSET_FUNCTION_SPAN: usize = offset_of!(Function, span); pub(crate) const OFFSET_FUNCTION_ID: usize = offset_of!(Function, id); pub(crate) const OFFSET_FUNCTION_GENERATOR: usize = offset_of!(Function, generator); pub(crate) const OFFSET_FUNCTION_ASYNC: usize = offset_of!(Function, r#async); +pub(crate) const OFFSET_FUNCTION_DECLARE: usize = offset_of!(Function, declare); pub(crate) const OFFSET_FUNCTION_TYPE_PARAMETERS: usize = offset_of!(Function, type_parameters); pub(crate) const OFFSET_FUNCTION_THIS_PARAM: usize = offset_of!(Function, this_param); pub(crate) const OFFSET_FUNCTION_PARAMS: usize = offset_of!(Function, params); pub(crate) const OFFSET_FUNCTION_BODY: usize = offset_of!(Function, body); pub(crate) const OFFSET_FUNCTION_RETURN_TYPE: usize = offset_of!(Function, return_type); -pub(crate) const OFFSET_FUNCTION_MODIFIERS: usize = offset_of!(Function, modifiers); pub(crate) const OFFSET_FUNCTION_SCOPE_ID: usize = offset_of!(Function, scope_id); #[repr(transparent)] @@ -5206,6 +5206,11 @@ impl<'a> FunctionWithoutId<'a> { unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_ASYNC) as *const bool) } } + #[inline] + pub fn declare(&self) -> &bool { + unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_DECLARE) as *const bool) } + } + #[inline] pub fn type_parameters(&self) -> &Option>> { unsafe { @@ -5246,11 +5251,6 @@ impl<'a> FunctionWithoutId<'a> { } } - #[inline] - pub fn modifiers(&self) -> &Modifiers<'a> { - unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_MODIFIERS) as *const Modifiers<'a>) } - } - #[inline] pub fn scope_id(&self) -> &Cell> { unsafe { @@ -5292,6 +5292,11 @@ impl<'a> FunctionWithoutTypeParameters<'a> { unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_ASYNC) as *const bool) } } + #[inline] + pub fn declare(&self) -> &bool { + unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_DECLARE) as *const bool) } + } + #[inline] pub fn this_param(&self) -> &Option> { unsafe { @@ -5324,11 +5329,6 @@ impl<'a> FunctionWithoutTypeParameters<'a> { } } - #[inline] - pub fn modifiers(&self) -> &Modifiers<'a> { - unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_MODIFIERS) as *const Modifiers<'a>) } - } - #[inline] pub fn scope_id(&self) -> &Cell> { unsafe { @@ -5370,6 +5370,11 @@ impl<'a> FunctionWithoutThisParam<'a> { unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_ASYNC) as *const bool) } } + #[inline] + pub fn declare(&self) -> &bool { + unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_DECLARE) as *const bool) } + } + #[inline] pub fn type_parameters(&self) -> &Option>> { unsafe { @@ -5402,11 +5407,6 @@ impl<'a> FunctionWithoutThisParam<'a> { } } - #[inline] - pub fn modifiers(&self) -> &Modifiers<'a> { - unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_MODIFIERS) as *const Modifiers<'a>) } - } - #[inline] pub fn scope_id(&self) -> &Cell> { unsafe { @@ -5448,6 +5448,11 @@ impl<'a> FunctionWithoutParams<'a> { unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_ASYNC) as *const bool) } } + #[inline] + pub fn declare(&self) -> &bool { + unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_DECLARE) as *const bool) } + } + #[inline] pub fn type_parameters(&self) -> &Option>> { unsafe { @@ -5480,11 +5485,6 @@ impl<'a> FunctionWithoutParams<'a> { } } - #[inline] - pub fn modifiers(&self) -> &Modifiers<'a> { - unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_MODIFIERS) as *const Modifiers<'a>) } - } - #[inline] pub fn scope_id(&self) -> &Cell> { unsafe { @@ -5526,6 +5526,11 @@ impl<'a> FunctionWithoutBody<'a> { unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_ASYNC) as *const bool) } } + #[inline] + pub fn declare(&self) -> &bool { + unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_DECLARE) as *const bool) } + } + #[inline] pub fn type_parameters(&self) -> &Option>> { unsafe { @@ -5558,11 +5563,6 @@ impl<'a> FunctionWithoutBody<'a> { } } - #[inline] - pub fn modifiers(&self) -> &Modifiers<'a> { - unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_MODIFIERS) as *const Modifiers<'a>) } - } - #[inline] pub fn scope_id(&self) -> &Cell> { unsafe { @@ -5604,6 +5604,11 @@ impl<'a> FunctionWithoutReturnType<'a> { unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_ASYNC) as *const bool) } } + #[inline] + pub fn declare(&self) -> &bool { + unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_DECLARE) as *const bool) } + } + #[inline] pub fn type_parameters(&self) -> &Option>> { unsafe { @@ -5636,11 +5641,6 @@ impl<'a> FunctionWithoutReturnType<'a> { } } - #[inline] - pub fn modifiers(&self) -> &Modifiers<'a> { - unsafe { &*((self.0 as *const u8).add(OFFSET_FUNCTION_MODIFIERS) as *const Modifiers<'a>) } - } - #[inline] pub fn scope_id(&self) -> &Cell> { unsafe { diff --git a/tasks/coverage/parser_typescript.snap b/tasks/coverage/parser_typescript.snap index 29bf3129638c0c..66bf96afb519a3 100644 --- a/tasks/coverage/parser_typescript.snap +++ b/tasks/coverage/parser_typescript.snap @@ -6422,6 +6422,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 3 │ export export function f() { } ╰──── + × TS1044: 'export' modifier cannot appear on a module or namespace element. + ╭─[compiler/exportAlreadySeen.ts:3:12] + 2 │ export export var x = 1; + 3 │ export export function f() { } + · ────── + 4 │ + ╰──── + × TS1044: 'export' modifier cannot appear on a module or namespace element. ╭─[compiler/exportAlreadySeen.ts:6:16] 5 │ export export module N { @@ -6438,6 +6446,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 13 │ export export function f() ╰──── + × TS1044: 'export' modifier cannot appear on a module or namespace element. + ╭─[compiler/exportAlreadySeen.ts:13:12] + 12 │ export export var x; + 13 │ export export function f() + · ────── + 14 │ + ╰──── + × TS1044: 'export' modifier cannot appear on a module or namespace element. ╭─[compiler/exportAlreadySeen.ts:16:16] 15 │ export export module N { @@ -6446,14 +6462,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 17 │ export export interface I { } ╰──── - × Modifiers cannot be used here. - ╭─[compiler/exportAlreadySeen.ts:3:12] - 2 │ export export var x = 1; - 3 │ export export function f() { } - · ────── - 4 │ - ╰──── - × Modifiers cannot be used here. ╭─[compiler/exportAlreadySeen.ts:7:16] 6 │ export export class C { } @@ -6470,14 +6478,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 6 │ export export class C { } ╰──── - × Modifiers cannot be used here. - ╭─[compiler/exportAlreadySeen.ts:13:12] - 12 │ export export var x; - 13 │ export export function f() - · ────── - 14 │ - ╰──── - × Modifiers cannot be used here. ╭─[compiler/exportAlreadySeen.ts:17:16] 16 │ export export class C { } @@ -6743,7 +6743,7 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 154 │ } ╰──── - × Modifiers cannot be used here. + × TS1044: 'export' modifier cannot appear on a module or namespace element. ╭─[compiler/functionsWithModifiersInBlocks1.ts:4:12] 3 │ export function f() { } 4 │ declare export function f() { } @@ -16381,6 +16381,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 5 │ } ╰──── + × TS1044: 'public' modifier cannot appear on a module or namespace element. + ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:8:5] + 7 │ module Y2 { + 8 │ public function fn(x: string) { } + · ────── + 9 │ } + ╰──── + × TS1044: 'static' modifier cannot appear on a module or namespace element. ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:12:5] 11 │ module Y4 { @@ -16389,6 +16397,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 13 │ } ╰──── + × TS1044: 'static' modifier cannot appear on a module or namespace element. + ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:16:5] + 15 │ module YY { + 16 │ static function fn(x: string) { } + · ────── + 17 │ } + ╰──── + × TS1044: 'private' modifier cannot appear on a module or namespace element. ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:20:5] 19 │ module YY2 { @@ -16397,23 +16413,7 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 21 │ } ╰──── - × Modifiers cannot be used here. - ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:8:5] - 7 │ module Y2 { - 8 │ public function fn(x: string) { } - · ────── - 9 │ } - ╰──── - - × Modifiers cannot be used here. - ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:16:5] - 15 │ module YY { - 16 │ static function fn(x: string) { } - · ────── - 17 │ } - ╰──── - - × Modifiers cannot be used here. + × TS1044: 'private' modifier cannot appear on a module or namespace element. ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:25:5] 24 │ module YY3 { 25 │ private function fn(x: string) { }