diff --git a/crates/oxc_ast/src/context.rs b/crates/oxc_ast/src/context.rs index 8e7e84f6d..a810849fa 100644 --- a/crates/oxc_ast/src/context.rs +++ b/crates/oxc_ast/src/context.rs @@ -48,6 +48,8 @@ bitflags! { /// Decorator context does not parse computed member expressions, e.g. /// `class C { @dec() ["method"]() {} }` const Decorator = 1 << 6; + + const ClassStaticBlock = 1 << 7; } } @@ -100,6 +102,12 @@ impl Context { self.contains(Self::Decorator) } + #[must_use] + #[inline] + pub fn has_class_static_block(self) -> bool { + self.contains(Self::ClassStaticBlock) + } + #[must_use] #[inline] pub fn union_await_if(self, include: bool) -> Self { @@ -160,6 +168,12 @@ impl Context { self.and(Self::Decorator, include) } + #[must_use] + #[inline] + pub fn and_class_static_block(self, include: bool) -> Self { + self.and(Self::ClassStaticBlock, include) + } + #[must_use] #[inline] fn and(self, flag: Self, set: bool) -> Self { diff --git a/crates/oxc_parser/src/js/class.rs b/crates/oxc_parser/src/js/class.rs index 41ddf8ce0..55dd8f771 100644 --- a/crates/oxc_parser/src/js/class.rs +++ b/crates/oxc_parser/src/js/class.rs @@ -458,9 +458,19 @@ impl<'a> Parser<'a> { let has_await = self.ctx.has_await(); let has_yield = self.ctx.has_yield(); let has_return = self.ctx.has_return(); - self.ctx = self.ctx.and_await(true).and_yield(false).and_return(false); + self.ctx = self + .ctx + .and_await(true) + .and_yield(false) + .and_return(false) + .and_class_static_block(true); let block = self.parse_block()?; - self.ctx = self.ctx.and_await(has_await).and_yield(has_yield).and_return(has_return); + self.ctx = self + .ctx + .and_await(has_await) + .and_yield(has_yield) + .and_return(has_return) + .and_class_static_block(false); Ok(self.ast.static_block(self.end_span(span), block.unbox().body)) } diff --git a/crates/oxc_parser/src/js/expression.rs b/crates/oxc_parser/src/js/expression.rs index d2b9100ff..71d890c82 100644 --- a/crates/oxc_parser/src/js/expression.rs +++ b/crates/oxc_parser/src/js/expression.rs @@ -999,7 +999,7 @@ impl<'a> Parser<'a> { let span = self.start_span(); self.bump_any(); let has_await = self.ctx.has_await(); - if !has_await { + if !has_await || self.ctx.has_class_static_block() { self.error(diagnostics::AwaitExpression(Span::new(span.start, span.start + 5))); } self.ctx = self.ctx.and_await(true); diff --git a/tasks/coverage/test262.snap b/tasks/coverage/test262.snap index 040b38685..ee8af7217 100644 --- a/tasks/coverage/test262.snap +++ b/tasks/coverage/test262.snap @@ -1,7 +1,7 @@ Test262 Summary: AST Parsed : 44015/44034 (99.96%) Positive Passed: 44015/44034 (99.96%) -Negative Passed: 3903/3917 (99.64%) +Negative Passed: 3904/3917 (99.67%) Expect Syntax Error: "language/global-code/export.js" Expect Syntax Error: "language/global-code/import.js" Expect Syntax Error: "language/import/dup-bound-names.js" @@ -14,7 +14,6 @@ Expect Syntax Error: "language/module-code/early-dup-export-id.js" Expect Syntax Error: "language/module-code/early-dup-export-star-as-dflt.js" Expect Syntax Error: "language/module-code/early-export-global.js" Expect Syntax Error: "language/module-code/early-export-unresolvable.js" -Expect Syntax Error: "language/statements/class/static-init-invalid-await.js" Expect Syntax Error: "language/statements/variable/dstr/obj-ptrn-elem-id-static-init-await-invalid.js" Expect to Parse: "language/block-scope/syntax/redeclaration-global/allowed-to-redeclare-function-declaration-with-var.js" @@ -2414,6 +2413,14 @@ Expect to Parse: "language/statements/function/S14_A5_T2.js" 17 │ } ╰──── + × `await` is only allowed within async functions and at the top levels of modules + ╭─[language/expressions/arrow-function/static-init-await-reference.js:15:1] + 15 │ static { + 16 │ ((x = await) => 0); + · ───── + 17 │ } + ╰──── + × Unexpected token ╭─[language/expressions/arrow-function/static-init-await-reference.js:15:1] 15 │ static { @@ -18080,6 +18087,14 @@ Expect to Parse: "language/statements/function/S14_A5_T2.js" · ───── ╰──── + × `await` is only allowed within async functions and at the top levels of modules + ╭─[language/identifier-resolution/static-init-invalid-await.js:22:1] + 22 │ static { + 23 │ await; + · ───── + 24 │ } + ╰──── + × Unexpected token ╭─[language/identifier-resolution/static-init-invalid-await.js:22:1] 22 │ static { @@ -29429,6 +29444,14 @@ Expect to Parse: "language/statements/function/S14_A5_T2.js" 22 │ } ╰──── + × `await` is only allowed within async functions and at the top levels of modules + ╭─[language/statements/class/static-init-invalid-await.js:29:1] + 29 │ static { + 30 │ await 0; + · ───── + 31 │ } + ╰──── + × Identifier `x` has already been declared ╭─[language/statements/class/static-init-invalid-label-dup.js:20:1] 20 │ static { @@ -34026,6 +34049,14 @@ Expect to Parse: "language/statements/function/S14_A5_T2.js" ╰──── help: Wrap this declaration in a block statement + × `await` is only allowed within async functions and at the top levels of modules + ╭─[language/statements/labeled/static-init-invalid-await.js:22:1] + 22 │ static { + 23 │ await: 0; + · ───── + 24 │ } + ╰──── + × Unexpected token ╭─[language/statements/labeled/static-init-invalid-await.js:22:1] 22 │ static { diff --git a/tasks/coverage/typescript.snap b/tasks/coverage/typescript.snap index a980c92e1..841370ab3 100644 --- a/tasks/coverage/typescript.snap +++ b/tasks/coverage/typescript.snap @@ -2777,6 +2777,14 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 22 │ } ╰──── + × `await` is only allowed within async functions and at the top levels of modules + ╭─[classes/classStaticBlock/classStaticBlock22.ts:26:1] + 26 │ await = 1; // legal + 27 │ x = await; // legal (initializers have an implicit function boundary) + · ───── + 28 │ }; + ╰──── + × Unexpected token ╭─[classes/classStaticBlock/classStaticBlock22.ts:26:1] 26 │ await = 1; // legal @@ -2785,6 +2793,14 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 28 │ }; ╰──── + × `await` is only allowed within async functions and at the top levels of modules + ╭─[classes/classStaticBlock/classStaticBlock26.ts:4:1] + 4 │ static { + 5 │ await; // illegal + · ───── + 6 │ } + ╰──── + × Unexpected token ╭─[classes/classStaticBlock/classStaticBlock26.ts:4:1] 4 │ static { @@ -2801,6 +2817,14 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 8 │ let arguments = 1; ╰──── + × `await` is only allowed within async functions and at the top levels of modules + ╭─[classes/classStaticBlock/classStaticBlock6.ts:12:1] + 12 │ static { + 13 │ await: if (true) { + · ───── + 14 │ + ╰──── + × Unexpected token ╭─[classes/classStaticBlock/classStaticBlock6.ts:12:1] 12 │ static { @@ -2809,6 +2833,14 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 14 │ ╰──── + × `await` is only allowed within async functions and at the top levels of modules + ╭─[classes/classStaticBlock/classStaticBlock7.ts:2:1] + 2 │ static { + 3 │ await 1; + · ───── + 4 │ yield 1; + ╰──── + × A 'yield' expression is only allowed in a generator body. ╭─[classes/classStaticBlock/classStaticBlock7.ts:3:1] 3 │ await 1; @@ -2826,6 +2858,22 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 6 │ } ╰──── + × `await` is only allowed within async functions and at the top levels of modules + ╭─[classes/classStaticBlock/classStaticBlock7.ts:11:1] + 11 │ static { + 12 │ await 1; + · ───── + 13 │ + ╰──── + + × `await` is only allowed within async functions and at the top levels of modules + ╭─[classes/classStaticBlock/classStaticBlock7.ts:14:1] + 14 │ async function ff () { + 15 │ await 1; + · ───── + 16 │ } + ╰──── + × A 'yield' expression is only allowed in a generator body. ╭─[classes/classStaticBlock/classStaticBlock7.ts:23:1] 23 │ static {