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, &params](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