diff --git a/ets2panda/compiler/core/ASTVerifier.cpp b/ets2panda/compiler/core/ASTVerifier.cpp index 932779bba412654173bc35bb5fd29635e50324a3..56eee58bbf2e2e94f3969d2a5aac0a9950dafc49 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 6432660de174155a2e48c31e9623fd0584169317..137b312cf58a74f826af74239c85470103aece13 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 6e01c38304ec2e96d48d81cf0f3ba307b06ce29c..c871308ffbd27e514cdb3d43eadf659556e1ab37 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 0000000000000000000000000000000000000000..10c5b37668290486c3bf766c804c9dcac2da3ee0 --- /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); +}