From 520e6ae988d66154dbb342ffcd4d9d00dae09039 Mon Sep 17 00:00:00 2001 From: Klimentieva Date: Thu, 29 May 2025 13:27:00 +0300 Subject: [PATCH] change transforming to static invoke Change-Id: I0a7eb43b2673626ce9fbbbdac75c0dde24f03f75 Signed-off-by: Klimentieva --- ets2panda/BUILD.gn | 1 + ets2panda/CMakeLists.txt | 1 + ets2panda/checker/ETSAnalyzer.cpp | 8 -- ets2panda/checker/ETSchecker.h | 6 +- ets2panda/checker/ets/function.cpp | 11 +++ ets2panda/checker/ets/function_helpers.h | 6 +- ets2panda/checker/ets/helpers.cpp | 63 ++++-------- ets2panda/checker/ets/validateHelpers.cpp | 4 +- ets2panda/checker/types/signature.h | 2 + .../lowering/ets/transformToStaticInvoke.cpp | 96 +++++++++++++++++++ .../lowering/ets/transformToStaticInvoke.h | 35 +++++++ ets2panda/compiler/lowering/phase.cpp | 2 + 12 files changed, 177 insertions(+), 58 deletions(-) create mode 100644 ets2panda/compiler/lowering/ets/transformToStaticInvoke.cpp create mode 100644 ets2panda/compiler/lowering/ets/transformToStaticInvoke.h diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 92680ad14a..7934aa99a8 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -258,6 +258,7 @@ libes2panda_sources = [ "compiler/lowering/ets/topLevelStmts/topLevelStmts.cpp", "compiler/lowering/ets/typeFromLowering.cpp", "compiler/lowering/ets/unboxLowering.cpp", + "compiler/lowering/ets/transformToStaticInvoke.cpp", "compiler/lowering/ets/unionLowering.cpp", "compiler/lowering/ets/annotationCopyLowering.cpp", "compiler/lowering/ets/annotationCopyPostLowering.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 7719bd2968..6d18dffc53 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -325,6 +325,7 @@ set(ES2PANDA_LIB_SRC compiler/lowering/ets/annotationCopyPostLowering.cpp compiler/lowering/ets/primitiveConversionPhase.cpp compiler/lowering/ets/unboxLowering.cpp + compiler/lowering/ets/transformToStaticInvoke.cpp ir/astDump.cpp ir/srcDump.cpp ir/astNode.cpp diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index ca365e2a61..c0278457a8 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1523,19 +1523,11 @@ checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const return expr->TsType(); } ES2PANDA_ASSERT(!expr->IsOptional()); - - auto *oldCallee = expr->Callee(); checker::Type *calleeType = checker->GetApparentType(expr->Callee()->Check(checker)); if (calleeType->IsTypeError()) { return checker->InvalidateType(expr); } - if (expr->Callee() != oldCallee) { - // If it is a static invoke, the callee will be transformed from an identifier to a member expression - // Type check the callee again for member expression - calleeType = checker->GetApparentType(expr->Callee()->Check(checker)); - } - CheckCallee(checker, expr); checker::TypeStackElement tse(checker, expr, {{diagnostic::CYCLIC_CALLEE, {}}}, expr->Start()); diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index ec155ee9ae..9e3a686b3c 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -1037,11 +1037,7 @@ private: ArenaVector ExtendArgumentsWithFakeLamda(ir::CallExpression *callExpr); // Static invoke - bool SetStaticInvokeValues(ir::Identifier *const ident, ir::Identifier *classId, ir::Identifier *methodId, - varbinder::LocalVariable *instantiateMethod); - void CreateTransformedCallee(ir::Identifier *classId, ir::Identifier *methodId, ir::Identifier *const ident, - varbinder::LocalVariable *instantiateMethod); - bool TryTransformingToStaticInvoke(ir::Identifier *ident, const Type *resolvedType); + bool ValidateStaticInvoke(ir::Identifier *ident, Type *resolvedType); // Partial Type *HandleUnionForPartialType(ETSUnionType *typeToBePartial); diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index c2c1ed6974..d243b9b069 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -646,6 +646,13 @@ Signature *ETSChecker::ValidateSignature( compareCount = compareCount - 1; } + if (signature->HasSignatureFlag(SignatureFlags::INSTANTIATE)) { + if (baseSignature->Params().empty()) { + LogError(diagnostic::NO_MATCHING_SIG_2, {"call"}, pos); + } + return signature; + } + if (compareCount < signature->MinArgCount() || (argCount > signature->ArgCount() && !hasRestParameter)) { if (reportError) { LogError(diagnostic::PARAM_COUNT_MISMATCH, {signature->MinArgCount(), argCount}, pos); @@ -1302,6 +1309,10 @@ Signature *ETSChecker::MakeSignatureInvocable(Signature *sig, ir::CallExpression continue; } + if (sig->HasSignatureFlag(SignatureFlags::INSTANTIATE)) { + continue; + } + auto ctx = checker::AssignmentContext( Relation(), callExpr->Arguments().at(idx), callExpr->Arguments().at(idx)->TsType(), sig->Params().at(idx)->TsType(), callExpr->Arguments().at(idx)->Start(), diff --git a/ets2panda/checker/ets/function_helpers.h b/ets2panda/checker/ets/function_helpers.h index 7c22e2f83b..223579ff03 100644 --- a/ets2panda/checker/ets/function_helpers.h +++ b/ets2panda/checker/ets/function_helpers.h @@ -132,6 +132,11 @@ static std::optional BuildImplicitSubstitutionForArguments(ETSChec continue; } if (newTypeParam->GetDefaultType() == nullptr) { + if (signature->HasSignatureFlag(SignatureFlags::INSTANTIATE)) { + checker->EmplaceSubstituted(&substitution, newTypeParam, signature->Owner()->AsETSObjectType()); + continue; + } + checker->EmplaceSubstituted(&substitution, newTypeParam, checker->GlobalETSNeverType()); continue; } @@ -148,7 +153,6 @@ static std::optional BuildImplicitSubstitutionForArguments(ETSChec signature->ReturnType(), &substitution))) { return std::nullopt; } - return substitution; } diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 26ed9ad28c..a3d5bf47da 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -307,6 +307,7 @@ Type *ETSChecker::ResolveIdentifier(ir::Identifier *ident) ident->SetVariable(resolved); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) ValidateResolvedIdentifier(ident); + resolved = ident->Variable(); ValidatePropertyAccess(resolved, Context().ContainingClass(), ident->Start()); SaveCapturedVariable(resolved, ident); @@ -2926,8 +2927,7 @@ void ETSChecker::GenerateGetterSetterPropertyAndMethod(ir::ClassProperty *origin } } -// CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic -bool ETSChecker::TryTransformingToStaticInvoke(ir::Identifier *const ident, const Type *resolvedType) +bool ETSChecker::ValidateStaticInvoke(ir::Identifier *const ident, Type *resolvedType) { ES2PANDA_ASSERT(ident->Parent()->IsCallExpression()); ES2PANDA_ASSERT(ident->Parent()->AsCallExpression()->Callee() == ident); @@ -2937,61 +2937,40 @@ bool ETSChecker::TryTransformingToStaticInvoke(ir::Identifier *const ident, cons } auto className = ident->Name(); - std::string_view propertyName; PropertySearchFlags searchFlag = PropertySearchFlags::SEARCH_IN_INTERFACES | PropertySearchFlags::SEARCH_IN_BASE | PropertySearchFlags::SEARCH_STATIC_METHOD; auto *instantiateMethod = resolvedType->AsETSObjectType()->GetProperty(compiler::Signatures::STATIC_INSTANTIATE_METHOD, searchFlag); + if (instantiateMethod != nullptr) { + for (auto sig : instantiateMethod->TsType()->AsETSFunctionType()->CallSignaturesOfMethodOrArrow()) { + sig->AddSignatureFlag(SignatureFlags::INSTANTIATE); + sig->SetOwner(resolvedType->AsETSObjectType()); + } + } + auto *invokeMethod = resolvedType->AsETSObjectType()->GetProperty(compiler::Signatures::STATIC_INVOKE_METHOD, searchFlag); - if (instantiateMethod != nullptr) { - propertyName = compiler::Signatures::STATIC_INSTANTIATE_METHOD; - } else if (invokeMethod != nullptr) { - propertyName = compiler::Signatures::STATIC_INVOKE_METHOD; - } else { + if (invokeMethod != nullptr) { + for (auto sig : invokeMethod->TsType()->AsETSFunctionType()->CallSignaturesOfMethodOrArrow()) { + sig->AddSignatureFlag(SignatureFlags::INVOKE); + } + } + + if (invokeMethod == nullptr && instantiateMethod == nullptr) { LogError(diagnostic::NO_STATIC_INVOKE, {compiler::Signatures::STATIC_INVOKE_METHOD, compiler::Signatures::STATIC_INSTANTIATE_METHOD, className, className}, ident->Start()); return true; } - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *classId = ProgramAllocNode(className, ProgramAllocator()); - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *methodId = ProgramAllocNode(propertyName, ProgramAllocator()); - if (propertyName == compiler::Signatures::STATIC_INSTANTIATE_METHOD) { - methodId->SetVariable(instantiateMethod); - } else if (propertyName == compiler::Signatures::STATIC_INVOKE_METHOD) { - methodId->SetVariable(invokeMethod); - } - - auto *transformedCallee = - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - ProgramAllocNode(classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, - false); - classId->SetRange(ident->Range()); - methodId->SetRange(ident->Range()); - transformedCallee->SetRange(ident->Range()); + ident->SetTsType(invokeMethod != nullptr ? invokeMethod->TsType() : instantiateMethod->TsType()); + varbinder::LocalVariable *invokeinstantiateVar = + Allocator()->New(ident->Variable()->Declaration(), ident->Variable()->Flags()); + ident->SetVariable(invokeinstantiateVar); - auto *callExpr = ident->Parent()->AsCallExpression(); - transformedCallee->SetParent(callExpr); - callExpr->SetCallee(transformedCallee); - - if (instantiateMethod != nullptr) { - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - auto *argExpr = GenerateImplicitInstantiateArg(std::string(className)); - - argExpr->SetParent(callExpr); - argExpr->SetRange(ident->Range()); - - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - VarBinder()->AsETSBinder()->HandleCustomNodes(argExpr); - - auto &arguments = callExpr->Arguments(); - arguments.insert(arguments.begin(), argExpr); - } + ident->Variable()->SetTsType(ident->TsType()); return true; } diff --git a/ets2panda/checker/ets/validateHelpers.cpp b/ets2panda/checker/ets/validateHelpers.cpp index 685c1d8b4b..91bcbb10a7 100644 --- a/ets2panda/checker/ets/validateHelpers.cpp +++ b/ets2panda/checker/ets/validateHelpers.cpp @@ -71,8 +71,8 @@ void ETSChecker::ValidateCallExpressionIdentifier(ir::Identifier *const ident, T if (type->IsETSFunctionType()) { return; } - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - if (TryTransformingToStaticInvoke(ident, type)) { + + if (ValidateStaticInvoke(ident, type)) { return; } diff --git a/ets2panda/checker/types/signature.h b/ets2panda/checker/types/signature.h index d94e607e8b..219a6fc049 100644 --- a/ets2panda/checker/types/signature.h +++ b/ets2panda/checker/types/signature.h @@ -91,6 +91,8 @@ enum class SignatureFlags : uint32_t { EXTENSION_FUNCTION = 1U << 18U, DUPLICATE_ASM = 1U << 19U, BRIDGE = 1U << 20U, + INSTANTIATE = 1U << 21U, + INVOKE = 1U << 22U, INTERNAL_PROTECTED = INTERNAL | PROTECTED, GETTER_OR_SETTER = GETTER | SETTER, diff --git a/ets2panda/compiler/lowering/ets/transformToStaticInvoke.cpp b/ets2panda/compiler/lowering/ets/transformToStaticInvoke.cpp new file mode 100644 index 0000000000..18b870a30b --- /dev/null +++ b/ets2panda/compiler/lowering/ets/transformToStaticInvoke.cpp @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2025 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 "checker/ETSchecker.h" +#include "varbinder/ETSBinder.h" +#include "transformToStaticInvoke.h" +#include +#include "compiler/lowering/util.h" + +namespace ark::es2panda::compiler { + +std::string_view TransformToStaticInvoke::Name() const +{ + return "TransformToStaticInvoke"; +} +bool TransformToStaticInvoke::IsNodeApplicable(ir::AstNode *const ast) +{ + return ast->IsCallExpression() && ast->AsCallExpression()->Callee()->IsIdentifier() && + (ast->AsCallExpression()->Signature()->HasSignatureFlag(checker::SignatureFlags::INSTANTIATE) || + ast->AsCallExpression()->Signature()->HasSignatureFlag(checker::SignatureFlags::INVOKE)); +} +void TransformToStaticInvoke::TransformCallable(ir::AstNode *const ast, public_lib::Context *ctx) +{ + checker::ETSChecker *const checker = ctx->GetChecker()->AsETSChecker(); + if (!IsNodeApplicable(ast)) { + return; + } + auto callExpr = ast->AsCallExpression(); + auto ident = callExpr->Callee()->AsIdentifier(); + std::string_view propertyName; + + if (callExpr->Signature()->HasSignatureFlag(checker::SignatureFlags::INSTANTIATE)) { + propertyName = compiler::Signatures::STATIC_INSTANTIATE_METHOD; + } else if (callExpr->Signature()->HasSignatureFlag(checker::SignatureFlags::INVOKE)) { + propertyName = compiler::Signatures::STATIC_INVOKE_METHOD; + } + + auto *classId = checker->AllocNode(ident->Name(), checker->Allocator()); + auto *methodId = checker->AllocNode(propertyName, checker->Allocator()); + + if (propertyName == compiler::Signatures::STATIC_INSTANTIATE_METHOD) { + methodId->SetVariable(ident->Variable()); + } else if (propertyName == compiler::Signatures::STATIC_INVOKE_METHOD) { + methodId->SetVariable(ident->Variable()); + } + + auto *transformedCallee = checker->AllocNode( + classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); + + classId->SetRange(ident->Range()); + methodId->SetRange(ident->Range()); + transformedCallee->SetRange(ident->Range()); + + transformedCallee->SetParent(callExpr); + callExpr->SetCallee(transformedCallee); + + if (callExpr->Signature()->HasSignatureFlag(checker::SignatureFlags::INSTANTIATE)) { + callExpr->Signature()->RemoveSignatureFlag(checker::SignatureFlags::INSTANTIATE); + auto *argExpr = checker->GenerateImplicitInstantiateArg(std::string(ident->Name())); + + argExpr->SetParent(callExpr); + argExpr->SetRange(ident->Range()); + + checker->VarBinder()->AsETSBinder()->HandleCustomNodes(argExpr); + + auto &arguments = callExpr->Arguments(); + arguments.insert(arguments.begin(), argExpr); + } + + Recheck(ctx->phaseManager, checker->VarBinder()->AsETSBinder(), checker, transformedCallee); +} +bool TransformToStaticInvoke::PerformForModule(public_lib::Context *ctx, parser::Program *program) +{ + ir::NodeTransformer handleTransformToStaticInvoke = [this, ctx](ir::AstNode *const ast) { + TransformCallable(ast, ctx); + return ast; + }; + + program->Ast()->TransformChildrenRecursively(handleTransformToStaticInvoke, Name()); + + return true; +} + +} // namespace ark::es2panda::compiler \ No newline at end of file diff --git a/ets2panda/compiler/lowering/ets/transformToStaticInvoke.h b/ets2panda/compiler/lowering/ets/transformToStaticInvoke.h new file mode 100644 index 0000000000..8f6e061350 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/transformToStaticInvoke.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2025 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. + */ + +#ifndef ES2PANDA_COMPILER_LOWERING_TRANSFORM_TO_STATIC_INVOKE_H +#define ES2PANDA_COMPILER_LOWERING_TRANSFORM_TO_STATIC_INVOKE_H + +#include "compiler/lowering/phase.h" + +namespace ark::es2panda::compiler { + +class TransformToStaticInvoke : public PhaseForBodies { +public: + std::string_view Name() const override; + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; + +private: + bool IsNodeApplicable(ir::AstNode *const ast); + void TransformCallable(ir::AstNode *const ast, public_lib::Context *ctx); +}; + +} // namespace ark::es2panda::compiler + +#endif // ES2PANDA_COMPILER_LOWERING_TRANSFORM_TO_STATIC_INVOKE_H \ No newline at end of file diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index be67b7ac50..a080e77a50 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -69,6 +69,7 @@ #include "compiler/lowering/ets/unboxLowering.h" #include "compiler/lowering/ets/unionLowering.h" #include "compiler/lowering/ets/typeFromLowering.h" +#include "compiler/lowering/ets/transformToStaticInvoke.h" #include "compiler/lowering/plugin_phase.h" #include "compiler/lowering/resolveIdentifiers.h" #include "compiler/lowering/scopesInit/scopesInitPhase.h" @@ -126,6 +127,7 @@ std::vector GetETSPhaseList() // pluginsAfterCheck has to go right after checkerPhase, nothing should be between them new PluginPhase {g_pluginsAfterCheck, ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}, // new ConvertPrimitiveCastMethodCall, + new TransformToStaticInvoke, // Can be only applied after checking phase and before lambda lowering new DynamicImport, new GradualTypeNarrowing, new AnnotationCopyPostLowering, -- Gitee