13af6ab5fSopenharmony_ci/* 23af6ab5fSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License. 53af6ab5fSopenharmony_ci * You may obtain a copy of the License at 63af6ab5fSopenharmony_ci * 73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83af6ab5fSopenharmony_ci * 93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and 133af6ab5fSopenharmony_ci * limitations under the License. 143af6ab5fSopenharmony_ci */ 153af6ab5fSopenharmony_ci 163af6ab5fSopenharmony_ci#include "lambdaLowering.h" 173af6ab5fSopenharmony_ci 183af6ab5fSopenharmony_ci#include "checker/ets/typeRelationContext.h" 193af6ab5fSopenharmony_ci#include "compiler/lowering/scopesInit/scopesInitPhase.h" 203af6ab5fSopenharmony_ci#include "compiler/lowering/util.h" 213af6ab5fSopenharmony_ci 223af6ab5fSopenharmony_cinamespace ark::es2panda::compiler { 233af6ab5fSopenharmony_ci 243af6ab5fSopenharmony_cistruct LambdaInfo { 253af6ab5fSopenharmony_ci ir::ClassDeclaration *calleeClass = nullptr; 263af6ab5fSopenharmony_ci ir::ScriptFunction *enclosingFunction = nullptr; 273af6ab5fSopenharmony_ci util::StringView name = ""; 283af6ab5fSopenharmony_ci ArenaSet<varbinder::Variable *> *capturedVars = nullptr; 293af6ab5fSopenharmony_ci ir::Expression *callReceiver = nullptr; 303af6ab5fSopenharmony_ci}; 313af6ab5fSopenharmony_ci 323af6ab5fSopenharmony_cistruct CalleeMethodInfo { 333af6ab5fSopenharmony_ci util::StringView calleeName; 343af6ab5fSopenharmony_ci ir::AstNode *body = nullptr; 353af6ab5fSopenharmony_ci checker::Type *forcedReturnType = nullptr; 363af6ab5fSopenharmony_ci ir::ModifierFlags auxModifierFlags = ir::ModifierFlags::NONE; 373af6ab5fSopenharmony_ci ir::ScriptFunctionFlags auxFunctionFlags = ir::ScriptFunctionFlags::NONE; 383af6ab5fSopenharmony_ci}; 393af6ab5fSopenharmony_ci 403af6ab5fSopenharmony_cistruct LambdaClassInvokeInfo { 413af6ab5fSopenharmony_ci checker::Signature *lambdaSignature = nullptr; 423af6ab5fSopenharmony_ci ir::MethodDefinition *callee = nullptr; 433af6ab5fSopenharmony_ci ir::ClassDefinition *classDefinition = nullptr; 443af6ab5fSopenharmony_ci checker::Substitution *substitution = nullptr; 453af6ab5fSopenharmony_ci}; 463af6ab5fSopenharmony_ci 473af6ab5fSopenharmony_cistruct CalleeParameterInfo { 483af6ab5fSopenharmony_ci ir::ArrowFunctionExpression *lambda = nullptr; 493af6ab5fSopenharmony_ci ArenaSet<varbinder::Variable *> const &captured; 503af6ab5fSopenharmony_ci varbinder::ParamScope *paramScope = nullptr; 513af6ab5fSopenharmony_ci checker::Substitution *substitution = nullptr; 523af6ab5fSopenharmony_ci size_t limit = 0; 533af6ab5fSopenharmony_ci}; 543af6ab5fSopenharmony_ci 553af6ab5fSopenharmony_cistatic std::pair<ir::ClassDeclaration *, ir::ScriptFunction *> FindEnclosingClassAndFunction(ir::AstNode *ast) 563af6ab5fSopenharmony_ci{ 573af6ab5fSopenharmony_ci ir::ScriptFunction *function = nullptr; 583af6ab5fSopenharmony_ci for (ir::AstNode *curr = ast->Parent(); curr != nullptr; curr = curr->Parent()) { 593af6ab5fSopenharmony_ci if (curr->IsClassDeclaration()) { 603af6ab5fSopenharmony_ci return {curr->AsClassDeclaration(), function}; 613af6ab5fSopenharmony_ci } 623af6ab5fSopenharmony_ci if (curr->IsScriptFunction()) { 633af6ab5fSopenharmony_ci function = curr->AsScriptFunction(); 643af6ab5fSopenharmony_ci } 653af6ab5fSopenharmony_ci } 663af6ab5fSopenharmony_ci UNREACHABLE(); 673af6ab5fSopenharmony_ci} 683af6ab5fSopenharmony_ci 693af6ab5fSopenharmony_cistatic bool CheckIfNeedThis(ir::ArrowFunctionExpression const *lambda) 703af6ab5fSopenharmony_ci{ 713af6ab5fSopenharmony_ci return lambda->IsAnyChild([](ir::AstNode *ast) { return ast->IsThisExpression(); }); 723af6ab5fSopenharmony_ci} 733af6ab5fSopenharmony_ci 743af6ab5fSopenharmony_cistatic size_t g_calleeCount = 0; 753af6ab5fSopenharmony_ci 763af6ab5fSopenharmony_ci// Make calleeCount behaviour predictable 773af6ab5fSopenharmony_cistatic void ResetCalleeCount() 783af6ab5fSopenharmony_ci{ 793af6ab5fSopenharmony_ci g_calleeCount = 0; 803af6ab5fSopenharmony_ci} 813af6ab5fSopenharmony_ci 823af6ab5fSopenharmony_cistatic util::StringView CreateCalleeName(ArenaAllocator *allocator) 833af6ab5fSopenharmony_ci{ 843af6ab5fSopenharmony_ci auto name = util::UString(util::StringView("lambda$invoke$"), allocator); 853af6ab5fSopenharmony_ci name.Append(std::to_string(g_calleeCount++)); 863af6ab5fSopenharmony_ci return name.View(); 873af6ab5fSopenharmony_ci} 883af6ab5fSopenharmony_ci 893af6ab5fSopenharmony_cistatic std::pair<ir::TSTypeParameterDeclaration *, checker::Substitution *> CloneTypeParams( 903af6ab5fSopenharmony_ci public_lib::Context *ctx, ir::TSTypeParameterDeclaration *oldIrTypeParams, ir::ScriptFunction *enclosingFunction, 913af6ab5fSopenharmony_ci varbinder::Scope *enclosingScope) 923af6ab5fSopenharmony_ci{ 933af6ab5fSopenharmony_ci if (oldIrTypeParams == nullptr) { 943af6ab5fSopenharmony_ci return {nullptr, nullptr}; 953af6ab5fSopenharmony_ci } 963af6ab5fSopenharmony_ci 973af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 983af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 993af6ab5fSopenharmony_ci 1003af6ab5fSopenharmony_ci auto *newScope = allocator->New<varbinder::LocalScope>(allocator, enclosingScope); 1013af6ab5fSopenharmony_ci auto newTypeParams = ArenaVector<checker::ETSTypeParameter *>(allocator->Adapter()); 1023af6ab5fSopenharmony_ci auto newTypeParamNodes = ArenaVector<ir::TSTypeParameter *>(allocator->Adapter()); 1033af6ab5fSopenharmony_ci auto *substitution = checker->NewSubstitution(); 1043af6ab5fSopenharmony_ci 1053af6ab5fSopenharmony_ci for (size_t ix = 0; ix < oldIrTypeParams->Params().size(); ix++) { 1063af6ab5fSopenharmony_ci auto *oldTypeParamNode = oldIrTypeParams->Params()[ix]; 1073af6ab5fSopenharmony_ci auto *oldTypeParam = enclosingFunction->Signature()->TypeParams()[ix]->AsETSTypeParameter(); 1083af6ab5fSopenharmony_ci auto *newTypeParamId = allocator->New<ir::Identifier>(oldTypeParamNode->Name()->Name(), allocator); 1093af6ab5fSopenharmony_ci auto *newTypeParamNode = 1103af6ab5fSopenharmony_ci util::NodeAllocator::ForceSetParent<ir::TSTypeParameter>(allocator, newTypeParamId, nullptr, nullptr); 1113af6ab5fSopenharmony_ci auto *newTypeParam = allocator->New<checker::ETSTypeParameter>(); 1123af6ab5fSopenharmony_ci newTypeParam->SetDeclNode(newTypeParamNode); 1133af6ab5fSopenharmony_ci 1143af6ab5fSopenharmony_ci auto *newTypeParamDecl = allocator->New<varbinder::TypeParameterDecl>(newTypeParamId->Name()); 1153af6ab5fSopenharmony_ci newTypeParamDecl->BindNode(newTypeParamNode); 1163af6ab5fSopenharmony_ci auto *newTypeParamVar = 1173af6ab5fSopenharmony_ci allocator->New<varbinder::LocalVariable>(newTypeParamDecl, varbinder::VariableFlags::TYPE_PARAMETER); 1183af6ab5fSopenharmony_ci 1193af6ab5fSopenharmony_ci newTypeParamVar->SetTsType(newTypeParam); 1203af6ab5fSopenharmony_ci newScope->InsertBinding(newTypeParamId->Name(), newTypeParamVar); 1213af6ab5fSopenharmony_ci newTypeParamId->SetVariable(newTypeParamVar); 1223af6ab5fSopenharmony_ci 1233af6ab5fSopenharmony_ci newTypeParams.push_back(newTypeParam); 1243af6ab5fSopenharmony_ci newTypeParamNodes.push_back(newTypeParamNode); 1253af6ab5fSopenharmony_ci substitution->emplace(oldTypeParam, newTypeParam); 1263af6ab5fSopenharmony_ci } 1273af6ab5fSopenharmony_ci 1283af6ab5fSopenharmony_ci for (size_t ix = 0; ix < oldIrTypeParams->Params().size(); ix++) { 1293af6ab5fSopenharmony_ci auto *oldTypeParam = enclosingFunction->Signature()->TypeParams()[ix]->AsETSTypeParameter(); 1303af6ab5fSopenharmony_ci 1313af6ab5fSopenharmony_ci if (auto *oldConstraint = oldTypeParam->GetConstraintType(); oldConstraint != nullptr) { 1323af6ab5fSopenharmony_ci auto *newConstraint = oldConstraint->Substitute(checker->Relation(), substitution); 1333af6ab5fSopenharmony_ci newTypeParams[ix]->SetConstraintType(newConstraint); 1343af6ab5fSopenharmony_ci newTypeParamNodes[ix]->SetConstraint(allocator->New<ir::OpaqueTypeNode>(newConstraint)); 1353af6ab5fSopenharmony_ci newTypeParamNodes[ix]->Constraint()->SetParent(newTypeParamNodes[ix]); 1363af6ab5fSopenharmony_ci } 1373af6ab5fSopenharmony_ci if (auto *oldDefault = oldTypeParam->GetDefaultType(); oldDefault != nullptr) { 1383af6ab5fSopenharmony_ci auto *newDefault = oldDefault->Substitute(checker->Relation(), substitution); 1393af6ab5fSopenharmony_ci newTypeParams[ix]->SetDefaultType(newDefault); 1403af6ab5fSopenharmony_ci newTypeParamNodes[ix]->SetDefaultType(allocator->New<ir::OpaqueTypeNode>(newDefault)); 1413af6ab5fSopenharmony_ci newTypeParamNodes[ix]->DefaultType()->SetParent(newTypeParamNodes[ix]); 1423af6ab5fSopenharmony_ci } 1433af6ab5fSopenharmony_ci } 1443af6ab5fSopenharmony_ci 1453af6ab5fSopenharmony_ci auto *newIrTypeParams = util::NodeAllocator::ForceSetParent<ir::TSTypeParameterDeclaration>( 1463af6ab5fSopenharmony_ci allocator, std::move(newTypeParamNodes), oldIrTypeParams->RequiredParams()); 1473af6ab5fSopenharmony_ci newIrTypeParams->SetScope(newScope); 1483af6ab5fSopenharmony_ci 1493af6ab5fSopenharmony_ci return {newIrTypeParams, substitution}; 1503af6ab5fSopenharmony_ci} 1513af6ab5fSopenharmony_ci 1523af6ab5fSopenharmony_ciusing ParamsAndVarMap = 1533af6ab5fSopenharmony_ci std::pair<ArenaVector<ir::Expression *>, ArenaMap<varbinder::Variable *, varbinder::Variable *>>; 1543af6ab5fSopenharmony_ciParamsAndVarMap CreateLambdaCalleeParameters(public_lib::Context *ctx, const CalleeParameterInfo &calleeParameterInfo) 1553af6ab5fSopenharmony_ci{ 1563af6ab5fSopenharmony_ci auto allocator = ctx->allocator; 1573af6ab5fSopenharmony_ci auto checker = ctx->checker->AsETSChecker(); 1583af6ab5fSopenharmony_ci auto varBinder = ctx->checker->VarBinder(); 1593af6ab5fSopenharmony_ci auto resParams = ArenaVector<ir::Expression *>(allocator->Adapter()); 1603af6ab5fSopenharmony_ci auto varMap = ArenaMap<varbinder::Variable *, varbinder::Variable *>(allocator->Adapter()); 1613af6ab5fSopenharmony_ci 1623af6ab5fSopenharmony_ci auto paramLexScope = 1633af6ab5fSopenharmony_ci varbinder::LexicalScope<varbinder::ParamScope>::Enter(varBinder, calleeParameterInfo.paramScope); 1643af6ab5fSopenharmony_ci 1653af6ab5fSopenharmony_ci for (auto capturedVar : calleeParameterInfo.captured) { 1663af6ab5fSopenharmony_ci auto *newType = capturedVar->TsType()->Substitute(checker->Relation(), calleeParameterInfo.substitution); 1673af6ab5fSopenharmony_ci auto newId = util::NodeAllocator::ForceSetParent<ir::Identifier>( 1683af6ab5fSopenharmony_ci allocator, capturedVar->Name(), allocator->New<ir::OpaqueTypeNode>(newType), allocator); 1693af6ab5fSopenharmony_ci auto param = util::NodeAllocator::ForceSetParent<ir::ETSParameterExpression>(allocator, newId, nullptr); 1703af6ab5fSopenharmony_ci auto [_, var] = varBinder->AddParamDecl(param); 1713af6ab5fSopenharmony_ci (void)_; 1723af6ab5fSopenharmony_ci var->SetTsType(newType); 1733af6ab5fSopenharmony_ci var->SetScope(calleeParameterInfo.paramScope); 1743af6ab5fSopenharmony_ci param->SetVariable(var); 1753af6ab5fSopenharmony_ci param->SetTsType(newType); 1763af6ab5fSopenharmony_ci resParams.push_back(param); 1773af6ab5fSopenharmony_ci varMap[capturedVar] = var; 1783af6ab5fSopenharmony_ci } 1793af6ab5fSopenharmony_ci 1803af6ab5fSopenharmony_ci size_t i = 0; 1813af6ab5fSopenharmony_ci 1823af6ab5fSopenharmony_ci for (auto *oldParam : calleeParameterInfo.lambda->Function()->Params()) { 1833af6ab5fSopenharmony_ci if (i > calleeParameterInfo.limit) { 1843af6ab5fSopenharmony_ci break; 1853af6ab5fSopenharmony_ci } 1863af6ab5fSopenharmony_ci 1873af6ab5fSopenharmony_ci auto *oldParamType = oldParam->AsETSParameterExpression()->Ident()->TypeAnnotation()->TsType(); 1883af6ab5fSopenharmony_ci auto *newParamType = oldParamType->Substitute(checker->Relation(), calleeParameterInfo.substitution); 1893af6ab5fSopenharmony_ci auto *newParam = oldParam->AsETSParameterExpression()->Clone(allocator, nullptr); 1903af6ab5fSopenharmony_ci newParam->Ident()->SetVariable(nullptr); // Remove the cloned variable. 1913af6ab5fSopenharmony_ci auto [_, var] = varBinder->AddParamDecl(newParam); 1923af6ab5fSopenharmony_ci (void)_; 1933af6ab5fSopenharmony_ci var->SetTsType(newParamType); 1943af6ab5fSopenharmony_ci var->SetScope(calleeParameterInfo.paramScope); 1953af6ab5fSopenharmony_ci newParam->SetVariable(var); 1963af6ab5fSopenharmony_ci newParam->SetTsType(newParamType); 1973af6ab5fSopenharmony_ci newParam->Ident()->SetTsType(newParamType); 1983af6ab5fSopenharmony_ci resParams.push_back(newParam); 1993af6ab5fSopenharmony_ci varMap[oldParam->AsETSParameterExpression()->Variable()] = var; 2003af6ab5fSopenharmony_ci i++; 2013af6ab5fSopenharmony_ci } 2023af6ab5fSopenharmony_ci 2033af6ab5fSopenharmony_ci return {resParams, varMap}; 2043af6ab5fSopenharmony_ci} 2053af6ab5fSopenharmony_ci 2063af6ab5fSopenharmony_cistatic void ProcessCalleeMethodBody(ir::AstNode *body, checker::ETSChecker *checker, varbinder::Scope *paramScope, 2073af6ab5fSopenharmony_ci checker::Substitution *substitution, 2083af6ab5fSopenharmony_ci ArenaMap<varbinder::Variable *, varbinder::Variable *> const &varMap) 2093af6ab5fSopenharmony_ci{ 2103af6ab5fSopenharmony_ci if (body == nullptr || body->Scope() == nullptr) { 2113af6ab5fSopenharmony_ci return; 2123af6ab5fSopenharmony_ci } 2133af6ab5fSopenharmony_ci body->Scope()->SetParent(paramScope); 2143af6ab5fSopenharmony_ci body->IterateRecursively([&](ir::AstNode *node) { 2153af6ab5fSopenharmony_ci if (node->IsIdentifier()) { 2163af6ab5fSopenharmony_ci auto *id = node->AsIdentifier(); 2173af6ab5fSopenharmony_ci if (auto ref = varMap.find(id->Variable()); ref != varMap.end()) { 2183af6ab5fSopenharmony_ci id->SetVariable(ref->second); 2193af6ab5fSopenharmony_ci } 2203af6ab5fSopenharmony_ci } 2213af6ab5fSopenharmony_ci if (substitution == nullptr) { 2223af6ab5fSopenharmony_ci return; 2233af6ab5fSopenharmony_ci } 2243af6ab5fSopenharmony_ci if (node->IsTyped() && node->AsTyped()->TsType() != nullptr) { 2253af6ab5fSopenharmony_ci node->AsTyped()->SetTsType(node->AsTyped()->TsType()->Substitute(checker->Relation(), substitution)); 2263af6ab5fSopenharmony_ci } 2273af6ab5fSopenharmony_ci if (node->IsCallExpression()) { 2283af6ab5fSopenharmony_ci node->AsCallExpression()->SetSignature( 2293af6ab5fSopenharmony_ci node->AsCallExpression()->Signature()->Substitute(checker->Relation(), substitution)); 2303af6ab5fSopenharmony_ci } 2313af6ab5fSopenharmony_ci if (node->IsETSNewClassInstanceExpression()) { 2323af6ab5fSopenharmony_ci node->AsETSNewClassInstanceExpression()->SetSignature( 2333af6ab5fSopenharmony_ci node->AsETSNewClassInstanceExpression()->GetSignature()->Substitute(checker->Relation(), substitution)); 2343af6ab5fSopenharmony_ci } 2353af6ab5fSopenharmony_ci if (node->IsScriptFunction()) { 2363af6ab5fSopenharmony_ci node->AsScriptFunction()->SetSignature( 2373af6ab5fSopenharmony_ci node->AsScriptFunction()->Signature()->Substitute(checker->Relation(), substitution)); 2383af6ab5fSopenharmony_ci } 2393af6ab5fSopenharmony_ci if (node->IsVariableDeclarator()) { 2403af6ab5fSopenharmony_ci auto *id = node->AsVariableDeclarator()->Id(); 2413af6ab5fSopenharmony_ci id->Variable()->SetTsType(id->Variable()->TsType()->Substitute(checker->Relation(), substitution)); 2423af6ab5fSopenharmony_ci } 2433af6ab5fSopenharmony_ci }); 2443af6ab5fSopenharmony_ci} 2453af6ab5fSopenharmony_ci 2463af6ab5fSopenharmony_cistatic ir::MethodDefinition *SetUpCalleeMethod(public_lib::Context *ctx, LambdaInfo const *info, 2473af6ab5fSopenharmony_ci CalleeMethodInfo const *cmInfo, ir::ScriptFunction *func, 2483af6ab5fSopenharmony_ci varbinder::Scope *scopeForMethod, varbinder::Variable *variable) 2493af6ab5fSopenharmony_ci{ 2503af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 2513af6ab5fSopenharmony_ci auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); 2523af6ab5fSopenharmony_ci 2533af6ab5fSopenharmony_ci auto *calleeClass = info->calleeClass; 2543af6ab5fSopenharmony_ci auto *funcScope = func->Scope(); 2553af6ab5fSopenharmony_ci auto *paramScope = funcScope->ParamScope(); 2563af6ab5fSopenharmony_ci auto modifierFlags = ir::ModifierFlags::PUBLIC | 2573af6ab5fSopenharmony_ci (info->callReceiver != nullptr ? ir::ModifierFlags::NONE : ir::ModifierFlags::STATIC) | 2583af6ab5fSopenharmony_ci cmInfo->auxModifierFlags; 2593af6ab5fSopenharmony_ci 2603af6ab5fSopenharmony_ci auto *calleeNameId = allocator->New<ir::Identifier>(cmInfo->calleeName, allocator); 2613af6ab5fSopenharmony_ci func->SetIdent(calleeNameId); 2623af6ab5fSopenharmony_ci calleeNameId->SetParent(func); 2633af6ab5fSopenharmony_ci 2643af6ab5fSopenharmony_ci auto *calleeNameClone = calleeNameId->Clone(allocator, nullptr); 2653af6ab5fSopenharmony_ci auto *funcExpr = util::NodeAllocator::ForceSetParent<ir::FunctionExpression>(allocator, func); 2663af6ab5fSopenharmony_ci auto *method = util::NodeAllocator::ForceSetParent<ir::MethodDefinition>( 2673af6ab5fSopenharmony_ci allocator, ir::MethodDefinitionKind::METHOD, calleeNameClone, funcExpr, modifierFlags, allocator, false); 2683af6ab5fSopenharmony_ci calleeClass->Definition()->Body().push_back(method); 2693af6ab5fSopenharmony_ci method->SetParent(calleeClass->Definition()); 2703af6ab5fSopenharmony_ci 2713af6ab5fSopenharmony_ci if (variable == nullptr) { 2723af6ab5fSopenharmony_ci auto [_, var] = 2733af6ab5fSopenharmony_ci varBinder->NewVarDecl<varbinder::FunctionDecl>(func->Start(), allocator, cmInfo->calleeName, func); 2743af6ab5fSopenharmony_ci (void)_; 2753af6ab5fSopenharmony_ci var->AddFlag(varbinder::VariableFlags::METHOD); 2763af6ab5fSopenharmony_ci var->SetScope(scopeForMethod); 2773af6ab5fSopenharmony_ci func->Id()->SetVariable(var); 2783af6ab5fSopenharmony_ci method->Id()->SetVariable(var); 2793af6ab5fSopenharmony_ci if (info->callReceiver != nullptr) { 2803af6ab5fSopenharmony_ci auto paramScopeCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(varBinder, paramScope); 2813af6ab5fSopenharmony_ci varBinder->AddMandatoryParam(varbinder::TypedBinder::MANDATORY_PARAM_THIS); 2823af6ab5fSopenharmony_ci calleeClass->Definition()->TsType()->AsETSObjectType()->AddProperty<checker::PropertyType::INSTANCE_METHOD>( 2833af6ab5fSopenharmony_ci var->AsLocalVariable()); 2843af6ab5fSopenharmony_ci } else { 2853af6ab5fSopenharmony_ci calleeClass->Definition()->TsType()->AsETSObjectType()->AddProperty<checker::PropertyType::STATIC_METHOD>( 2863af6ab5fSopenharmony_ci var->AsLocalVariable()); 2873af6ab5fSopenharmony_ci } 2883af6ab5fSopenharmony_ci 2893af6ab5fSopenharmony_ci varbinder::BoundContext bctx {varBinder->GetRecordTable(), calleeClass->Definition(), true}; 2903af6ab5fSopenharmony_ci varBinder->ResolveReferencesForScopeWithContext(func, funcScope); 2913af6ab5fSopenharmony_ci 2923af6ab5fSopenharmony_ci auto checkerCtx = checker::SavedCheckerContext(ctx->checker, checker::CheckerStatus::IN_CLASS, 2933af6ab5fSopenharmony_ci calleeClass->Definition()->TsType()->AsETSObjectType()); 2943af6ab5fSopenharmony_ci method->Check(ctx->checker->AsETSChecker()); 2953af6ab5fSopenharmony_ci } else { 2963af6ab5fSopenharmony_ci func->Id()->SetVariable(variable); 2973af6ab5fSopenharmony_ci method->Id()->SetVariable(variable); 2983af6ab5fSopenharmony_ci method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); 2993af6ab5fSopenharmony_ci } 3003af6ab5fSopenharmony_ci 3013af6ab5fSopenharmony_ci return method; 3023af6ab5fSopenharmony_ci} 3033af6ab5fSopenharmony_ci 3043af6ab5fSopenharmony_cistatic varbinder::FunctionScope *GetAndApplyFunctionScope(public_lib::Context *ctx, LambdaInfo const *info, 3053af6ab5fSopenharmony_ci CalleeMethodInfo const *cmInfo, 3063af6ab5fSopenharmony_ci varbinder::ParamScope *paramScope, ir::ScriptFunction *func) 3073af6ab5fSopenharmony_ci{ 3083af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 3093af6ab5fSopenharmony_ci auto *funcScope = cmInfo->body == nullptr ? allocator->New<varbinder::FunctionScope>(allocator, paramScope) 3103af6ab5fSopenharmony_ci : (cmInfo->body->Scope() == nullptr 3113af6ab5fSopenharmony_ci ? allocator->New<varbinder::FunctionScope>(allocator, paramScope) 3123af6ab5fSopenharmony_ci : cmInfo->body->Scope()->AsFunctionScope()); 3133af6ab5fSopenharmony_ci funcScope->BindName(info->calleeClass->Definition()->TsType()->AsETSObjectType()->AssemblerName()); 3143af6ab5fSopenharmony_ci func->SetScope(funcScope); 3153af6ab5fSopenharmony_ci 3163af6ab5fSopenharmony_ci if (cmInfo->body != nullptr) { 3173af6ab5fSopenharmony_ci cmInfo->body->AsBlockStatement()->SetScope(funcScope); 3183af6ab5fSopenharmony_ci cmInfo->body->SetParent(func); 3193af6ab5fSopenharmony_ci } 3203af6ab5fSopenharmony_ci 3213af6ab5fSopenharmony_ci return funcScope; 3223af6ab5fSopenharmony_ci} 3233af6ab5fSopenharmony_ci 3243af6ab5fSopenharmony_cistatic ir::MethodDefinition *CreateCalleeMethod(public_lib::Context *ctx, ir::ArrowFunctionExpression *lambda, 3253af6ab5fSopenharmony_ci LambdaInfo const *info, CalleeMethodInfo const *cmInfo, 3263af6ab5fSopenharmony_ci size_t limit = std::numeric_limits<size_t>::max(), 3273af6ab5fSopenharmony_ci varbinder::Variable *variable = nullptr) 3283af6ab5fSopenharmony_ci{ 3293af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 3303af6ab5fSopenharmony_ci auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); 3313af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 3323af6ab5fSopenharmony_ci 3333af6ab5fSopenharmony_ci auto *classScope = info->calleeClass->Definition()->Scope()->AsClassScope(); 3343af6ab5fSopenharmony_ci 3353af6ab5fSopenharmony_ci auto *oldTypeParams = (info->enclosingFunction != nullptr) ? info->enclosingFunction->TypeParams() : nullptr; 3363af6ab5fSopenharmony_ci auto enclosingScope = 3373af6ab5fSopenharmony_ci info->callReceiver != nullptr ? classScope->InstanceMethodScope() : classScope->StaticMethodScope(); 3383af6ab5fSopenharmony_ci 3393af6ab5fSopenharmony_ci auto [newTypeParams, subst0] = CloneTypeParams(ctx, oldTypeParams, info->enclosingFunction, enclosingScope); 3403af6ab5fSopenharmony_ci auto *substitution = subst0; // NOTE(gogabr): needed to capture in a lambda later. 3413af6ab5fSopenharmony_ci auto *scopeForMethod = newTypeParams != nullptr ? newTypeParams->Scope() : enclosingScope; 3423af6ab5fSopenharmony_ci 3433af6ab5fSopenharmony_ci auto lexScope = varbinder::LexicalScope<varbinder::LocalScope>::Enter(varBinder, enclosingScope); 3443af6ab5fSopenharmony_ci auto paramScope = allocator->New<varbinder::FunctionParamScope>(allocator, scopeForMethod); 3453af6ab5fSopenharmony_ci 3463af6ab5fSopenharmony_ci CalleeParameterInfo cpi {lambda, *info->capturedVars, paramScope, substitution, limit}; 3473af6ab5fSopenharmony_ci 3483af6ab5fSopenharmony_ci auto [params, vMap] = CreateLambdaCalleeParameters(ctx, cpi); 3493af6ab5fSopenharmony_ci auto varMap = std::move(vMap); 3503af6ab5fSopenharmony_ci 3513af6ab5fSopenharmony_ci auto *returnType = 3523af6ab5fSopenharmony_ci cmInfo->forcedReturnType != nullptr 3533af6ab5fSopenharmony_ci ? cmInfo->forcedReturnType 3543af6ab5fSopenharmony_ci : lambda->Function()->Signature()->ReturnType()->Substitute(checker->Relation(), substitution); 3553af6ab5fSopenharmony_ci auto returnTypeAnnotation = allocator->New<ir::OpaqueTypeNode>(returnType); 3563af6ab5fSopenharmony_ci 3573af6ab5fSopenharmony_ci auto funcFlags = ir::ScriptFunctionFlags::METHOD | cmInfo->auxFunctionFlags; 3583af6ab5fSopenharmony_ci auto modifierFlags = ir::ModifierFlags::PUBLIC | 3593af6ab5fSopenharmony_ci (info->callReceiver != nullptr ? ir::ModifierFlags::NONE : ir::ModifierFlags::STATIC) | 3603af6ab5fSopenharmony_ci cmInfo->auxModifierFlags; 3613af6ab5fSopenharmony_ci 3623af6ab5fSopenharmony_ci auto func = util::NodeAllocator::ForceSetParent<ir::ScriptFunction>( 3633af6ab5fSopenharmony_ci allocator, allocator, 3643af6ab5fSopenharmony_ci ir::ScriptFunction::ScriptFunctionData { 3653af6ab5fSopenharmony_ci cmInfo->body, ir::FunctionSignature(newTypeParams, std::move(params), returnTypeAnnotation), funcFlags, 3663af6ab5fSopenharmony_ci modifierFlags}); 3673af6ab5fSopenharmony_ci auto funcScope = GetAndApplyFunctionScope(ctx, info, cmInfo, paramScope, func); 3683af6ab5fSopenharmony_ci ProcessCalleeMethodBody(cmInfo->body, checker, paramScope, substitution, varMap); 3693af6ab5fSopenharmony_ci 3703af6ab5fSopenharmony_ci for (auto *param : func->Params()) { 3713af6ab5fSopenharmony_ci param->SetParent(func); 3723af6ab5fSopenharmony_ci } 3733af6ab5fSopenharmony_ci 3743af6ab5fSopenharmony_ci // Bind the scopes 3753af6ab5fSopenharmony_ci funcScope->BindNode(func); 3763af6ab5fSopenharmony_ci paramScope->BindNode(func); 3773af6ab5fSopenharmony_ci funcScope->AssignParamScope(paramScope); 3783af6ab5fSopenharmony_ci paramScope->BindFunctionScope(funcScope); 3793af6ab5fSopenharmony_ci 3803af6ab5fSopenharmony_ci /* NOTE(gogabr): Why does function scope need to replicate bindings from param scope?. 3813af6ab5fSopenharmony_ci Keeping it for now. 3823af6ab5fSopenharmony_ci */ 3833af6ab5fSopenharmony_ci for (auto [ov, nv] : varMap) { 3843af6ab5fSopenharmony_ci ASSERT(ov->Name() == nv->Name()); 3853af6ab5fSopenharmony_ci auto name = ov->Name(); 3863af6ab5fSopenharmony_ci funcScope->EraseBinding(name); 3873af6ab5fSopenharmony_ci funcScope->InsertBinding(name, nv); 3883af6ab5fSopenharmony_ci } 3893af6ab5fSopenharmony_ci 3903af6ab5fSopenharmony_ci return SetUpCalleeMethod(ctx, info, cmInfo, func, scopeForMethod, variable); 3913af6ab5fSopenharmony_ci} 3923af6ab5fSopenharmony_ci 3933af6ab5fSopenharmony_cistatic ir::MethodDefinition *CreateCalleeDefault(public_lib::Context *ctx, ir::ArrowFunctionExpression *lambda, 3943af6ab5fSopenharmony_ci LambdaInfo const *info) 3953af6ab5fSopenharmony_ci{ 3963af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 3973af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 3983af6ab5fSopenharmony_ci auto *body = lambda->Function()->Body()->AsBlockStatement(); 3993af6ab5fSopenharmony_ci auto calleeName = lambda->Function()->IsAsyncFunc() 4003af6ab5fSopenharmony_ci ? (util::UString {checker::ETSChecker::GetAsyncImplName(info->name), allocator}).View() 4013af6ab5fSopenharmony_ci : info->name; 4023af6ab5fSopenharmony_ci auto *forcedReturnType = lambda->Function()->IsAsyncFunc() ? checker->GlobalETSNullishObjectType() : nullptr; 4033af6ab5fSopenharmony_ci 4043af6ab5fSopenharmony_ci CalleeMethodInfo cmInfo; 4053af6ab5fSopenharmony_ci cmInfo.calleeName = calleeName; 4063af6ab5fSopenharmony_ci cmInfo.body = body; 4073af6ab5fSopenharmony_ci cmInfo.forcedReturnType = forcedReturnType; 4083af6ab5fSopenharmony_ci auto *method = CreateCalleeMethod(ctx, lambda, info, &cmInfo); 4093af6ab5fSopenharmony_ci 4103af6ab5fSopenharmony_ci if (lambda->Function()->IsAsyncFunc()) { 4113af6ab5fSopenharmony_ci CalleeMethodInfo cmInfoAsync; 4123af6ab5fSopenharmony_ci cmInfoAsync.calleeName = info->name; 4133af6ab5fSopenharmony_ci cmInfoAsync.body = nullptr; 4143af6ab5fSopenharmony_ci cmInfoAsync.forcedReturnType = nullptr; 4153af6ab5fSopenharmony_ci cmInfoAsync.auxModifierFlags = ir::ModifierFlags::NATIVE; 4163af6ab5fSopenharmony_ci cmInfoAsync.auxFunctionFlags = ir::ScriptFunctionFlags::ASYNC; 4173af6ab5fSopenharmony_ci auto *asyncMethod = CreateCalleeMethod(ctx, lambda, info, &cmInfoAsync); 4183af6ab5fSopenharmony_ci return asyncMethod; 4193af6ab5fSopenharmony_ci } 4203af6ab5fSopenharmony_ci 4213af6ab5fSopenharmony_ci return method; 4223af6ab5fSopenharmony_ci} 4233af6ab5fSopenharmony_ci 4243af6ab5fSopenharmony_cistatic ArenaVector<ir::Expression *> CreateArgsForOptionalCall(public_lib::Context *ctx, 4253af6ab5fSopenharmony_ci ir::ArrowFunctionExpression *lambda, 4263af6ab5fSopenharmony_ci ir::MethodDefinition *defaultMethod) 4273af6ab5fSopenharmony_ci{ 4283af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 4293af6ab5fSopenharmony_ci 4303af6ab5fSopenharmony_ci ArenaVector<ir::Expression *> funcCallArgs(checker->Allocator()->Adapter()); 4313af6ab5fSopenharmony_ci funcCallArgs.reserve(defaultMethod->Function()->Params().size()); 4323af6ab5fSopenharmony_ci 4333af6ab5fSopenharmony_ci size_t i = 0; 4343af6ab5fSopenharmony_ci 4353af6ab5fSopenharmony_ci for (auto *param : defaultMethod->Function()->Params()) { 4363af6ab5fSopenharmony_ci if (!param->AsETSParameterExpression()->IsDefault()) { 4373af6ab5fSopenharmony_ci auto *paramName = 4383af6ab5fSopenharmony_ci param->AsETSParameterExpression()->Ident()->Clone(checker->Allocator(), nullptr)->AsIdentifier(); 4393af6ab5fSopenharmony_ci funcCallArgs.push_back(paramName); 4403af6ab5fSopenharmony_ci } else { 4413af6ab5fSopenharmony_ci break; 4423af6ab5fSopenharmony_ci } 4433af6ab5fSopenharmony_ci i++; 4443af6ab5fSopenharmony_ci } 4453af6ab5fSopenharmony_ci 4463af6ab5fSopenharmony_ci for (; i < lambda->Function()->Params().size(); i++) { 4473af6ab5fSopenharmony_ci auto *param = lambda->Function()->Params()[i]->AsETSParameterExpression(); 4483af6ab5fSopenharmony_ci if (param->Initializer() == nullptr) { 4493af6ab5fSopenharmony_ci checker->ThrowTypeError({"Expected initializer for parameter ", param->Ident()->Name(), "."}, 4503af6ab5fSopenharmony_ci param->Start()); 4513af6ab5fSopenharmony_ci } else { 4523af6ab5fSopenharmony_ci funcCallArgs.push_back(param->Initializer()); 4533af6ab5fSopenharmony_ci } 4543af6ab5fSopenharmony_ci } 4553af6ab5fSopenharmony_ci 4563af6ab5fSopenharmony_ci return funcCallArgs; 4573af6ab5fSopenharmony_ci} 4583af6ab5fSopenharmony_ci 4593af6ab5fSopenharmony_cistatic ir::BlockStatement *CreateFunctionBody(public_lib::Context *ctx, ir::ArrowFunctionExpression *lambda, 4603af6ab5fSopenharmony_ci ir::MethodDefinition *defaultMethod) 4613af6ab5fSopenharmony_ci{ 4623af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 4633af6ab5fSopenharmony_ci ArenaVector<ir::Statement *> statements(checker->Allocator()->Adapter()); 4643af6ab5fSopenharmony_ci ir::CallExpression *callExpression = nullptr; 4653af6ab5fSopenharmony_ci ir::Expression *id = nullptr; 4663af6ab5fSopenharmony_ci ir::Expression *accessor = nullptr; 4673af6ab5fSopenharmony_ci auto *const callee = checker->AllocNode<ir::Identifier>(defaultMethod->Id()->Name(), checker->Allocator()); 4683af6ab5fSopenharmony_ci callee->SetReference(); 4693af6ab5fSopenharmony_ci 4703af6ab5fSopenharmony_ci if (defaultMethod->IsStatic() && defaultMethod->Parent()->IsClassDefinition() && 4713af6ab5fSopenharmony_ci (!defaultMethod->Parent()->AsClassDefinition()->IsGlobal())) { 4723af6ab5fSopenharmony_ci id = checker->AllocNode<ir::Identifier>(defaultMethod->Parent()->AsClassDefinition()->Ident()->Name(), 4733af6ab5fSopenharmony_ci checker->Allocator()); 4743af6ab5fSopenharmony_ci id->AsIdentifier()->SetReference(); 4753af6ab5fSopenharmony_ci accessor = checker->AllocNode<ir::MemberExpression>(id, callee, ir::MemberExpressionKind::PROPERTY_ACCESS, 4763af6ab5fSopenharmony_ci false, false); 4773af6ab5fSopenharmony_ci callee->SetParent(accessor); 4783af6ab5fSopenharmony_ci } 4793af6ab5fSopenharmony_ci 4803af6ab5fSopenharmony_ci callExpression = checker->AllocNode<ir::CallExpression>(accessor != nullptr ? accessor : callee, 4813af6ab5fSopenharmony_ci CreateArgsForOptionalCall(ctx, lambda, defaultMethod), 4823af6ab5fSopenharmony_ci nullptr, false, false); 4833af6ab5fSopenharmony_ci callee->SetParent(callExpression); 4843af6ab5fSopenharmony_ci callExpression->SetSignature(defaultMethod->Function()->Signature()); 4853af6ab5fSopenharmony_ci 4863af6ab5fSopenharmony_ci if ((defaultMethod->Function()->ReturnTypeAnnotation() != nullptr) || 4873af6ab5fSopenharmony_ci ((defaultMethod->Function()->AsScriptFunction()->Flags() & ir::ScriptFunctionFlags::HAS_RETURN) != 0)) { 4883af6ab5fSopenharmony_ci statements.push_back(checker->AllocNode<ir::ReturnStatement>(callExpression)); 4893af6ab5fSopenharmony_ci } else { 4903af6ab5fSopenharmony_ci statements.push_back(checker->AllocNode<ir::ExpressionStatement>(callExpression)); 4913af6ab5fSopenharmony_ci } 4923af6ab5fSopenharmony_ci 4933af6ab5fSopenharmony_ci auto blockStatement = checker->AllocNode<ir::BlockStatement>(checker->Allocator(), std::move(statements)); 4943af6ab5fSopenharmony_ci blockStatement->Statements().front()->SetParent(blockStatement); 4953af6ab5fSopenharmony_ci 4963af6ab5fSopenharmony_ci return blockStatement; 4973af6ab5fSopenharmony_ci} 4983af6ab5fSopenharmony_ci 4993af6ab5fSopenharmony_cistatic ir::MethodDefinition *CreateCallee(public_lib::Context *ctx, ir::ArrowFunctionExpression *lambda, 5003af6ab5fSopenharmony_ci LambdaInfo const *info, ir::MethodDefinition *defaultMethod, 5013af6ab5fSopenharmony_ci size_t limit = std::numeric_limits<size_t>::max()) 5023af6ab5fSopenharmony_ci{ 5033af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 5043af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 5053af6ab5fSopenharmony_ci 5063af6ab5fSopenharmony_ci auto calleeName = lambda->Function()->IsAsyncFunc() 5073af6ab5fSopenharmony_ci ? (util::UString {checker::ETSChecker::GetAsyncImplName(info->name), allocator}).View() 5083af6ab5fSopenharmony_ci : info->name; 5093af6ab5fSopenharmony_ci auto *forcedReturnType = lambda->Function()->IsAsyncFunc() ? checker->GlobalETSNullishObjectType() : nullptr; 5103af6ab5fSopenharmony_ci 5113af6ab5fSopenharmony_ci CalleeMethodInfo cmInfo; 5123af6ab5fSopenharmony_ci cmInfo.calleeName = calleeName; 5133af6ab5fSopenharmony_ci cmInfo.body = CreateFunctionBody(ctx, lambda, defaultMethod); 5143af6ab5fSopenharmony_ci cmInfo.forcedReturnType = forcedReturnType; 5153af6ab5fSopenharmony_ci 5163af6ab5fSopenharmony_ci auto *method = CreateCalleeMethod(ctx, lambda, info, &cmInfo, limit, defaultMethod->Id()->Variable()); 5173af6ab5fSopenharmony_ci 5183af6ab5fSopenharmony_ci if (lambda->Function()->IsAsyncFunc()) { 5193af6ab5fSopenharmony_ci CalleeMethodInfo cmInfoAsync; 5203af6ab5fSopenharmony_ci cmInfoAsync.calleeName = info->name; 5213af6ab5fSopenharmony_ci cmInfoAsync.body = nullptr; 5223af6ab5fSopenharmony_ci cmInfoAsync.forcedReturnType = nullptr; 5233af6ab5fSopenharmony_ci cmInfoAsync.auxModifierFlags = ir::ModifierFlags::NATIVE; 5243af6ab5fSopenharmony_ci cmInfoAsync.auxFunctionFlags = ir::ScriptFunctionFlags::ASYNC; 5253af6ab5fSopenharmony_ci auto *asyncMethod = CreateCalleeMethod(ctx, lambda, info, &cmInfoAsync); 5263af6ab5fSopenharmony_ci return asyncMethod; 5273af6ab5fSopenharmony_ci } 5283af6ab5fSopenharmony_ci 5293af6ab5fSopenharmony_ci return method; 5303af6ab5fSopenharmony_ci} 5313af6ab5fSopenharmony_ci 5323af6ab5fSopenharmony_ci// The name "=t" used in extension methods has special meaning for the code generator; 5333af6ab5fSopenharmony_ci// avoid it as parameter and field name in our generated code. 5343af6ab5fSopenharmony_cistatic util::StringView AvoidMandatoryThis(util::StringView name) 5353af6ab5fSopenharmony_ci{ 5363af6ab5fSopenharmony_ci return (name == varbinder::TypedBinder::MANDATORY_PARAM_THIS) ? "$extensionThis" : name; 5373af6ab5fSopenharmony_ci} 5383af6ab5fSopenharmony_ci 5393af6ab5fSopenharmony_cistatic void CreateLambdaClassFields(public_lib::Context *ctx, ir::ClassDefinition *classDefinition, 5403af6ab5fSopenharmony_ci LambdaInfo const *info, checker::Substitution *substitution) 5413af6ab5fSopenharmony_ci{ 5423af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 5433af6ab5fSopenharmony_ci auto *parser = ctx->parser->AsETSParser(); 5443af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 5453af6ab5fSopenharmony_ci auto props = ArenaVector<ir::AstNode *>(allocator->Adapter()); 5463af6ab5fSopenharmony_ci 5473af6ab5fSopenharmony_ci if (info->callReceiver != nullptr) { 5483af6ab5fSopenharmony_ci auto *outerThisDeclaration = parser->CreateFormattedClassFieldDefinition( 5493af6ab5fSopenharmony_ci "@@I1: @@T2", "$this", 5503af6ab5fSopenharmony_ci info->calleeClass->Definition()->TsType()->Substitute(checker->Relation(), substitution)); 5513af6ab5fSopenharmony_ci props.push_back(outerThisDeclaration); 5523af6ab5fSopenharmony_ci } 5533af6ab5fSopenharmony_ci 5543af6ab5fSopenharmony_ci for (auto *captured : *info->capturedVars) { 5553af6ab5fSopenharmony_ci auto *varDeclaration = parser->CreateFormattedClassFieldDefinition( 5563af6ab5fSopenharmony_ci "@@I1: @@T2", AvoidMandatoryThis(captured->Name()), 5573af6ab5fSopenharmony_ci captured->TsType()->Substitute(checker->Relation(), substitution)); 5583af6ab5fSopenharmony_ci props.push_back(varDeclaration); 5593af6ab5fSopenharmony_ci } 5603af6ab5fSopenharmony_ci 5613af6ab5fSopenharmony_ci classDefinition->AddProperties(std::move(props)); 5623af6ab5fSopenharmony_ci} 5633af6ab5fSopenharmony_ci 5643af6ab5fSopenharmony_cistatic void CreateLambdaClassConstructor(public_lib::Context *ctx, ir::ClassDefinition *classDefinition, 5653af6ab5fSopenharmony_ci LambdaInfo const *info, checker::Substitution *substitution) 5663af6ab5fSopenharmony_ci{ 5673af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 5683af6ab5fSopenharmony_ci auto *parser = ctx->parser->AsETSParser(); 5693af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 5703af6ab5fSopenharmony_ci 5713af6ab5fSopenharmony_ci auto params = ArenaVector<ir::Expression *>(allocator->Adapter()); 5723af6ab5fSopenharmony_ci auto makeParam = [checker, allocator, substitution, ¶ms](util::StringView name, checker::Type *type) { 5733af6ab5fSopenharmony_ci auto *substitutedType = type->Substitute(checker->Relation(), substitution); 5743af6ab5fSopenharmony_ci auto *id = util::NodeAllocator::ForceSetParent<ir::Identifier>( 5753af6ab5fSopenharmony_ci allocator, name, allocator->New<ir::OpaqueTypeNode>(substitutedType), allocator); 5763af6ab5fSopenharmony_ci auto *param = util::NodeAllocator::ForceSetParent<ir::ETSParameterExpression>(allocator, id, nullptr); 5773af6ab5fSopenharmony_ci params.push_back(param); 5783af6ab5fSopenharmony_ci }; 5793af6ab5fSopenharmony_ci 5803af6ab5fSopenharmony_ci if (info->callReceiver != nullptr) { 5813af6ab5fSopenharmony_ci makeParam("$this", info->calleeClass->Definition()->TsType()); 5823af6ab5fSopenharmony_ci } 5833af6ab5fSopenharmony_ci for (auto *var : *info->capturedVars) { 5843af6ab5fSopenharmony_ci makeParam(AvoidMandatoryThis(var->Name()), var->TsType()); 5853af6ab5fSopenharmony_ci } 5863af6ab5fSopenharmony_ci 5873af6ab5fSopenharmony_ci auto bodyStmts = ArenaVector<ir::Statement *>(allocator->Adapter()); 5883af6ab5fSopenharmony_ci auto makeStatement = [&parser, &bodyStmts](util::StringView name) { 5893af6ab5fSopenharmony_ci auto adjustedName = AvoidMandatoryThis(name); 5903af6ab5fSopenharmony_ci auto *statement = parser->CreateFormattedStatement("this.@@I1 = @@I2", adjustedName, adjustedName); 5913af6ab5fSopenharmony_ci bodyStmts.push_back(statement); 5923af6ab5fSopenharmony_ci }; 5933af6ab5fSopenharmony_ci if (info->callReceiver != nullptr) { 5943af6ab5fSopenharmony_ci makeStatement("$this"); 5953af6ab5fSopenharmony_ci } 5963af6ab5fSopenharmony_ci for (auto *var : *info->capturedVars) { 5973af6ab5fSopenharmony_ci makeStatement(var->Name()); 5983af6ab5fSopenharmony_ci } 5993af6ab5fSopenharmony_ci auto *body = util::NodeAllocator::ForceSetParent<ir::BlockStatement>(allocator, allocator, std::move(bodyStmts)); 6003af6ab5fSopenharmony_ci 6013af6ab5fSopenharmony_ci auto *constructorId = allocator->New<ir::Identifier>("constructor", allocator); 6023af6ab5fSopenharmony_ci auto *constructorIdClone = constructorId->Clone(allocator, nullptr); 6033af6ab5fSopenharmony_ci 6043af6ab5fSopenharmony_ci auto *func = util::NodeAllocator::ForceSetParent<ir::ScriptFunction>( 6053af6ab5fSopenharmony_ci allocator, allocator, 6063af6ab5fSopenharmony_ci ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), nullptr), 6073af6ab5fSopenharmony_ci ir::ScriptFunctionFlags::CONSTRUCTOR | 6083af6ab5fSopenharmony_ci ir::ScriptFunctionFlags::IMPLICIT_SUPER_CALL_NEEDED}); 6093af6ab5fSopenharmony_ci func->SetIdent(constructorId); 6103af6ab5fSopenharmony_ci auto *funcExpr = util::NodeAllocator::ForceSetParent<ir::FunctionExpression>(allocator, func); 6113af6ab5fSopenharmony_ci 6123af6ab5fSopenharmony_ci auto *ctor = util::NodeAllocator::ForceSetParent<ir::MethodDefinition>( 6133af6ab5fSopenharmony_ci allocator, ir::MethodDefinitionKind::CONSTRUCTOR, constructorIdClone, funcExpr, ir::ModifierFlags::NONE, 6143af6ab5fSopenharmony_ci allocator, false); 6153af6ab5fSopenharmony_ci 6163af6ab5fSopenharmony_ci classDefinition->Body().push_back(ctor); 6173af6ab5fSopenharmony_ci ctor->SetParent(classDefinition); 6183af6ab5fSopenharmony_ci} 6193af6ab5fSopenharmony_ci 6203af6ab5fSopenharmony_cistatic ir::CallExpression *CreateCallForLambdaClassInvoke(public_lib::Context *ctx, LambdaInfo const *info, 6213af6ab5fSopenharmony_ci LambdaClassInvokeInfo const *lciInfo, bool wrapToObject) 6223af6ab5fSopenharmony_ci{ 6233af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 6243af6ab5fSopenharmony_ci auto *parser = ctx->parser->AsETSParser(); 6253af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 6263af6ab5fSopenharmony_ci 6273af6ab5fSopenharmony_ci auto callArguments = ArenaVector<ir::Expression *>(allocator->Adapter()); 6283af6ab5fSopenharmony_ci for (auto *captured : *info->capturedVars) { 6293af6ab5fSopenharmony_ci auto *arg = parser->CreateFormattedExpression("this.@@I1", AvoidMandatoryThis(captured->Name())); 6303af6ab5fSopenharmony_ci callArguments.push_back(arg); 6313af6ab5fSopenharmony_ci } 6323af6ab5fSopenharmony_ci for (auto *lambdaParam : lciInfo->lambdaSignature->Params()) { 6333af6ab5fSopenharmony_ci auto argName = lambdaParam->Name(); 6343af6ab5fSopenharmony_ci auto *type = lambdaParam->TsType()->Substitute(checker->Relation(), lciInfo->substitution); 6353af6ab5fSopenharmony_ci auto *arg = wrapToObject ? parser->CreateFormattedExpression("@@I1 as @@T2 as @@T3", argName, 6363af6ab5fSopenharmony_ci checker->MaybePromotedBuiltinType(type), type) 6373af6ab5fSopenharmony_ci : allocator->New<ir::Identifier>(argName, allocator); 6383af6ab5fSopenharmony_ci callArguments.push_back(arg); 6393af6ab5fSopenharmony_ci } 6403af6ab5fSopenharmony_ci 6413af6ab5fSopenharmony_ci ir::Expression *calleeReceiver; 6423af6ab5fSopenharmony_ci if (info->callReceiver != nullptr) { 6433af6ab5fSopenharmony_ci calleeReceiver = parser->CreateFormattedExpression("this.@@I1", "$this"); 6443af6ab5fSopenharmony_ci } else { 6453af6ab5fSopenharmony_ci calleeReceiver = lciInfo->callee->Parent()->AsClassDefinition()->Ident()->Clone(allocator, nullptr); 6463af6ab5fSopenharmony_ci } 6473af6ab5fSopenharmony_ci 6483af6ab5fSopenharmony_ci auto *calleeMemberExpr = util::NodeAllocator::ForceSetParent<ir::MemberExpression>( 6493af6ab5fSopenharmony_ci allocator, calleeReceiver, lciInfo->callee->Key()->Clone(allocator, nullptr)->AsExpression(), 6503af6ab5fSopenharmony_ci ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); 6513af6ab5fSopenharmony_ci auto *call = parser->CreateFormattedExpression("@@E1(@@[E2)", calleeMemberExpr, std::move(callArguments)) 6523af6ab5fSopenharmony_ci ->AsCallExpression(); 6533af6ab5fSopenharmony_ci 6543af6ab5fSopenharmony_ci if (lciInfo->classDefinition->TypeParams() != nullptr) { 6553af6ab5fSopenharmony_ci auto typeArgs = ArenaVector<ir::TypeNode *>(allocator->Adapter()); 6563af6ab5fSopenharmony_ci for (auto *tp : lciInfo->classDefinition->TypeParams()->Params()) { 6573af6ab5fSopenharmony_ci typeArgs.push_back(allocator->New<ir::OpaqueTypeNode>(tp->Name()->AsIdentifier()->Variable()->TsType())); 6583af6ab5fSopenharmony_ci } 6593af6ab5fSopenharmony_ci auto *typeArg = 6603af6ab5fSopenharmony_ci util::NodeAllocator::ForceSetParent<ir::TSTypeParameterInstantiation>(allocator, std::move(typeArgs)); 6613af6ab5fSopenharmony_ci call->SetTypeParams(typeArg); 6623af6ab5fSopenharmony_ci typeArg->SetParent(call); 6633af6ab5fSopenharmony_ci } 6643af6ab5fSopenharmony_ci 6653af6ab5fSopenharmony_ci return call; 6663af6ab5fSopenharmony_ci} 6673af6ab5fSopenharmony_ci 6683af6ab5fSopenharmony_cistatic void CreateLambdaClassInvoke(public_lib::Context *ctx, LambdaInfo const *info, 6693af6ab5fSopenharmony_ci LambdaClassInvokeInfo const *lciInfo, util::StringView methodName, 6703af6ab5fSopenharmony_ci bool wrapToObject) 6713af6ab5fSopenharmony_ci{ 6723af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 6733af6ab5fSopenharmony_ci auto *parser = ctx->parser->AsETSParser(); 6743af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 6753af6ab5fSopenharmony_ci auto *anyType = checker->GlobalETSNullishObjectType(); 6763af6ab5fSopenharmony_ci 6773af6ab5fSopenharmony_ci auto params = ArenaVector<ir::Expression *>(allocator->Adapter()); 6783af6ab5fSopenharmony_ci for (auto *lparam : lciInfo->lambdaSignature->Params()) { 6793af6ab5fSopenharmony_ci auto *type = wrapToObject ? anyType : lparam->TsType()->Substitute(checker->Relation(), lciInfo->substitution); 6803af6ab5fSopenharmony_ci auto *id = util::NodeAllocator::ForceSetParent<ir::Identifier>( 6813af6ab5fSopenharmony_ci allocator, lparam->Name(), allocator->New<ir::OpaqueTypeNode>(type), allocator); 6823af6ab5fSopenharmony_ci auto *param = util::NodeAllocator::ForceSetParent<ir::ETSParameterExpression>(allocator, id, nullptr); 6833af6ab5fSopenharmony_ci params.push_back(param); 6843af6ab5fSopenharmony_ci } 6853af6ab5fSopenharmony_ci 6863af6ab5fSopenharmony_ci auto *call = CreateCallForLambdaClassInvoke(ctx, info, lciInfo, wrapToObject); 6873af6ab5fSopenharmony_ci 6883af6ab5fSopenharmony_ci auto bodyStmts = ArenaVector<ir::Statement *>(allocator->Adapter()); 6893af6ab5fSopenharmony_ci if (lciInfo->lambdaSignature->ReturnType() == checker->GlobalVoidType()) { 6903af6ab5fSopenharmony_ci auto *callStmt = util::NodeAllocator::ForceSetParent<ir::ExpressionStatement>(allocator, call); 6913af6ab5fSopenharmony_ci bodyStmts.push_back(callStmt); 6923af6ab5fSopenharmony_ci if (wrapToObject) { 6933af6ab5fSopenharmony_ci auto *returnStmt = util::NodeAllocator::ForceSetParent<ir::ReturnStatement>( 6943af6ab5fSopenharmony_ci allocator, allocator->New<ir::UndefinedLiteral>()); 6953af6ab5fSopenharmony_ci bodyStmts.push_back(returnStmt); 6963af6ab5fSopenharmony_ci } 6973af6ab5fSopenharmony_ci } else { 6983af6ab5fSopenharmony_ci auto *returnExpr = wrapToObject ? parser->CreateFormattedExpression("@@E1 as @@T2", call, anyType) : call; 6993af6ab5fSopenharmony_ci auto *returnStmt = util::NodeAllocator::ForceSetParent<ir::ReturnStatement>(allocator, returnExpr); 7003af6ab5fSopenharmony_ci bodyStmts.push_back(returnStmt); 7013af6ab5fSopenharmony_ci } 7023af6ab5fSopenharmony_ci 7033af6ab5fSopenharmony_ci auto body = util::NodeAllocator::ForceSetParent<ir::BlockStatement>(allocator, allocator, std::move(bodyStmts)); 7043af6ab5fSopenharmony_ci auto *returnType2 = allocator->New<ir::OpaqueTypeNode>( 7053af6ab5fSopenharmony_ci wrapToObject ? anyType 7063af6ab5fSopenharmony_ci : lciInfo->lambdaSignature->ReturnType()->Substitute(checker->Relation(), lciInfo->substitution)); 7073af6ab5fSopenharmony_ci auto *func = util::NodeAllocator::ForceSetParent<ir::ScriptFunction>( 7083af6ab5fSopenharmony_ci allocator, allocator, 7093af6ab5fSopenharmony_ci ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), returnType2), 7103af6ab5fSopenharmony_ci ir::ScriptFunctionFlags::METHOD}); 7113af6ab5fSopenharmony_ci 7123af6ab5fSopenharmony_ci auto *invokeId = allocator->New<ir::Identifier>(methodName, allocator); 7133af6ab5fSopenharmony_ci func->SetIdent(invokeId); 7143af6ab5fSopenharmony_ci 7153af6ab5fSopenharmony_ci auto *funcExpr = util::NodeAllocator::ForceSetParent<ir::FunctionExpression>(allocator, func); 7163af6ab5fSopenharmony_ci 7173af6ab5fSopenharmony_ci auto *invokeIdClone = invokeId->Clone(allocator, nullptr); 7183af6ab5fSopenharmony_ci auto *invokeMethod = util::NodeAllocator::ForceSetParent<ir::MethodDefinition>( 7193af6ab5fSopenharmony_ci allocator, ir::MethodDefinitionKind::METHOD, invokeIdClone, funcExpr, ir::ModifierFlags::NONE, allocator, 7203af6ab5fSopenharmony_ci false); 7213af6ab5fSopenharmony_ci 7223af6ab5fSopenharmony_ci lciInfo->classDefinition->Body().push_back(invokeMethod); 7233af6ab5fSopenharmony_ci invokeMethod->SetParent(lciInfo->classDefinition); 7243af6ab5fSopenharmony_ci} 7253af6ab5fSopenharmony_ci 7263af6ab5fSopenharmony_cistatic std::string BuildLambdaClass(public_lib::Context *ctx, ArenaVector<checker::Signature *> &lambdaSigs, 7273af6ab5fSopenharmony_ci checker::Substitution *substitution, ArenaVector<checker::Type *> &funcInterfaces) 7283af6ab5fSopenharmony_ci{ 7293af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 7303af6ab5fSopenharmony_ci 7313af6ab5fSopenharmony_ci std::string stringBuilder = "final class @@I1 implements "; 7323af6ab5fSopenharmony_ci constexpr uint8_t OFF_SET = 2; 7333af6ab5fSopenharmony_ci 7343af6ab5fSopenharmony_ci for (size_t i = 0; i < lambdaSigs.size(); i++) { 7353af6ab5fSopenharmony_ci funcInterfaces.push_back(checker->FunctionTypeToFunctionalInterfaceType( 7363af6ab5fSopenharmony_ci lambdaSigs[i]->Substitute(checker->Relation(), substitution))); 7373af6ab5fSopenharmony_ci stringBuilder += "@@T" + std::to_string(i + OFF_SET) + ", "; 7383af6ab5fSopenharmony_ci } 7393af6ab5fSopenharmony_ci 7403af6ab5fSopenharmony_ci stringBuilder.pop_back(); 7413af6ab5fSopenharmony_ci stringBuilder.pop_back(); 7423af6ab5fSopenharmony_ci stringBuilder += " {}"; 7433af6ab5fSopenharmony_ci 7443af6ab5fSopenharmony_ci return stringBuilder; 7453af6ab5fSopenharmony_ci} 7463af6ab5fSopenharmony_ci 7473af6ab5fSopenharmony_cistatic ir::ClassDeclaration *CreateLambdaClass(public_lib::Context *ctx, ArenaVector<checker::Signature *> &lambdaSigs, 7483af6ab5fSopenharmony_ci ir::MethodDefinition *callee, LambdaInfo const *info) 7493af6ab5fSopenharmony_ci{ 7503af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 7513af6ab5fSopenharmony_ci auto *parser = ctx->parser->AsETSParser(); 7523af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 7533af6ab5fSopenharmony_ci auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); 7543af6ab5fSopenharmony_ci 7553af6ab5fSopenharmony_ci auto *oldTypeParams = (info->enclosingFunction != nullptr) ? info->enclosingFunction->TypeParams() : nullptr; 7563af6ab5fSopenharmony_ci auto [newTypeParams, subst0] = 7573af6ab5fSopenharmony_ci CloneTypeParams(ctx, oldTypeParams, info->enclosingFunction, ctx->parserProgram->GlobalClassScope()); 7583af6ab5fSopenharmony_ci auto *substitution = subst0; // NOTE(gogabr): needed to capture in a lambda later. 7593af6ab5fSopenharmony_ci 7603af6ab5fSopenharmony_ci auto lexScope = varbinder::LexicalScope<varbinder::Scope>::Enter(varBinder, ctx->parserProgram->GlobalClassScope()); 7613af6ab5fSopenharmony_ci 7623af6ab5fSopenharmony_ci auto lambdaClassName = util::UString {std::string_view {"LambdaObject-"}, allocator}; 7633af6ab5fSopenharmony_ci lambdaClassName.Append(info->calleeClass->Definition()->Ident()->Name()); 7643af6ab5fSopenharmony_ci lambdaClassName.Append("$"); 7653af6ab5fSopenharmony_ci lambdaClassName.Append(info->name); 7663af6ab5fSopenharmony_ci 7673af6ab5fSopenharmony_ci ArenaVector<checker::Type *> funcInterfaces(allocator->Adapter()); 7683af6ab5fSopenharmony_ci 7693af6ab5fSopenharmony_ci auto *classDeclaration = 7703af6ab5fSopenharmony_ci parser 7713af6ab5fSopenharmony_ci ->CreateFormattedTopLevelStatement(BuildLambdaClass(ctx, lambdaSigs, substitution, funcInterfaces), 7723af6ab5fSopenharmony_ci lambdaClassName, funcInterfaces) 7733af6ab5fSopenharmony_ci ->AsClassDeclaration(); 7743af6ab5fSopenharmony_ci auto *classDefinition = classDeclaration->Definition(); 7753af6ab5fSopenharmony_ci 7763af6ab5fSopenharmony_ci // Adjust the class definition compared to what the parser gives. 7773af6ab5fSopenharmony_ci classDefinition->Body().clear(); // remove the default empty constructor 7783af6ab5fSopenharmony_ci classDefinition->AddModifier(ir::ModifierFlags::PUBLIC | ir::ModifierFlags::FUNCTIONAL); 7793af6ab5fSopenharmony_ci if (newTypeParams != nullptr) { 7803af6ab5fSopenharmony_ci classDefinition->SetTypeParams(newTypeParams); 7813af6ab5fSopenharmony_ci newTypeParams->SetParent(classDefinition); 7823af6ab5fSopenharmony_ci } 7833af6ab5fSopenharmony_ci 7843af6ab5fSopenharmony_ci auto *program = varBinder->GetRecordTable()->Program(); 7853af6ab5fSopenharmony_ci program->Ast()->Statements().push_back(classDeclaration); 7863af6ab5fSopenharmony_ci classDeclaration->SetParent(program->Ast()); 7873af6ab5fSopenharmony_ci 7883af6ab5fSopenharmony_ci CreateLambdaClassFields(ctx, classDefinition, info, substitution); 7893af6ab5fSopenharmony_ci CreateLambdaClassConstructor(ctx, classDefinition, info, substitution); 7903af6ab5fSopenharmony_ci 7913af6ab5fSopenharmony_ci LambdaClassInvokeInfo lciInfo; 7923af6ab5fSopenharmony_ci lciInfo.callee = callee; 7933af6ab5fSopenharmony_ci lciInfo.classDefinition = classDefinition; 7943af6ab5fSopenharmony_ci lciInfo.substitution = substitution; 7953af6ab5fSopenharmony_ci 7963af6ab5fSopenharmony_ci for (auto it : lambdaSigs) { 7973af6ab5fSopenharmony_ci lciInfo.lambdaSignature = it; 7983af6ab5fSopenharmony_ci CreateLambdaClassInvoke(ctx, info, &lciInfo, "invoke0", true); 7993af6ab5fSopenharmony_ci CreateLambdaClassInvoke(ctx, info, &lciInfo, "invoke", false); 8003af6ab5fSopenharmony_ci } 8013af6ab5fSopenharmony_ci 8023af6ab5fSopenharmony_ci InitScopesPhaseETS::RunExternalNode(classDeclaration, varBinder); 8033af6ab5fSopenharmony_ci varBinder->ResolveReferencesForScopeWithContext(classDeclaration, varBinder->TopScope()); 8043af6ab5fSopenharmony_ci classDeclaration->Check(checker); 8053af6ab5fSopenharmony_ci 8063af6ab5fSopenharmony_ci return classDeclaration; 8073af6ab5fSopenharmony_ci} 8083af6ab5fSopenharmony_ci 8093af6ab5fSopenharmony_cistatic ir::ETSNewClassInstanceExpression *CreateConstructorCall(public_lib::Context *ctx, ir::AstNode *lambdaOrFuncRef, 8103af6ab5fSopenharmony_ci ir::ClassDeclaration *lambdaClass, 8113af6ab5fSopenharmony_ci LambdaInfo const *info) 8123af6ab5fSopenharmony_ci{ 8133af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 8143af6ab5fSopenharmony_ci auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); 8153af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 8163af6ab5fSopenharmony_ci 8173af6ab5fSopenharmony_ci auto args = ArenaVector<ir::Expression *>(allocator->Adapter()); 8183af6ab5fSopenharmony_ci if (info->callReceiver != nullptr) { 8193af6ab5fSopenharmony_ci args.push_back(info->callReceiver); 8203af6ab5fSopenharmony_ci } 8213af6ab5fSopenharmony_ci for (auto captured : *info->capturedVars) { 8223af6ab5fSopenharmony_ci auto *id = allocator->New<ir::Identifier>(captured->Name(), allocator); 8233af6ab5fSopenharmony_ci args.push_back(id); 8243af6ab5fSopenharmony_ci } 8253af6ab5fSopenharmony_ci 8263af6ab5fSopenharmony_ci checker::ETSObjectType *constructedType = lambdaClass->Definition()->TsType()->AsETSObjectType(); 8273af6ab5fSopenharmony_ci if (info->enclosingFunction != nullptr) { 8283af6ab5fSopenharmony_ci constructedType = constructedType->SubstituteArguments(checker->Relation(), 8293af6ab5fSopenharmony_ci info->enclosingFunction->Signature()->TypeParams()); 8303af6ab5fSopenharmony_ci } 8313af6ab5fSopenharmony_ci auto *newExpr = util::NodeAllocator::ForceSetParent<ir::ETSNewClassInstanceExpression>( 8323af6ab5fSopenharmony_ci allocator, allocator->New<ir::OpaqueTypeNode>(constructedType), std::move(args), nullptr); 8333af6ab5fSopenharmony_ci auto *lambdaOrFuncRefParent = lambdaOrFuncRef->Parent(); 8343af6ab5fSopenharmony_ci newExpr->SetParent(lambdaOrFuncRefParent); 8353af6ab5fSopenharmony_ci // NOTE(dslynko, #19869): Required for correct debug-info generation 8363af6ab5fSopenharmony_ci newExpr->SetRange(lambdaOrFuncRefParent != nullptr ? lambdaOrFuncRefParent->Range() : lambdaOrFuncRef->Range()); 8373af6ab5fSopenharmony_ci 8383af6ab5fSopenharmony_ci auto *nearestScope = NearestScope(lambdaOrFuncRef); 8393af6ab5fSopenharmony_ci auto lexScope = varbinder::LexicalScope<varbinder::Scope>::Enter(varBinder, nearestScope); 8403af6ab5fSopenharmony_ci varBinder->ResolveReferencesForScopeWithContext(newExpr, nearestScope); 8413af6ab5fSopenharmony_ci 8423af6ab5fSopenharmony_ci auto checkerCtx = checker::SavedCheckerContext(ctx->checker, checker::CheckerStatus::IN_CLASS, 8433af6ab5fSopenharmony_ci info->calleeClass->Definition()->TsType()->AsETSObjectType()); 8443af6ab5fSopenharmony_ci auto scopeCtx = checker::ScopeContext(ctx->checker, nearestScope); 8453af6ab5fSopenharmony_ci newExpr->Check(checker); 8463af6ab5fSopenharmony_ci 8473af6ab5fSopenharmony_ci return newExpr; 8483af6ab5fSopenharmony_ci} 8493af6ab5fSopenharmony_ci 8503af6ab5fSopenharmony_cistatic ir::AstNode *ConvertLambda(public_lib::Context *ctx, ir::ArrowFunctionExpression *lambda) 8513af6ab5fSopenharmony_ci{ 8523af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 8533af6ab5fSopenharmony_ci 8543af6ab5fSopenharmony_ci auto firstDefaultIndex = lambda->Function()->DefaultParamIndex(); 8553af6ab5fSopenharmony_ci 8563af6ab5fSopenharmony_ci LambdaInfo info; 8573af6ab5fSopenharmony_ci std::tie(info.calleeClass, info.enclosingFunction) = FindEnclosingClassAndFunction(lambda); 8583af6ab5fSopenharmony_ci info.name = CreateCalleeName(allocator); 8593af6ab5fSopenharmony_ci auto capturedVars = FindCaptured(allocator, lambda); 8603af6ab5fSopenharmony_ci info.capturedVars = &capturedVars; 8613af6ab5fSopenharmony_ci info.callReceiver = CheckIfNeedThis(lambda) ? allocator->New<ir::ThisExpression>() : nullptr; 8623af6ab5fSopenharmony_ci 8633af6ab5fSopenharmony_ci auto *callee = CreateCalleeDefault(ctx, lambda, &info); 8643af6ab5fSopenharmony_ci 8653af6ab5fSopenharmony_ci if (firstDefaultIndex < lambda->Function()->Params().size()) { 8663af6ab5fSopenharmony_ci for (size_t i = firstDefaultIndex; i < lambda->Function()->Params().size(); i++) { 8673af6ab5fSopenharmony_ci auto overload = CreateCallee(ctx, lambda, &info, callee, firstDefaultIndex); 8683af6ab5fSopenharmony_ci callee->AddOverload(overload); 8693af6ab5fSopenharmony_ci } 8703af6ab5fSopenharmony_ci } 8713af6ab5fSopenharmony_ci 8723af6ab5fSopenharmony_ci ASSERT(lambda->TsType()->IsETSFunctionType()); 8733af6ab5fSopenharmony_ci auto *lambdaType = lambda->TsType()->AsETSFunctionType(); 8743af6ab5fSopenharmony_ci auto *lambdaClass = CreateLambdaClass(ctx, lambdaType->CallSignatures(), callee, &info); 8753af6ab5fSopenharmony_ci auto *constructorCall = CreateConstructorCall(ctx, lambda, lambdaClass, &info); 8763af6ab5fSopenharmony_ci return constructorCall; 8773af6ab5fSopenharmony_ci} 8783af6ab5fSopenharmony_ci 8793af6ab5fSopenharmony_cistatic checker::Signature *GuessSignature(checker::ETSChecker *checker, ir::Expression *ast) 8803af6ab5fSopenharmony_ci{ 8813af6ab5fSopenharmony_ci ASSERT(ast->TsType()->IsETSFunctionType()); 8823af6ab5fSopenharmony_ci auto *type = ast->TsType()->AsETSFunctionType(); 8833af6ab5fSopenharmony_ci 8843af6ab5fSopenharmony_ci if (type->CallSignatures().size() == 1) { 8853af6ab5fSopenharmony_ci return type->CallSignatures()[0]; 8863af6ab5fSopenharmony_ci } 8873af6ab5fSopenharmony_ci 8883af6ab5fSopenharmony_ci if (!ast->Parent()->IsCallExpression()) { 8893af6ab5fSopenharmony_ci checker->ThrowTypeError( 8903af6ab5fSopenharmony_ci std::initializer_list<checker::TypeErrorMessageElement> {"Cannot deduce call signature"}, ast->Start()); 8913af6ab5fSopenharmony_ci } 8923af6ab5fSopenharmony_ci 8933af6ab5fSopenharmony_ci auto &args = ast->Parent()->AsCallExpression()->Arguments(); 8943af6ab5fSopenharmony_ci for (size_t ix = 0; ix < args.size(); ix++) { 8953af6ab5fSopenharmony_ci if (args[ix] != ast) { 8963af6ab5fSopenharmony_ci continue; 8973af6ab5fSopenharmony_ci } 8983af6ab5fSopenharmony_ci 8993af6ab5fSopenharmony_ci auto *argType = ast->Parent()->AsCallExpression()->Signature()->Params()[ix]->TsType(); 9003af6ab5fSopenharmony_ci checker::Signature *sigFound = nullptr; 9013af6ab5fSopenharmony_ci 9023af6ab5fSopenharmony_ci for (auto *sig : type->CallSignatures()) { 9033af6ab5fSopenharmony_ci auto *tmpFunType = checker->Allocator()->New<checker::ETSFunctionType>("", sig, checker->Allocator()); 9043af6ab5fSopenharmony_ci checker::AssignmentContext actx { 9053af6ab5fSopenharmony_ci checker->Relation(), ast, tmpFunType, argType, ast->Start(), {}, checker::TypeRelationFlag::NO_THROW}; 9063af6ab5fSopenharmony_ci if (!actx.IsAssignable()) { 9073af6ab5fSopenharmony_ci continue; 9083af6ab5fSopenharmony_ci } 9093af6ab5fSopenharmony_ci if (sigFound != nullptr) { 9103af6ab5fSopenharmony_ci // ambiguiuty 9113af6ab5fSopenharmony_ci checker->ThrowTypeError( 9123af6ab5fSopenharmony_ci std::initializer_list<checker::TypeErrorMessageElement> {"Cannot deduce call signature"}, 9133af6ab5fSopenharmony_ci ast->Start()); 9143af6ab5fSopenharmony_ci } 9153af6ab5fSopenharmony_ci sigFound = sig; 9163af6ab5fSopenharmony_ci } 9173af6ab5fSopenharmony_ci if (sigFound != nullptr) { 9183af6ab5fSopenharmony_ci return sigFound; 9193af6ab5fSopenharmony_ci } 9203af6ab5fSopenharmony_ci } 9213af6ab5fSopenharmony_ci 9223af6ab5fSopenharmony_ci checker->ThrowTypeError({"Cannot deduce call signature"}, ast->Start()); 9233af6ab5fSopenharmony_ci} 9243af6ab5fSopenharmony_ci 9253af6ab5fSopenharmony_cistatic ir::ArrowFunctionExpression *CreateWrappingLambda(public_lib::Context *ctx, ir::Expression *funcRef) 9263af6ab5fSopenharmony_ci{ 9273af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 9283af6ab5fSopenharmony_ci auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); 9293af6ab5fSopenharmony_ci auto *signature = GuessSignature(ctx->checker->AsETSChecker(), funcRef); 9303af6ab5fSopenharmony_ci 9313af6ab5fSopenharmony_ci auto *parent = funcRef->Parent(); 9323af6ab5fSopenharmony_ci 9333af6ab5fSopenharmony_ci ArenaVector<ir::Expression *> params {allocator->Adapter()}; 9343af6ab5fSopenharmony_ci for (auto *p : signature->Params()) { 9353af6ab5fSopenharmony_ci params.push_back(util::NodeAllocator::ForceSetParent<ir::ETSParameterExpression>( 9363af6ab5fSopenharmony_ci allocator, 9373af6ab5fSopenharmony_ci allocator->New<ir::Identifier>(p->Name(), allocator->New<ir::OpaqueTypeNode>(p->TsType()), allocator), 9383af6ab5fSopenharmony_ci nullptr)); 9393af6ab5fSopenharmony_ci } 9403af6ab5fSopenharmony_ci auto *func = util::NodeAllocator::ForceSetParent<ir::ScriptFunction>( 9413af6ab5fSopenharmony_ci allocator, allocator, 9423af6ab5fSopenharmony_ci ir::ScriptFunction::ScriptFunctionData { 9433af6ab5fSopenharmony_ci nullptr, 9443af6ab5fSopenharmony_ci ir::FunctionSignature {nullptr, std::move(params), 9453af6ab5fSopenharmony_ci allocator->New<ir::OpaqueTypeNode>(signature->ReturnType())}, 9463af6ab5fSopenharmony_ci ir::ScriptFunctionFlags::ARROW}); 9473af6ab5fSopenharmony_ci 9483af6ab5fSopenharmony_ci ArenaVector<ir::Statement *> bodyStmts {allocator->Adapter()}; 9493af6ab5fSopenharmony_ci ArenaVector<ir::Expression *> callArgs {allocator->Adapter()}; 9503af6ab5fSopenharmony_ci 9513af6ab5fSopenharmony_ci for (auto *p : func->Params()) { 9523af6ab5fSopenharmony_ci callArgs.push_back(p->AsETSParameterExpression()->Ident()->Clone(allocator, nullptr)); 9533af6ab5fSopenharmony_ci } 9543af6ab5fSopenharmony_ci auto *callExpr = util::NodeAllocator::ForceSetParent<ir::CallExpression>(allocator, funcRef, std::move(callArgs), 9553af6ab5fSopenharmony_ci nullptr, false); 9563af6ab5fSopenharmony_ci ir::Statement *stmt; 9573af6ab5fSopenharmony_ci if (signature->ReturnType() == ctx->checker->AsETSChecker()->GlobalVoidType()) { 9583af6ab5fSopenharmony_ci stmt = util::NodeAllocator::ForceSetParent<ir::ExpressionStatement>(allocator, callExpr); 9593af6ab5fSopenharmony_ci } else { 9603af6ab5fSopenharmony_ci stmt = util::NodeAllocator::ForceSetParent<ir::ReturnStatement>(allocator, callExpr); 9613af6ab5fSopenharmony_ci } 9623af6ab5fSopenharmony_ci bodyStmts.push_back(stmt); 9633af6ab5fSopenharmony_ci func->SetBody(util::NodeAllocator::ForceSetParent<ir::BlockStatement>(allocator, allocator, std::move(bodyStmts))); 9643af6ab5fSopenharmony_ci func->Body()->SetParent(func); 9653af6ab5fSopenharmony_ci auto *lambda = util::NodeAllocator::ForceSetParent<ir::ArrowFunctionExpression>(allocator, func); 9663af6ab5fSopenharmony_ci lambda->SetParent(parent); 9673af6ab5fSopenharmony_ci 9683af6ab5fSopenharmony_ci auto *nearestScope = NearestScope(lambda); 9693af6ab5fSopenharmony_ci auto lexScope = varbinder::LexicalScope<varbinder::Scope>::Enter(varBinder, nearestScope); 9703af6ab5fSopenharmony_ci InitScopesPhaseETS::RunExternalNode(lambda, varBinder); 9713af6ab5fSopenharmony_ci varBinder->ResolveReferencesForScopeWithContext(lambda, nearestScope); 9723af6ab5fSopenharmony_ci 9733af6ab5fSopenharmony_ci auto [enclosingClass, enclosingFun] = FindEnclosingClassAndFunction(parent); 9743af6ab5fSopenharmony_ci (void)enclosingFun; 9753af6ab5fSopenharmony_ci 9763af6ab5fSopenharmony_ci auto checkerCtx = checker::SavedCheckerContext(ctx->checker, checker::CheckerStatus::IN_CLASS, 9773af6ab5fSopenharmony_ci enclosingClass->Definition()->TsType()->AsETSObjectType()); 9783af6ab5fSopenharmony_ci auto scopeCtx = checker::ScopeContext(ctx->checker, nearestScope); 9793af6ab5fSopenharmony_ci lambda->Check(ctx->checker->AsETSChecker()); 9803af6ab5fSopenharmony_ci 9813af6ab5fSopenharmony_ci return lambda; 9823af6ab5fSopenharmony_ci} 9833af6ab5fSopenharmony_ci 9843af6ab5fSopenharmony_cistatic ir::AstNode *ConvertFunctionReference(public_lib::Context *ctx, ir::Expression *funcRef) 9853af6ab5fSopenharmony_ci{ 9863af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 9873af6ab5fSopenharmony_ci ASSERT(funcRef->IsIdentifier() || 9883af6ab5fSopenharmony_ci (funcRef->IsMemberExpression() && 9893af6ab5fSopenharmony_ci funcRef->AsMemberExpression()->Kind() == ir::MemberExpressionKind::PROPERTY_ACCESS && 9903af6ab5fSopenharmony_ci funcRef->AsMemberExpression()->Property()->IsIdentifier())); 9913af6ab5fSopenharmony_ci varbinder::Variable *var; 9923af6ab5fSopenharmony_ci if (funcRef->IsIdentifier()) { 9933af6ab5fSopenharmony_ci var = funcRef->AsIdentifier()->Variable(); 9943af6ab5fSopenharmony_ci } else { 9953af6ab5fSopenharmony_ci auto *mexpr = funcRef->AsMemberExpression(); 9963af6ab5fSopenharmony_ci // NOTE(gogabr): mexpr->PropVar() is a synthetic variable wwith no reference to the method definition. Why? 9973af6ab5fSopenharmony_ci var = mexpr->Object()->TsType()->AsETSObjectType()->GetProperty( 9983af6ab5fSopenharmony_ci mexpr->Property()->AsIdentifier()->Name(), 9993af6ab5fSopenharmony_ci checker::PropertySearchFlags::SEARCH_INSTANCE_METHOD | checker::PropertySearchFlags::SEARCH_STATIC_METHOD | 10003af6ab5fSopenharmony_ci checker::PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION); 10013af6ab5fSopenharmony_ci ASSERT(var != nullptr); 10023af6ab5fSopenharmony_ci } 10033af6ab5fSopenharmony_ci 10043af6ab5fSopenharmony_ci ASSERT(var->Declaration()->Node()->IsMethodDefinition()); 10053af6ab5fSopenharmony_ci auto *method = var->Declaration()->Node()->AsMethodDefinition(); 10063af6ab5fSopenharmony_ci 10073af6ab5fSopenharmony_ci if (method->IsPrivate() || method->IsProtected()) { 10083af6ab5fSopenharmony_ci // Direct reference to method will be impossible from the lambda class, so replace func ref with a lambda 10093af6ab5fSopenharmony_ci // that will translate to a proxy method 10103af6ab5fSopenharmony_ci auto *lam = CreateWrappingLambda(ctx, funcRef); 10113af6ab5fSopenharmony_ci return ConvertLambda(ctx, lam); 10123af6ab5fSopenharmony_ci } 10133af6ab5fSopenharmony_ci 10143af6ab5fSopenharmony_ci LambdaInfo info; 10153af6ab5fSopenharmony_ci info.calleeClass = method->Parent()->Parent()->AsClassDeclaration(); 10163af6ab5fSopenharmony_ci info.enclosingFunction = nullptr; 10173af6ab5fSopenharmony_ci info.name = CreateCalleeName(allocator); 10183af6ab5fSopenharmony_ci auto emptySet = ArenaSet<varbinder::Variable *>(allocator->Adapter()); 10193af6ab5fSopenharmony_ci info.capturedVars = &emptySet; 10203af6ab5fSopenharmony_ci if (method->IsStatic()) { 10213af6ab5fSopenharmony_ci info.callReceiver = nullptr; 10223af6ab5fSopenharmony_ci } else { 10233af6ab5fSopenharmony_ci ASSERT(funcRef->IsMemberExpression()); 10243af6ab5fSopenharmony_ci info.callReceiver = funcRef->AsMemberExpression()->Object(); 10253af6ab5fSopenharmony_ci } 10263af6ab5fSopenharmony_ci 10273af6ab5fSopenharmony_ci auto *signature = GuessSignature(ctx->checker->AsETSChecker(), funcRef); 10283af6ab5fSopenharmony_ci ArenaVector<checker::Signature *> signatures(allocator->Adapter()); 10293af6ab5fSopenharmony_ci signatures.push_back(signature); 10303af6ab5fSopenharmony_ci auto *lambdaClass = CreateLambdaClass(ctx, signatures, method, &info); 10313af6ab5fSopenharmony_ci auto *constructorCall = CreateConstructorCall(ctx, funcRef, lambdaClass, &info); 10323af6ab5fSopenharmony_ci return constructorCall; 10333af6ab5fSopenharmony_ci} 10343af6ab5fSopenharmony_ci 10353af6ab5fSopenharmony_cistatic bool IsFunctionOrMethodCall(ir::AstNode const *node) 10363af6ab5fSopenharmony_ci{ 10373af6ab5fSopenharmony_ci ASSERT(node->IsCallExpression()); 10383af6ab5fSopenharmony_ci auto const *callee = node->AsCallExpression()->Callee(); 10393af6ab5fSopenharmony_ci 10403af6ab5fSopenharmony_ci if (callee->TsType() != nullptr && callee->TsType()->IsETSExtensionFuncHelperType()) { 10413af6ab5fSopenharmony_ci return true; 10423af6ab5fSopenharmony_ci } 10433af6ab5fSopenharmony_ci 10443af6ab5fSopenharmony_ci if (callee->IsMemberExpression() && callee->AsMemberExpression()->Object()->TsType() != nullptr && 10453af6ab5fSopenharmony_ci (callee->AsMemberExpression()->Object()->TsType()->IsETSEnumType())) { 10463af6ab5fSopenharmony_ci return true; 10473af6ab5fSopenharmony_ci } 10483af6ab5fSopenharmony_ci 10493af6ab5fSopenharmony_ci varbinder::Variable *var = nullptr; 10503af6ab5fSopenharmony_ci if (callee->IsMemberExpression() && 10513af6ab5fSopenharmony_ci callee->AsMemberExpression()->Kind() == ir::MemberExpressionKind::PROPERTY_ACCESS) { 10523af6ab5fSopenharmony_ci var = callee->AsMemberExpression()->Property()->Variable(); 10533af6ab5fSopenharmony_ci } else if (callee->IsIdentifier()) { 10543af6ab5fSopenharmony_ci var = callee->AsIdentifier()->Variable(); 10553af6ab5fSopenharmony_ci } 10563af6ab5fSopenharmony_ci return var != nullptr && !checker::ETSChecker::IsVariableGetterSetter(var) && 10573af6ab5fSopenharmony_ci (var->Flags() & varbinder::VariableFlags::METHOD) != 0; 10583af6ab5fSopenharmony_ci} 10593af6ab5fSopenharmony_ci 10603af6ab5fSopenharmony_cistatic ir::AstNode *InsertInvokeCall(public_lib::Context *ctx, ir::CallExpression *call) 10613af6ab5fSopenharmony_ci{ 10623af6ab5fSopenharmony_ci auto *allocator = ctx->allocator; 10633af6ab5fSopenharmony_ci auto *checker = ctx->checker->AsETSChecker(); 10643af6ab5fSopenharmony_ci auto *varBinder = checker->VarBinder()->AsETSBinder(); 10653af6ab5fSopenharmony_ci 10663af6ab5fSopenharmony_ci auto *oldCallee = call->Callee(); 10673af6ab5fSopenharmony_ci auto *ifaceType = oldCallee->TsType() != nullptr && oldCallee->TsType()->IsETSObjectType() 10683af6ab5fSopenharmony_ci ? oldCallee->TsType()->AsETSObjectType() 10693af6ab5fSopenharmony_ci : checker->FunctionTypeToFunctionalInterfaceType(call->Signature()); 10703af6ab5fSopenharmony_ci if (ifaceType->IsETSDynamicType()) { 10713af6ab5fSopenharmony_ci return call; 10723af6ab5fSopenharmony_ci } 10733af6ab5fSopenharmony_ci auto *prop = ifaceType->GetProperty(checker::FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME, 10743af6ab5fSopenharmony_ci checker::PropertySearchFlags::SEARCH_INSTANCE_METHOD | 10753af6ab5fSopenharmony_ci checker::PropertySearchFlags::SEARCH_IN_INTERFACES); 10763af6ab5fSopenharmony_ci ASSERT(prop != nullptr); 10773af6ab5fSopenharmony_ci auto *invoke0Id = allocator->New<ir::Identifier>(checker::FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME, allocator); 10783af6ab5fSopenharmony_ci invoke0Id->SetTsType(prop->TsType()); 10793af6ab5fSopenharmony_ci invoke0Id->SetVariable(prop); 10803af6ab5fSopenharmony_ci 10813af6ab5fSopenharmony_ci auto *newCallee = util::NodeAllocator::ForceSetParent<ir::MemberExpression>( 10823af6ab5fSopenharmony_ci allocator, oldCallee, invoke0Id, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); 10833af6ab5fSopenharmony_ci newCallee->SetTsType(prop->TsType()); 10843af6ab5fSopenharmony_ci newCallee->SetObjectType(ifaceType); 10853af6ab5fSopenharmony_ci 10863af6ab5fSopenharmony_ci call->SetCallee(newCallee); 10873af6ab5fSopenharmony_ci call->SetSignature(prop->TsType()->AsETSFunctionType()->CallSignatures()[0]); 10883af6ab5fSopenharmony_ci 10893af6ab5fSopenharmony_ci /* NOTE(gogabr): argument types may have been spoiled by widening/narrowing conversions. 10903af6ab5fSopenharmony_ci Repair them here. 10913af6ab5fSopenharmony_ci In the future, make sure those conversions behave appropriately. 10923af6ab5fSopenharmony_ci */ 10933af6ab5fSopenharmony_ci for (auto *arg : call->Arguments()) { 10943af6ab5fSopenharmony_ci auto boxingFlags = arg->GetBoxingUnboxingFlags(); 10953af6ab5fSopenharmony_ci Recheck(varBinder, checker, arg); 10963af6ab5fSopenharmony_ci arg->SetBoxingUnboxingFlags(boxingFlags); 10973af6ab5fSopenharmony_ci // NOTE (psiket) Temporal solution 10983af6ab5fSopenharmony_ci if (arg->TsType()->IsETSEnumType()) { 10993af6ab5fSopenharmony_ci arg->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::BOX_TO_ENUM); 11003af6ab5fSopenharmony_ci } 11013af6ab5fSopenharmony_ci } 11023af6ab5fSopenharmony_ci 11033af6ab5fSopenharmony_ci return call; 11043af6ab5fSopenharmony_ci} 11053af6ab5fSopenharmony_ci 11063af6ab5fSopenharmony_cistatic bool IsRedirectingConstructorCall(ir::CallExpression *expr) 11073af6ab5fSopenharmony_ci{ 11083af6ab5fSopenharmony_ci return expr->Callee()->IsThisExpression() || expr->Callee()->IsSuperExpression(); 11093af6ab5fSopenharmony_ci} 11103af6ab5fSopenharmony_ci 11113af6ab5fSopenharmony_cistatic bool IsInCalleePosition(ir::Expression *expr) 11123af6ab5fSopenharmony_ci{ 11133af6ab5fSopenharmony_ci return expr->Parent()->IsCallExpression() && expr->Parent()->AsCallExpression()->Callee() == expr; 11143af6ab5fSopenharmony_ci} 11153af6ab5fSopenharmony_ci 11163af6ab5fSopenharmony_cistatic ir::AstNode *BuildLambdaClassWhenNeeded(public_lib::Context *ctx, ir::AstNode *node) 11173af6ab5fSopenharmony_ci{ 11183af6ab5fSopenharmony_ci if (node->IsArrowFunctionExpression()) { 11193af6ab5fSopenharmony_ci return ConvertLambda(ctx, node->AsArrowFunctionExpression()); 11203af6ab5fSopenharmony_ci } 11213af6ab5fSopenharmony_ci if (node->IsIdentifier()) { 11223af6ab5fSopenharmony_ci auto *id = node->AsIdentifier(); 11233af6ab5fSopenharmony_ci auto *var = id->Variable(); 11243af6ab5fSopenharmony_ci if (id->IsReference() && id->TsType() != nullptr && id->TsType()->IsETSFunctionType() && var != nullptr && 11253af6ab5fSopenharmony_ci var->Declaration()->IsFunctionDecl() && !IsInCalleePosition(id)) { 11263af6ab5fSopenharmony_ci return ConvertFunctionReference(ctx, id); 11273af6ab5fSopenharmony_ci } 11283af6ab5fSopenharmony_ci } 11293af6ab5fSopenharmony_ci if (node->IsMemberExpression()) { 11303af6ab5fSopenharmony_ci auto *mexpr = node->AsMemberExpression(); 11313af6ab5fSopenharmony_ci if (mexpr->Kind() == ir::MemberExpressionKind::PROPERTY_ACCESS && mexpr->TsType() != nullptr && 11323af6ab5fSopenharmony_ci mexpr->TsType()->IsETSFunctionType() && mexpr->Object()->TsType()->IsETSObjectType()) { 11333af6ab5fSopenharmony_ci ASSERT(mexpr->Property()->IsIdentifier()); 11343af6ab5fSopenharmony_ci auto *var = mexpr->Object()->TsType()->AsETSObjectType()->GetProperty( 11353af6ab5fSopenharmony_ci mexpr->Property()->AsIdentifier()->Name(), 11363af6ab5fSopenharmony_ci checker::PropertySearchFlags::SEARCH_INSTANCE_METHOD | 11373af6ab5fSopenharmony_ci checker::PropertySearchFlags::SEARCH_STATIC_METHOD | 11383af6ab5fSopenharmony_ci checker::PropertySearchFlags::DISALLOW_SYNTHETIC_METHOD_CREATION); 11393af6ab5fSopenharmony_ci if (var != nullptr && var->Declaration()->IsFunctionDecl() && !IsInCalleePosition(mexpr)) { 11403af6ab5fSopenharmony_ci return ConvertFunctionReference(ctx, mexpr); 11413af6ab5fSopenharmony_ci } 11423af6ab5fSopenharmony_ci } 11433af6ab5fSopenharmony_ci } 11443af6ab5fSopenharmony_ci return node; 11453af6ab5fSopenharmony_ci} 11463af6ab5fSopenharmony_ci 11473af6ab5fSopenharmony_cistatic void CallPerformForExtSources(LambdaConversionPhase *phase, public_lib::Context *ctx, parser::Program *program) 11483af6ab5fSopenharmony_ci{ 11493af6ab5fSopenharmony_ci auto *varBinder = ctx->checker->VarBinder()->AsETSBinder(); 11503af6ab5fSopenharmony_ci for (auto &[_, extPrograms] : program->ExternalSources()) { 11513af6ab5fSopenharmony_ci (void)_; 11523af6ab5fSopenharmony_ci for (auto *extProg : extPrograms) { 11533af6ab5fSopenharmony_ci varbinder::RecordTableContext bctx {varBinder, extProg}; 11543af6ab5fSopenharmony_ci phase->Perform(ctx, extProg); 11553af6ab5fSopenharmony_ci } 11563af6ab5fSopenharmony_ci } 11573af6ab5fSopenharmony_ci} 11583af6ab5fSopenharmony_ci 11593af6ab5fSopenharmony_cibool LambdaConversionPhase::Perform(public_lib::Context *ctx, parser::Program *program) 11603af6ab5fSopenharmony_ci{ 11613af6ab5fSopenharmony_ci parser::SavedFormattingFileName savedFormattingName(ctx->parser->AsETSParser(), "lambda-conversion"); 11623af6ab5fSopenharmony_ci 11633af6ab5fSopenharmony_ci // For reproducibility of results when several compilation sessions are executed during 11643af6ab5fSopenharmony_ci // the same process's lifetime. 11653af6ab5fSopenharmony_ci if (program == ctx->parserProgram) { 11663af6ab5fSopenharmony_ci ResetCalleeCount(); 11673af6ab5fSopenharmony_ci } 11683af6ab5fSopenharmony_ci 11693af6ab5fSopenharmony_ci if (ctx->config->options->CompilerOptions().compilationMode == CompilationMode::GEN_STD_LIB) { 11703af6ab5fSopenharmony_ci CallPerformForExtSources(this, ctx, program); 11713af6ab5fSopenharmony_ci } 11723af6ab5fSopenharmony_ci 11733af6ab5fSopenharmony_ci program->Ast()->TransformChildrenRecursivelyPostorder( 11743af6ab5fSopenharmony_ci [ctx](ir::AstNode *node) { return BuildLambdaClassWhenNeeded(ctx, node); }, Name()); 11753af6ab5fSopenharmony_ci 11763af6ab5fSopenharmony_ci auto insertInvokeIfNeeded = [ctx](ir::AstNode *node) { 11773af6ab5fSopenharmony_ci if (node->IsCallExpression() && !IsFunctionOrMethodCall(node) && 11783af6ab5fSopenharmony_ci !IsRedirectingConstructorCall(node->AsCallExpression())) { 11793af6ab5fSopenharmony_ci return InsertInvokeCall(ctx, node->AsCallExpression()); 11803af6ab5fSopenharmony_ci } 11813af6ab5fSopenharmony_ci return node; 11823af6ab5fSopenharmony_ci }; 11833af6ab5fSopenharmony_ci program->Ast()->TransformChildrenRecursively(insertInvokeIfNeeded, Name()); 11843af6ab5fSopenharmony_ci 11853af6ab5fSopenharmony_ci return true; 11863af6ab5fSopenharmony_ci} 11873af6ab5fSopenharmony_ci 11883af6ab5fSopenharmony_cibool LambdaConversionPhase::Postcondition([[maybe_unused]] public_lib::Context *ctx, parser::Program const *program) 11893af6ab5fSopenharmony_ci{ 11903af6ab5fSopenharmony_ci return !program->Ast()->IsAnyChild([](ir::AstNode const *node) { return node->IsArrowFunctionExpression(); }); 11913af6ab5fSopenharmony_ci} 11923af6ab5fSopenharmony_ci 11933af6ab5fSopenharmony_ci} // namespace ark::es2panda::compiler 1194