From 78bd76e8d05bfdc043cc1781f7a01e788088c936 Mon Sep 17 00:00:00 2001 From: Boshen Date: Tue, 14 Mar 2023 07:37:30 +0800 Subject: [PATCH] feat(parser): check function name for `await` and `yield` --- crates/oxc_parser/src/js/expression.rs | 6 +-- crates/oxc_parser/src/js/function.rs | 1 + tasks/coverage/babel.snap | 61 ++++++++++++++++++++++---- tasks/coverage/test262.snap | 43 +++++++++++++++--- tasks/coverage/typescript.snap | 50 ++++++++++++++++++--- 5 files changed, 140 insertions(+), 21 deletions(-) diff --git a/crates/oxc_parser/src/js/expression.rs b/crates/oxc_parser/src/js/expression.rs index 87051e591..d2b9100ff 100644 --- a/crates/oxc_parser/src/js/expression.rs +++ b/crates/oxc_parser/src/js/expression.rs @@ -107,13 +107,13 @@ impl<'a> Parser<'a> { (self.end_span(span), Atom::from(name)) } - fn check_identifier(&mut self, span: Span, name: &Atom) { + pub fn check_identifier(&mut self, span: Span, name: &Atom) { // It is a Syntax Error if this production has an [Await] parameter. - if *name == "await" && self.ctx.has_await() { + if self.ctx.has_await() && *name == "await" { self.error(diagnostics::IdentifierAsync("await", span)); } // It is a Syntax Error if this production has a [Yield] parameter. - if *name == "yield" && self.ctx.has_yield() { + if self.ctx.has_yield() && *name == "yield" { self.error(diagnostics::IdentifierGenerator("yield", span)); } } diff --git a/crates/oxc_parser/src/js/function.rs b/crates/oxc_parser/src/js/function.rs index 1d94c82cc..66224448b 100644 --- a/crates/oxc_parser/src/js/function.rs +++ b/crates/oxc_parser/src/js/function.rs @@ -349,6 +349,7 @@ impl<'a> Parser<'a> { } let id = self.cur_kind().is_binding_identifier().then(|| { let (span, name) = self.parse_identifier_kind(Kind::Ident); + self.check_identifier(span, &name); BindingIdentifier { span, name } }); self.ctx = ctx; diff --git a/tasks/coverage/babel.snap b/tasks/coverage/babel.snap index c3ca0d57a..d3ceaeb7b 100644 --- a/tasks/coverage/babel.snap +++ b/tasks/coverage/babel.snap @@ -1,7 +1,7 @@ Babel Summary: AST Parsed : 2050/2069 (99.08%) Positive Passed: 2050/2069 (99.08%) -Negative Passed: 1312/1502 (87.35%) +Negative Passed: 1319/1502 (87.82%) Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js" Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js" Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-multiple-labels/input.js" @@ -34,11 +34,7 @@ Expect Syntax Error: "es2015/uncategorised/.191/input.js" Expect Syntax Error: "es2015/uncategorised/.335/input.js" Expect Syntax Error: "es2015/uncategorised/.343/input.js" Expect Syntax Error: "es2015/uncategorised/220/input.js" -Expect Syntax Error: "es2015/yield/function-name-function-declaration-inside-generator/input.js" -Expect Syntax Error: "es2015/yield/function-name-generator-expression/input.js" -Expect Syntax Error: "es2017/async-functions/await-async-function-expression-name/input.js" Expect Syntax Error: "es2017/async-functions/await-binding-inside-arrow-params-inside-async-arrow-params/input.js" -Expect Syntax Error: "es2017/async-functions/await-function-declaration-name-inside-async-function/input.js" Expect Syntax Error: "es2017/trailing-function-commas/7/input.js" Expect Syntax Error: "es2018/object-rest-spread/24/input.js" Expect Syntax Error: "es2018/object-rest-spread/comma-after-rest/input.js" @@ -52,9 +48,6 @@ Expect Syntax Error: "esprima/es2015-generator/.generator-parameter-binding-prop Expect Syntax Error: "esprima/es2015-identifier/.invalid_function_wait/input.js" Expect Syntax Error: "esprima/es2015-identifier/invalid_expression_await/input.js" Expect Syntax Error: "esprima/es2015-identifier/invalid_var_await/input.js" -Expect Syntax Error: "esprima/es2015-yield/invalid-yield-generator-declaration/input.js" -Expect Syntax Error: "esprima/es2015-yield/invalid-yield-generator-expression-name/input.js" -Expect Syntax Error: "esprima/es2015-yield/invalid-yield-generator-function-declaration/input.js" Expect Syntax Error: "esprima/expression-primary-literal-regular-expression/.migrated_0005/input.js" Expect Syntax Error: "esprima/expression-primary-literal-regular-expression/.migrated_0006/input.js" Expect Syntax Error: "esprima/expression-primary-literal-regular-expression/.u-flag-invalid-range-4-hex/input.js" @@ -4156,6 +4149,12 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts" · ───── ╰──── + × Cannot use `await` as an identifier in an async context + ╭─[es2015/uncategorised/365/input.js:1:1] + 1 │ function await() {} + · ───── + ╰──── + × The keyword 'await' is reserved ╭─[es2015/uncategorised/367/input.js:1:1] 1 │ class await {} @@ -4331,6 +4330,20 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts" · ╰── Expect `from` here, but found `default` ╰──── + × Cannot use `yield` as an identifier in a generator context + ╭─[es2015/yield/function-name-function-declaration-inside-generator/input.js:1:1] + 1 │ function* fn() { + 2 │ function yield() {} + · ───── + 3 │ } + ╰──── + + × Cannot use `yield` as an identifier in a generator context + ╭─[es2015/yield/function-name-generator-expression/input.js:1:1] + 1 │ +function* yield() {} + · ───── + ╰──── + × The keyword 'yield' is reserved ╭─[es2015/yield/function-name-strict-body/input.js:1:1] 1 │ function yield() { "use strict"; } @@ -4857,6 +4870,20 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts" ╰──── help: Try insert a semicolon here + × Cannot use `await` as an identifier in an async context + ╭─[es2017/async-functions/await-async-function-expression-name/input.js:1:1] + 1 │ (async function await() {}); + · ───── + ╰──── + + × Cannot use `await` as an identifier in an async context + ╭─[es2017/async-functions/await-function-declaration-name-inside-async-function/input.js:1:1] + 1 │ async function foo() { + 2 │ function await() {} + · ───── + 3 │ } + ╰──── + × await expression not allowed in formal parameter ╭─[es2017/async-functions/await-inside-arguments-of-async-call-inside-parameters-of-async-arrow-function/input.js:1:1] 1 │ async function fn() { @@ -7722,12 +7749,24 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts" · ───── ╰──── + × Cannot use `yield` as an identifier in a generator context + ╭─[esprima/es2015-yield/invalid-yield-generator-declaration/input.js:1:1] + 1 │ function *g() { function *yield(){} } + · ───── + ╰──── + × The keyword 'yield' is reserved ╭─[esprima/es2015-yield/invalid-yield-generator-export-default/input.js:1:1] 1 │ export default function *yield() {} · ───── ╰──── + × Cannot use `yield` as an identifier in a generator context + ╭─[esprima/es2015-yield/invalid-yield-generator-expression-name/input.js:1:1] + 1 │ (function*yield(){}) + · ───── + ╰──── + × Cannot use `yield` as an identifier in a generator context ╭─[esprima/es2015-yield/invalid-yield-generator-expression-parameter/input.js:1:1] 1 │ (function *(yield){}) @@ -7740,6 +7779,12 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts" · ───── ╰──── + × Cannot use `yield` as an identifier in a generator context + ╭─[esprima/es2015-yield/invalid-yield-generator-function-declaration/input.js:1:1] + 1 │ function *g() { function yield() {} } + · ───── + ╰──── + × Cannot use `yield` as an identifier in a generator context ╭─[esprima/es2015-yield/invalid-yield-generator-lexical-declaration/input.js:1:1] 1 │ function *g() { let yield; } diff --git a/tasks/coverage/test262.snap b/tasks/coverage/test262.snap index cd0e9a026..040b38685 100644 --- a/tasks/coverage/test262.snap +++ b/tasks/coverage/test262.snap @@ -1,10 +1,7 @@ Test262 Summary: AST Parsed : 44015/44034 (99.96%) Positive Passed: 44015/44034 (99.96%) -Negative Passed: 3899/3917 (99.54%) -Expect Syntax Error: "language/expressions/async-generator/early-errors-expression-await-as-function-binding-identifier.js" -Expect Syntax Error: "language/expressions/await/await-BindingIdentifier-nested.js" -Expect Syntax Error: "language/expressions/generators/yield-as-generator-expression-binding-identifier.js" +Negative Passed: 3903/3917 (99.64%) 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" @@ -18,7 +15,6 @@ 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/function/static-init-await-binding-invalid.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" @@ -6603,6 +6599,13 @@ Expect to Parse: "language/statements/function/S14_A5_T2.js" · ───────── ╰──── + × Cannot use `await` as an identifier in an async context + ╭─[language/expressions/async-generator/early-errors-expression-await-as-function-binding-identifier.js:16:1] + 16 │ + 17 │ (async function* await() { }); + · ───── + ╰──── + × Cannot assign to 'arguments' in strict mode ╭─[language/expressions/async-generator/early-errors-expression-binding-identifier-arguments.js:18:1] 18 │ @@ -6740,6 +6743,13 @@ Expect to Parse: "language/statements/function/S14_A5_T2.js" × The keyword 'yield' is reserved ╭─[language/expressions/async-generator/early-errors-expression-yield-as-function-binding-identifier.js:16:1] 16 │ + 17 │ (async function* yield() { }); + · ───── + ╰──── + + × Cannot use `yield` as an identifier in a generator context + ╭─[language/expressions/async-generator/early-errors-expression-yield-as-function-binding-identifier.js:16:1] + 16 │ 17 │ (async function* yield() { }); · ───── ╰──── @@ -7120,6 +7130,14 @@ Expect to Parse: "language/statements/function/S14_A5_T2.js" 29 │ throw new Test262Error(); ╰──── + × Cannot use `await` as an identifier in an async context + ╭─[language/expressions/await/await-BindingIdentifier-nested.js:16:1] + 16 │ async function foo() { + 17 │ function await() { + · ───── + 18 │ } + ╰──── + × Invalid assignment ╭─[language/expressions/await/early-errors-await-not-simple-assignment-target.js:16:1] 16 │ async function foo() { @@ -15349,6 +15367,13 @@ Expect to Parse: "language/statements/function/S14_A5_T2.js" 29 │ }; ╰──── + × Cannot use `yield` as an identifier in a generator context + ╭─[language/expressions/generators/yield-as-generator-expression-binding-identifier.js:16:1] + 16 │ + 17 │ var g = function* yield() {}; + · ───── + ╰──── + × The keyword 'yield' is reserved ╭─[language/expressions/generators/yield-as-identifier-reference-escaped.js:27:1] 27 │ var gen = function *() { @@ -33049,6 +33074,14 @@ Expect to Parse: "language/statements/function/S14_A5_T2.js" 57 │ ╰──── + × Cannot use `await` as an identifier in an async context + ╭─[language/statements/function/static-init-await-binding-invalid.js:23:1] + 23 │ static { + 24 │ function await() {} + · ───── + 25 │ } + ╰──── + × Illegal 'use strict' directive in function with non-simple parameter list ╭─[language/statements/function/use-strict-with-non-simple-param.js:19:1] 19 │ function f(a = 0) { diff --git a/tasks/coverage/typescript.snap b/tasks/coverage/typescript.snap index 783d21e68..a980c92e1 100644 --- a/tasks/coverage/typescript.snap +++ b/tasks/coverage/typescript.snap @@ -1,7 +1,7 @@ TypeScript Summary: AST Parsed : 2305/2338 (98.59%) Positive Passed: 2305/2338 (98.59%) -Negative Passed: 682/2532 (26.94%) +Negative Passed: 686/2532 (27.09%) Expect Syntax Error: "Symbols/ES5SymbolProperty2.ts" Expect Syntax Error: "Symbols/ES5SymbolProperty6.ts" Expect Syntax Error: "additionalChecks/noPropertyAccessFromIndexSignature1.ts" @@ -16,7 +16,6 @@ Expect Syntax Error: "async/es2017/asyncAwaitIsolatedModules_es2017.ts" Expect Syntax Error: "async/es2017/await_incorrectThisType.ts" Expect Syntax Error: "async/es2017/await_unaryExpression_es2017_1.ts" Expect Syntax Error: "async/es2017/await_unaryExpression_es2017_2.ts" -Expect Syntax Error: "async/es2017/functionDeclarations/asyncFunctionDeclaration12_es2017.ts" Expect Syntax Error: "async/es2017/functionDeclarations/asyncFunctionDeclaration13_es2017.ts" Expect Syntax Error: "async/es2017/functionDeclarations/asyncFunctionDeclaration3_es2017.ts" Expect Syntax Error: "async/es2017/functionDeclarations/asyncFunctionDeclaration8_es2017.ts" @@ -30,7 +29,6 @@ Expect Syntax Error: "async/es5/asyncDeclare_es5.ts" Expect Syntax Error: "async/es5/asyncEnum_es5.ts" Expect Syntax Error: "async/es5/asyncInterface_es5.ts" Expect Syntax Error: "async/es5/asyncModule_es5.ts" -Expect Syntax Error: "async/es5/functionDeclarations/asyncFunctionDeclaration12_es5.ts" Expect Syntax Error: "async/es5/functionDeclarations/asyncFunctionDeclaration13_es5.ts" Expect Syntax Error: "async/es5/functionDeclarations/asyncFunctionDeclaration15_es5.ts" Expect Syntax Error: "async/es5/functionDeclarations/asyncFunctionDeclaration3_es5.ts" @@ -47,7 +45,6 @@ Expect Syntax Error: "async/es6/asyncModule_es6.ts" Expect Syntax Error: "async/es6/asyncQualifiedReturnType_es6.ts" Expect Syntax Error: "async/es6/await_unaryExpression_es6_1.ts" Expect Syntax Error: "async/es6/await_unaryExpression_es6_2.ts" -Expect Syntax Error: "async/es6/functionDeclarations/asyncFunctionDeclaration12_es6.ts" Expect Syntax Error: "async/es6/functionDeclarations/asyncFunctionDeclaration13_es6.ts" Expect Syntax Error: "async/es6/functionDeclarations/asyncFunctionDeclaration15_es6.ts" Expect Syntax Error: "async/es6/functionDeclarations/asyncFunctionDeclaration3_es6.ts" @@ -541,7 +538,6 @@ Expect Syntax Error: "es6/for-ofStatements/for-of48.ts" Expect Syntax Error: "es6/for-ofStatements/for-of55.ts" Expect Syntax Error: "es6/for-ofStatements/for-of6.ts" Expect Syntax Error: "es6/for-ofStatements/for-of7.ts" -Expect Syntax Error: "es6/functionDeclarations/FunctionDeclaration12_es6.ts" Expect Syntax Error: "es6/functionDeclarations/FunctionDeclaration13_es6.ts" Expect Syntax Error: "es6/functionDeclarations/FunctionDeclaration3_es6.ts" Expect Syntax Error: "es6/functionDeclarations/FunctionDeclaration8_es6.ts" @@ -2262,6 +2258,13 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 4 │ } ╰──── + × Cannot use `await` as an identifier in an async context + ╭─[async/es2017/functionDeclarations/asyncFunctionDeclaration12_es2017.ts:2:1] + 2 │ // @noEmitHelpers: true + 3 │ var v = async function await(): Promise { } + · ───── + ╰──── + × Cannot use `await` as an identifier in an async context ╭─[async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts:2:1] 2 │ // @noEmitHelpers: true @@ -2371,6 +2374,13 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 5 │ } ╰──── + × Cannot use `await` as an identifier in an async context + ╭─[async/es5/functionDeclarations/asyncFunctionDeclaration12_es5.ts:3:1] + 3 │ // @noEmitHelpers: true + 4 │ var v = async function await(): Promise { } + · ───── + ╰──── + × Cannot use `await` as an identifier in an async context ╭─[async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts:3:1] 3 │ // @noEmitHelpers: true @@ -2489,6 +2499,13 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 4 │ } ╰──── + × Cannot use `await` as an identifier in an async context + ╭─[async/es6/functionDeclarations/asyncFunctionDeclaration12_es6.ts:2:1] + 2 │ // @noEmitHelpers: true + 3 │ var v = async function await(): Promise { } + · ───── + ╰──── + × Cannot use `await` as an identifier in an async context ╭─[async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts:2:1] 2 │ // @noEmitHelpers: true @@ -2744,6 +2761,14 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 16 │ } ╰──── + × Cannot use `await` as an identifier in an async context + ╭─[classes/classStaticBlock/classStaticBlock22.ts:17:1] + 17 │ static { + 18 │ function await() { }; // illegal + · ───── + 19 │ } + ╰──── + × Cannot use `await` as an identifier in an async context ╭─[classes/classStaticBlock/classStaticBlock22.ts:20:1] 20 │ static { @@ -5166,6 +5191,13 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 3 │ } ╰──── + × Cannot use `yield` as an identifier in a generator context + ╭─[es6/functionDeclarations/FunctionDeclaration12_es6.ts:1:1] + 1 │ // @target: es6 + 2 │ var v = function * yield() { } + · ───── + ╰──── + × Cannot use `yield` as an identifier in a generator context ╭─[es6/functionDeclarations/FunctionDeclaration5_es6.ts:1:1] 1 │ // @target: es6 @@ -8352,6 +8384,14 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" × The keyword 'await' is reserved ╭─[externalModules/topLevelAwaitErrors.6.ts:4:1] 4 │ // await in exported function name should fail + 5 │ export function await() { + · ───── + 6 │ } + ╰──── + + × Cannot use `await` as an identifier in an async context + ╭─[externalModules/topLevelAwaitErrors.6.ts:4:1] + 4 │ // await in exported function name should fail 5 │ export function await() { · ───── 6 │ }