From df1db419d1aea440ea2d2bd54b80c99b48ed89f9 Mon Sep 17 00:00:00 2001 From: Konstantin Kuznetsov Date: Fri, 12 Jul 2024 13:44:37 +0300 Subject: [PATCH] Fix lambda scope warning from AST Verifier VariableHasScope check failed on test with async lambda due to missing scope node in ETSFunctionType. Scope node was missing after duplicating param scope in a follow-up visit to ETSFunctionType in InitScopesPhaseETS. As it seems duplicating scope was not necessary. Added check to avoid erroneous duplication. Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/IAA1OE Testing: new unit-test for AST Verifier Signed-off-by: Konstantin Kuznetsov --- ets2panda/compiler/core/ASTVerifier.cpp | 5 -- .../lowering/scopesInit/scopesInitPhase.cpp | 14 +++-- ets2panda/test/unit/public/CMakeLists.txt | 4 ++ .../ast_verifier_variable_has_scope_test.cpp | 60 +++++++++++++++++++ 4 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 ets2panda/test/unit/public/ast_verifier_variable_has_scope_test.cpp diff --git a/ets2panda/compiler/core/ASTVerifier.cpp b/ets2panda/compiler/core/ASTVerifier.cpp index 932779bba4..56eee58bbf 100644 --- a/ets2panda/compiler/core/ASTVerifier.cpp +++ b/ets2panda/compiler/core/ASTVerifier.cpp @@ -809,11 +809,6 @@ private: bool CheckAstExceptions(const ir::AstNode *ast) { - // NOTE(kkonkuznetsov): in some cases with lambdas scope node is null - if (ast->Parent() != nullptr && ast->Parent()->IsETSFunctionType()) { - return true; - } - if (ast->IsLabelledStatement()) { // Labels are attached to loop scopes, // however label identifier is outside of loop. diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 6432660de1..137b312cf5 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -963,10 +963,16 @@ void InitScopesPhaseETS::VisitMethodDefinition(ir::MethodDefinition *method) void InitScopesPhaseETS::VisitETSFunctionType(ir::ETSFunctionType *funcType) { auto typeParamsCtx = LexicalScopeCreateOrEnter(VarBinder(), funcType->TypeParams()); - varbinder::LexicalScope lexicalScope(VarBinder()); - auto *funcParamScope = lexicalScope.GetScope(); - BindScopeNode(funcParamScope, funcType); - Iterate(funcType); + + // Check for existing scope + // In some cases we can visit function again with scope that already exists + // Example: async lambda, we "move" original function to another place and visit it again + if (funcType->Scope() == nullptr) { + varbinder::LexicalScope lexicalScope(VarBinder()); + auto *funcParamScope = lexicalScope.GetScope(); + BindScopeNode(funcParamScope, funcType); + Iterate(funcType); + } } void InitScopesPhaseETS::VisitETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *newClassExpr) diff --git a/ets2panda/test/unit/public/CMakeLists.txt b/ets2panda/test/unit/public/CMakeLists.txt index 6e01c38304..c871308ffb 100644 --- a/ets2panda/test/unit/public/CMakeLists.txt +++ b/ets2panda/test/unit/public/CMakeLists.txt @@ -55,6 +55,10 @@ ets2panda_add_gtest(ast_verifier_variable_has_enclosing_scope_test CPP_SOURCES ast_verifier_variable_has_enclosing_scope_test.cpp ) +ets2panda_add_gtest(ast_verifier_variable_has_scope_test + CPP_SOURCES ast_verifier_variable_has_scope_test.cpp +) + panda_add_library(e2p_test_plugin SHARED e2p_test_plugin.c) panda_target_include_directories(e2p_test_plugin PRIVATE "${ES2PANDA_PATH}") panda_target_link_libraries(e2p_test_plugin es2panda-public) 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 new file mode 100644 index 0000000000..10c5b37668 --- /dev/null +++ b/ets2panda/test/unit/public/ast_verifier_variable_has_scope_test.cpp @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ast_verifier_test.h" +#include "ir/astNode.h" + +#include + +using ark::es2panda::compiler::ast_verifier::ASTVerifier; +using ark::es2panda::compiler::ast_verifier::InvariantNameSet; +using ark::es2panda::ir::AstNode; + +TEST_F(ASTVerifierTest, AsyncLambda) +{ + ASTVerifier verifier {Allocator()}; + + char const *text = R"( + let fs: ((p: int) => int)[] + function foo(i: int): ((p: int) => int) { + return fs[i] + } + + function main() { + fs = [ + (p: int): int => p + 1, + ] + + let ps: Object = new Object() + ps = launch foo(0) + + let cnt = 0 + cnt += (await ps as Promise<(p: int) => int>)(0) + } + )"; + + es2panda_Context *ctx = impl_->CreateContextFromString(cfg_, text, "dummy.ets"); + impl_->ProceedToState(ctx, ES2PANDA_STATE_CHECKED); + ASSERT_EQ(impl_->ContextState(ctx), ES2PANDA_STATE_CHECKED); + + auto *ast = reinterpret_cast(impl_->ProgramAst(impl_->ContextProgram(ctx))); + + InvariantNameSet checks; + checks.insert("VariableHasScopeForAll"); + const auto &messages = verifier.Verify(ast, checks); + ASSERT_EQ(messages.size(), 0); + + impl_->DestroyContext(ctx); +} -- Gitee