From 22e5247ca0e12d3046cf038410859a9b3bc25405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E5=AE=B6=E7=86=99?= Date: Fri, 27 Jun 2025 15:15:34 +0800 Subject: [PATCH] Fix await shouldn't out async function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICIB76 Signed-off-by: 梁家熙 --- ets2panda/checker/ETSAnalyzer.cpp | 18 ++++++++++++++++++ .../test/ast/parser/ets/await_priority.ets | 3 +-- .../parser/ets/dynmicImportUnimplemented.ets | 2 +- .../ast/parser/ets/unexpected_token_22.ets | 1 + .../ets/import_tests/asyncfunc_lambda_main.ets | 6 +++++- .../test/parser/ets/await_complex_promise.ets | 10 +++++----- ets2panda/test/parser/ets/await_keyword.ets | 4 ++-- .../test/runtime/ets/ThisInAsyncMethod.ets | 7 +++++-- .../ets/async-func-overload-and-type-infer.ets | 6 +++++- ...nc_and_instance_method_with_same_name01.ets | 6 +++++- ...nc_and_instance_method_with_same_name02.ets | 6 +++++- .../ets/async_method_with_same_name01.ets | 6 +++++- .../ets/async_method_with_same_name02.ets | 6 +++++- ets2panda/test/runtime/ets/async_optional.ets | 6 +++++- .../ast_verifier_variable_has_scope_test.cpp | 6 +++++- ets2panda/util/diagnostic/syntax.yaml | 6 +++++- 16 files changed, 78 insertions(+), 21 deletions(-) diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 4bbfa6e063..6ec19292c1 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1276,6 +1276,20 @@ static bool IsPromiseType(checker::Type *type, ETSChecker *checker) type->AsETSObjectType()->GetOriginalBaseType() == checker->GlobalBuiltinPromiseType(); } +static bool CheckAwaitExpressionInAsyncFunc(ir::AwaitExpression *expr) +{ + ir::AstNode *node = expr; + while (node != nullptr) { + if (node->IsScriptFunction() && + (node->AsScriptFunction()->IsAsyncFunc() || node->AsScriptFunction()->IsAsyncImplFunc())) { + return true; + } else { + node = node->Parent(); + } + } + return false; +} + checker::Type *ETSAnalyzer::Check(ir::AwaitExpression *expr) const { ETSChecker *checker = GetETSChecker(); @@ -1283,6 +1297,10 @@ checker::Type *ETSAnalyzer::Check(ir::AwaitExpression *expr) const return expr->TsType(); } + if (!CheckAwaitExpressionInAsyncFunc(expr)) { + return checker->TypeError(expr, diagnostic::AWAIT_MUST_IN_ASYNC_FUNCTION, expr->Argument()->Start()); + } + checker::Type *argType = checker->GetApparentType(expr->argument_->Check(checker)); ArenaVector awaitedTypes(checker->ProgramAllocator()->Adapter()); diff --git a/ets2panda/test/ast/parser/ets/await_priority.ets b/ets2panda/test/ast/parser/ets/await_priority.ets index 4e77ac3504..d98c5292ef 100644 --- a/ets2panda/test/ast/parser/ets/await_priority.ets +++ b/ets2panda/test/ast/parser/ets/await_priority.ets @@ -14,8 +14,7 @@ */ function main(){ - await test(); - + test(); } async function test() { diff --git a/ets2panda/test/ast/parser/ets/dynmicImportUnimplemented.ets b/ets2panda/test/ast/parser/ets/dynmicImportUnimplemented.ets index 089ace2f22..54eca610e9 100644 --- a/ets2panda/test/ast/parser/ets/dynmicImportUnimplemented.ets +++ b/ets2panda/test/ast/parser/ets/dynmicImportUnimplemented.ets @@ -28,4 +28,4 @@ function main() { } /* @@? 18:15 Error SyntaxError: Unexpected token 'import'. */ -/* @@? 18:15 Error TypeError: 'await' expressions require Promise object as argument. */ +/* @@? 18:15 Error SyntaxError: Using await outside of async function is forbidden. */ diff --git a/ets2panda/test/ast/parser/ets/unexpected_token_22.ets b/ets2panda/test/ast/parser/ets/unexpected_token_22.ets index 19b5147c4d..8ba4500cc5 100644 --- a/ets2panda/test/ast/parser/ets/unexpected_token_22.ets +++ b/ets2panda/test/ast/parser/ets/unexpected_token_22.ets @@ -40,3 +40,4 @@ function main(): void { /* @@? 25:43 Error TypeError: Type '(_: Promise) => Promise' cannot be assigned to type '() => Promise' */ /* @@? 25:44 Error SyntaxError: Unexpected token, expected an identifier. */ /* @@? 25:60 Error SyntaxError: Unexpected token, expected ',' or ')'. */ +/* @@? 31:11 Error SyntaxError: Using await outside of async function is forbidden. */ diff --git a/ets2panda/test/compiler/ets/import_tests/asyncfunc_lambda_main.ets b/ets2panda/test/compiler/ets/import_tests/asyncfunc_lambda_main.ets index 000e77b934..9ae4b2079a 100644 --- a/ets2panda/test/compiler/ets/import_tests/asyncfunc_lambda_main.ets +++ b/ets2panda/test/compiler/ets/import_tests/asyncfunc_lambda_main.ets @@ -19,7 +19,7 @@ import { CC } from "./asyncfun_lambda_lib" import { DC } from "./asyncfun_lambda_lib" -function main(): void { +async function asyncFoo(): Promise { let aClass: AC = new AC(); await aClass.foo(); @@ -32,3 +32,7 @@ function main(): void { let dClass: DC = new DC(); dClass.foz(); } + +function main(): void { + asyncFoo() +} diff --git a/ets2panda/test/parser/ets/await_complex_promise.ets b/ets2panda/test/parser/ets/await_complex_promise.ets index 6efaf5c538..f946480fbd 100644 --- a/ets2panda/test/parser/ets/await_complex_promise.ets +++ b/ets2panda/test/parser/ets/await_complex_promise.ets @@ -13,23 +13,23 @@ * limitations under the License. */ -function foo1(p: Promise>): void { +async function foo1(p: Promise>): Promise { let result: string = await p; } -function foo2(p: Promise|number>): void { +async function foo2(p: Promise|number>): Promise { let result: string|number = await p; } -function foo3(p: Promise|Promise>): void { +async function foo3(p: Promise|Promise>): Promise { let result: string|number = await p; } -function foo4(p: Promise>): void { +async function foo4(p: Promise>): Promise { let result: null|string = await p; } type Alias = Promise|number; -function foo5(p: Promise): void { +async function foo5(p: Promise): Promise { let result: string|number = await p; } diff --git a/ets2panda/test/parser/ets/await_keyword.ets b/ets2panda/test/parser/ets/await_keyword.ets index b90d64d9bf..613a23cf43 100644 --- a/ets2panda/test/parser/ets/await_keyword.ets +++ b/ets2panda/test/parser/ets/await_keyword.ets @@ -25,12 +25,12 @@ let asyncLambda: () => Promise = async (): Promise return promise; } -function foo(): void { +async function foo(): Promise { let promise: Promise | null = (): Promise | null => { return null; }(); let obj: Object | null = await promise!; } -let lambda: () => void = (): void => { +let lambda: () => Promise = async (): Promise => { let promise: Promise | null = (): Promise | null => { return null; }(); let obj: Object | null = await promise!; } diff --git a/ets2panda/test/runtime/ets/ThisInAsyncMethod.ets b/ets2panda/test/runtime/ets/ThisInAsyncMethod.ets index 82ca7f094e..64b9dd5e7c 100644 --- a/ets2panda/test/runtime/ets/ThisInAsyncMethod.ets +++ b/ets2panda/test/runtime/ets/ThisInAsyncMethod.ets @@ -17,8 +17,11 @@ class X { async m(): Promise /* #19874 */ { return this } } -function main() { +async function asyncFoo(): Promise { let f = (): object | null | undefined => await new X().m() - arktest.assertTrue(f() instanceof X) } + +function main() { + asyncFoo() +} diff --git a/ets2panda/test/runtime/ets/async-func-overload-and-type-infer.ets b/ets2panda/test/runtime/ets/async-func-overload-and-type-infer.ets index 74b905de90..11635623e6 100644 --- a/ets2panda/test/runtime/ets/async-func-overload-and-type-infer.ets +++ b/ets2panda/test/runtime/ets/async-func-overload-and-type-infer.ets @@ -30,10 +30,14 @@ async function multipleReturns(flag: boolean): Promise { return "string2" } -function main() { +async function asyncFoo(): Promise { let a: int|string = await multipleReturns(true, 42); let b: int|string = await multipleReturns(false); arktest.assertEQ(a, 42) arktest.assertEQ(b, "string2") } + +function main() { + asyncFoo() +} diff --git a/ets2panda/test/runtime/ets/async_and_instance_method_with_same_name01.ets b/ets2panda/test/runtime/ets/async_and_instance_method_with_same_name01.ets index ec2ef06385..baa2e52386 100644 --- a/ets2panda/test/runtime/ets/async_and_instance_method_with_same_name01.ets +++ b/ets2panda/test/runtime/ets/async_and_instance_method_with_same_name01.ets @@ -22,9 +22,13 @@ class A{ } } -function main(){ +async function asyncFoo(): Promise { let res1:string = await new A().getData() let res2:string = A.getData("I'm a static method with name 'getData'") arktest.assertEQ(res1, "I'm a instance method with name 'getData'") arktest.assertEQ(res2, "I'm a static method with name 'getData'") } + +function main(){ + asyncFoo() +} diff --git a/ets2panda/test/runtime/ets/async_and_instance_method_with_same_name02.ets b/ets2panda/test/runtime/ets/async_and_instance_method_with_same_name02.ets index 8cd629b6de..c0b8408ce9 100644 --- a/ets2panda/test/runtime/ets/async_and_instance_method_with_same_name02.ets +++ b/ets2panda/test/runtime/ets/async_and_instance_method_with_same_name02.ets @@ -22,9 +22,13 @@ class A{ } } -function main(){ +async function asyncFoo(): Promise { let res1:string = new A().getData() let res2:string = await A.getData("I'm a static method with name 'getData'") arktest.assertEQ(res1, "I'm a instance method with name 'getData'") arktest.assertEQ(res2, "I'm a static method with name 'getData'") } + +function main(){ + asyncFoo() +} diff --git a/ets2panda/test/runtime/ets/async_method_with_same_name01.ets b/ets2panda/test/runtime/ets/async_method_with_same_name01.ets index a1aac4e6dc..646bf9c9d6 100644 --- a/ets2panda/test/runtime/ets/async_method_with_same_name01.ets +++ b/ets2panda/test/runtime/ets/async_method_with_same_name01.ets @@ -22,9 +22,13 @@ class A{ } } -function main(){ +async function asyncFoo(): Promise { let res1:string = await new A().getData() let res2:string = await A.getData("I'm a static method with name 'getData'") arktest.assertEQ(res1, "I'm a instance method with name 'getData'") arktest.assertEQ(res2, "I'm a static method with name 'getData'") } + +function main(){ + asyncFoo() +} diff --git a/ets2panda/test/runtime/ets/async_method_with_same_name02.ets b/ets2panda/test/runtime/ets/async_method_with_same_name02.ets index db334bdb7d..d50d3a1d85 100644 --- a/ets2panda/test/runtime/ets/async_method_with_same_name02.ets +++ b/ets2panda/test/runtime/ets/async_method_with_same_name02.ets @@ -22,10 +22,14 @@ class A{ } } -function main(){ +async function asyncFoo(): Promise { let res1:string = await A.getData() let res2:string = await A.getData("I'm a static method2 with name 'getData'") arktest.assertEQ(res1, "I'm a static method1 with name 'getData'") arktest.assertEQ(res2, "I'm a static method2 with name 'getData'") } +function main(){ + asyncFoo() +} + diff --git a/ets2panda/test/runtime/ets/async_optional.ets b/ets2panda/test/runtime/ets/async_optional.ets index 87d4a1059a..0c891bed82 100644 --- a/ets2panda/test/runtime/ets/async_optional.ets +++ b/ets2panda/test/runtime/ets/async_optional.ets @@ -22,9 +22,13 @@ class A { } } -function main() { +async function asyncFoo(): Promise { let t : InputT = {name: "zztest"}; let a : A = new A(); let b = await a.update(t); arktest.assertEQ(b, "zztest") +} + +function main() { + asyncFoo() } \ No newline at end of file diff --git a/ets2panda/test/unit/public/ast_verifier_variable_has_scope_test.cpp b/ets2panda/test/unit/public/ast_verifier_variable_has_scope_test.cpp index 470b082849..778e7b29ab 100644 --- a/ets2panda/test/unit/public/ast_verifier_variable_has_scope_test.cpp +++ b/ets2panda/test/unit/public/ast_verifier_variable_has_scope_test.cpp @@ -95,7 +95,7 @@ TEST_F(ASTVerifierTest, AsyncLambda1) return fs[i] } - function main() { + async function asyncFoo() { fs = [ (p: int): int => p + 1, ] @@ -106,6 +106,10 @@ TEST_F(ASTVerifierTest, AsyncLambda1) let cnt = 0 cnt += (await (ps as Promise<(p: int) => int>))(0) } + + function main() { + asyncFoo() + } )"; CONTEXT(ES2PANDA_STATE_CHECKED, text) diff --git a/ets2panda/util/diagnostic/syntax.yaml b/ets2panda/util/diagnostic/syntax.yaml index 707be9029a..8e49f08b6b 100644 --- a/ets2panda/util/diagnostic/syntax.yaml +++ b/ets2panda/util/diagnostic/syntax.yaml @@ -1306,4 +1306,8 @@ syntax: - name: FUNCTION_OVERLOADED_NAME_MUST_QUALIFIED_NAME id: 325 - message: "The overloaded method name in function overload declaration must be qualified name." \ No newline at end of file + message: "The overloaded method name in function overload declaration must be qualified name." + +- name: AWAIT_MUST_IN_ASYNC_FUNCTION + id: 326 + message: "Using await outside of async function is forbidden." -- Gitee