13af6ab5fSopenharmony_ci/*
23af6ab5fSopenharmony_ci * Copyright (c) 2021-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 "ETSAnalyzerHelpers.h"
173af6ab5fSopenharmony_ci#include "checker/types/ets/etsAsyncFuncReturnType.h"
183af6ab5fSopenharmony_ci
193af6ab5fSopenharmony_cinamespace ark::es2panda::checker {
203af6ab5fSopenharmony_civoid CheckExtensionIsShadowedInCurrentClassOrInterface(checker::ETSChecker *checker, checker::ETSObjectType *objType,
213af6ab5fSopenharmony_ci                                                       ir::ScriptFunction *extensionFunc, checker::Signature *signature)
223af6ab5fSopenharmony_ci{
233af6ab5fSopenharmony_ci    const auto methodName = extensionFunc->Id()->Name();
243af6ab5fSopenharmony_ci    // Only check if there are class and interfaces' instance methods which would shadow instance extension method
253af6ab5fSopenharmony_ci    auto *const variable = objType->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>(methodName);
263af6ab5fSopenharmony_ci    if (variable == nullptr) {
273af6ab5fSopenharmony_ci        return;
283af6ab5fSopenharmony_ci    }
293af6ab5fSopenharmony_ci
303af6ab5fSopenharmony_ci    const auto *const funcType = variable->TsType()->AsETSFunctionType();
313af6ab5fSopenharmony_ci    for (auto *funcSignature : funcType->CallSignatures()) {
323af6ab5fSopenharmony_ci        signature->SetReturnType(funcSignature->ReturnType());
333af6ab5fSopenharmony_ci        if (!checker->Relation()->IsCompatibleTo(signature, funcSignature)) {
343af6ab5fSopenharmony_ci            continue;
353af6ab5fSopenharmony_ci        }
363af6ab5fSopenharmony_ci
373af6ab5fSopenharmony_ci        checker->ReportWarning({"extension is shadowed by a instance member function '", funcType->Name(),
383af6ab5fSopenharmony_ci                                funcSignature, "' in class ", objType->Name()},
393af6ab5fSopenharmony_ci                               extensionFunc->Body()->Start());
403af6ab5fSopenharmony_ci        return;
413af6ab5fSopenharmony_ci    }
423af6ab5fSopenharmony_ci}
433af6ab5fSopenharmony_ci
443af6ab5fSopenharmony_civoid CheckExtensionIsShadowedByMethod(checker::ETSChecker *checker, checker::ETSObjectType *objType,
453af6ab5fSopenharmony_ci                                      ir::ScriptFunction *extensionFunc, checker::Signature *signature)
463af6ab5fSopenharmony_ci{
473af6ab5fSopenharmony_ci    if (objType == nullptr) {
483af6ab5fSopenharmony_ci        return;
493af6ab5fSopenharmony_ci    }
503af6ab5fSopenharmony_ci
513af6ab5fSopenharmony_ci    CheckExtensionIsShadowedInCurrentClassOrInterface(checker, objType, extensionFunc, signature);
523af6ab5fSopenharmony_ci
533af6ab5fSopenharmony_ci    for (auto *interface : objType->Interfaces()) {
543af6ab5fSopenharmony_ci        CheckExtensionIsShadowedByMethod(checker, interface, extensionFunc, signature);
553af6ab5fSopenharmony_ci    }
563af6ab5fSopenharmony_ci
573af6ab5fSopenharmony_ci    CheckExtensionIsShadowedByMethod(checker, objType->SuperType(), extensionFunc, signature);
583af6ab5fSopenharmony_ci}
593af6ab5fSopenharmony_ci
603af6ab5fSopenharmony_cistatic void ReplaceThisInExtensionMethod(checker::ETSChecker *checker, ir::ScriptFunction *extensionFunc)
613af6ab5fSopenharmony_ci{
623af6ab5fSopenharmony_ci    ASSERT(!extensionFunc->Params().empty());
633af6ab5fSopenharmony_ci    ASSERT(extensionFunc->Params()[0]->AsETSParameterExpression()->Ident()->Name() ==
643af6ab5fSopenharmony_ci           varbinder::TypedBinder::MANDATORY_PARAM_THIS);
653af6ab5fSopenharmony_ci    auto thisVariable = extensionFunc->Params()[0]->Variable();
663af6ab5fSopenharmony_ci    extensionFunc->Body()->TransformChildrenRecursively(
673af6ab5fSopenharmony_ci        [=](ir::AstNode *ast) {
683af6ab5fSopenharmony_ci            if (ast->IsThisExpression()) {
693af6ab5fSopenharmony_ci                auto *thisParam = checker->Allocator()->New<ir::Identifier>(
703af6ab5fSopenharmony_ci                    varbinder::TypedBinder::MANDATORY_PARAM_THIS, checker->Allocator());
713af6ab5fSopenharmony_ci                thisParam->SetParent(ast->Parent());
723af6ab5fSopenharmony_ci                thisParam->SetVariable(thisVariable);
733af6ab5fSopenharmony_ci                return static_cast<ir::AstNode *>(thisParam);
743af6ab5fSopenharmony_ci            }
753af6ab5fSopenharmony_ci            return ast;
763af6ab5fSopenharmony_ci        },
773af6ab5fSopenharmony_ci        "replace-this-in-extension-method");
783af6ab5fSopenharmony_ci}
793af6ab5fSopenharmony_ci
803af6ab5fSopenharmony_civoid CheckExtensionMethod(checker::ETSChecker *checker, ir::ScriptFunction *extensionFunc, ir::MethodDefinition *node)
813af6ab5fSopenharmony_ci{
823af6ab5fSopenharmony_ci    auto *const classType = checker->GetApparentType(extensionFunc->Signature()->Params()[0]->TsType());
833af6ab5fSopenharmony_ci    if (!classType->IsETSObjectType() ||
843af6ab5fSopenharmony_ci        (!classType->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::CLASS) &&
853af6ab5fSopenharmony_ci         !classType->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::INTERFACE))) {
863af6ab5fSopenharmony_ci        checker->LogTypeError("Extension function can only defined for class and interface type.", node->Start());
873af6ab5fSopenharmony_ci    }
883af6ab5fSopenharmony_ci    if (classType->Variable()->Declaration()->Node()->IsClassDefinition() &&
893af6ab5fSopenharmony_ci        !classType->Variable()->Declaration()->Node()->AsClassDefinition()->IsClassDefinitionChecked()) {
903af6ab5fSopenharmony_ci        classType->Variable()->Declaration()->Node()->Check(checker);
913af6ab5fSopenharmony_ci    }
923af6ab5fSopenharmony_ci
933af6ab5fSopenharmony_ci    // NOTE(gogabr): should be done in a lowering
943af6ab5fSopenharmony_ci    ReplaceThisInExtensionMethod(checker, extensionFunc);
953af6ab5fSopenharmony_ci
963af6ab5fSopenharmony_ci    checker::SignatureInfo *originalExtensionSigInfo = checker->Allocator()->New<checker::SignatureInfo>(
973af6ab5fSopenharmony_ci        extensionFunc->Signature()->GetSignatureInfo(), checker->Allocator());
983af6ab5fSopenharmony_ci    originalExtensionSigInfo->minArgCount -= 1;
993af6ab5fSopenharmony_ci    originalExtensionSigInfo->params.erase(originalExtensionSigInfo->params.begin());
1003af6ab5fSopenharmony_ci    checker::Signature *originalExtensionSigature =
1013af6ab5fSopenharmony_ci        checker->CreateSignature(originalExtensionSigInfo, extensionFunc->Signature()->ReturnType(), extensionFunc);
1023af6ab5fSopenharmony_ci
1033af6ab5fSopenharmony_ci    CheckExtensionIsShadowedByMethod(checker, classType->AsETSObjectType(), extensionFunc, originalExtensionSigature);
1043af6ab5fSopenharmony_ci}
1053af6ab5fSopenharmony_ci
1063af6ab5fSopenharmony_civoid DoBodyTypeChecking(ETSChecker *checker, ir::MethodDefinition *node, ir::ScriptFunction *scriptFunc)
1073af6ab5fSopenharmony_ci{
1083af6ab5fSopenharmony_ci    if (scriptFunc->HasBody() && (node->IsNative() || node->IsAbstract() || node->IsDeclare())) {
1093af6ab5fSopenharmony_ci        checker->LogTypeError("Native, Abstract and Declare methods cannot have body.", scriptFunc->Body()->Start());
1103af6ab5fSopenharmony_ci    }
1113af6ab5fSopenharmony_ci
1123af6ab5fSopenharmony_ci    if (!scriptFunc->IsAsyncFunc() && scriptFunc->HasBody() &&
1133af6ab5fSopenharmony_ci        (!scriptFunc->IsExternal() || scriptFunc->IsExternalOverload())) {
1143af6ab5fSopenharmony_ci        checker::ScopeContext scopeCtx(checker, scriptFunc->Scope());
1153af6ab5fSopenharmony_ci        checker::SavedCheckerContext savedContext(checker, checker->Context().Status(),
1163af6ab5fSopenharmony_ci                                                  checker->Context().ContainingClass());
1173af6ab5fSopenharmony_ci        checker->Context().SetContainingSignature(checker->GetSignatureFromMethodDefinition(node));
1183af6ab5fSopenharmony_ci
1193af6ab5fSopenharmony_ci        if (node->IsStatic() && !node->IsConstructor() &&
1203af6ab5fSopenharmony_ci            !checker->Context().ContainingClass()->HasObjectFlag(checker::ETSObjectFlags::GLOBAL)) {
1213af6ab5fSopenharmony_ci            checker->AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT);
1223af6ab5fSopenharmony_ci        }
1233af6ab5fSopenharmony_ci
1243af6ab5fSopenharmony_ci        if (node->IsConstructor()) {
1253af6ab5fSopenharmony_ci            checker->AddStatus(checker::CheckerStatus::IN_CONSTRUCTOR);
1263af6ab5fSopenharmony_ci        }
1273af6ab5fSopenharmony_ci
1283af6ab5fSopenharmony_ci        if (node->IsExtensionMethod()) {
1293af6ab5fSopenharmony_ci            CheckExtensionMethod(checker, scriptFunc, node);
1303af6ab5fSopenharmony_ci        }
1313af6ab5fSopenharmony_ci
1323af6ab5fSopenharmony_ci        scriptFunc->Body()->Check(checker);
1333af6ab5fSopenharmony_ci
1343af6ab5fSopenharmony_ci        if (scriptFunc->ReturnTypeAnnotation() == nullptr) {
1353af6ab5fSopenharmony_ci            if (scriptFunc->IsAsyncImplFunc()) {
1363af6ab5fSopenharmony_ci                ComposeAsyncImplFuncReturnType(checker, scriptFunc);
1373af6ab5fSopenharmony_ci            }
1383af6ab5fSopenharmony_ci
1393af6ab5fSopenharmony_ci            for (auto &returnStatement : scriptFunc->ReturnStatements()) {
1403af6ab5fSopenharmony_ci                returnStatement->SetReturnType(checker, scriptFunc->Signature()->ReturnType());
1413af6ab5fSopenharmony_ci            }
1423af6ab5fSopenharmony_ci        }
1433af6ab5fSopenharmony_ci
1443af6ab5fSopenharmony_ci        checker->Context().SetContainingSignature(nullptr);
1453af6ab5fSopenharmony_ci    }
1463af6ab5fSopenharmony_ci}
1473af6ab5fSopenharmony_ci
1483af6ab5fSopenharmony_civoid ComposeAsyncImplFuncReturnType(ETSChecker *checker, ir::ScriptFunction *scriptFunc)
1493af6ab5fSopenharmony_ci{
1503af6ab5fSopenharmony_ci    const auto &promiseGlobal = checker->GlobalBuiltinPromiseType()->AsETSObjectType();
1513af6ab5fSopenharmony_ci    auto promiseType =
1523af6ab5fSopenharmony_ci        promiseGlobal->Instantiate(checker->Allocator(), checker->Relation(), checker->GetGlobalTypesHolder())
1533af6ab5fSopenharmony_ci            ->AsETSObjectType();
1543af6ab5fSopenharmony_ci    promiseType->AddTypeFlag(checker::TypeFlag::GENERIC);
1553af6ab5fSopenharmony_ci    promiseType->TypeArguments().clear();
1563af6ab5fSopenharmony_ci    promiseType->TypeArguments().emplace_back(scriptFunc->Signature()->ReturnType());
1573af6ab5fSopenharmony_ci
1583af6ab5fSopenharmony_ci    auto *objectId =
1593af6ab5fSopenharmony_ci        checker->AllocNode<ir::Identifier>(compiler::Signatures::BUILTIN_OBJECT_CLASS, checker->Allocator());
1603af6ab5fSopenharmony_ci    objectId->SetReference();
1613af6ab5fSopenharmony_ci    checker->VarBinder()->AsETSBinder()->LookupTypeReference(objectId, false);
1623af6ab5fSopenharmony_ci    auto *returnType = checker->AllocNode<ir::ETSTypeReference>(
1633af6ab5fSopenharmony_ci        checker->AllocNode<ir::ETSTypeReferencePart>(objectId, nullptr, nullptr));
1643af6ab5fSopenharmony_ci    objectId->SetParent(returnType->Part());
1653af6ab5fSopenharmony_ci    returnType->Part()->SetParent(returnType);
1663af6ab5fSopenharmony_ci    returnType->SetTsType(
1673af6ab5fSopenharmony_ci        checker->Allocator()->New<ETSAsyncFuncReturnType>(checker->Allocator(), checker->Relation(), promiseType));
1683af6ab5fSopenharmony_ci    returnType->Check(checker);
1693af6ab5fSopenharmony_ci    scriptFunc->Signature()->SetReturnType(returnType->TsType());
1703af6ab5fSopenharmony_ci}
1713af6ab5fSopenharmony_ci
1723af6ab5fSopenharmony_civoid ComposeAsyncImplMethod(ETSChecker *checker, ir::MethodDefinition *node)
1733af6ab5fSopenharmony_ci{
1743af6ab5fSopenharmony_ci    auto *classDef = checker->FindAncestorGivenByType(node, ir::AstNodeType::CLASS_DEFINITION)->AsClassDefinition();
1753af6ab5fSopenharmony_ci    auto *scriptFunc = node->Function();
1763af6ab5fSopenharmony_ci    ir::MethodDefinition *implMethod = checker->CreateAsyncProxy(node, classDef);
1773af6ab5fSopenharmony_ci
1783af6ab5fSopenharmony_ci    implMethod->Check(checker);
1793af6ab5fSopenharmony_ci    node->SetAsyncPairMethod(implMethod);
1803af6ab5fSopenharmony_ci
1813af6ab5fSopenharmony_ci    if (scriptFunc->Signature()->HasSignatureFlag(SignatureFlags::NEED_RETURN_TYPE)) {
1823af6ab5fSopenharmony_ci        node->Function()->Signature()->SetReturnType(
1833af6ab5fSopenharmony_ci            implMethod->Function()->Signature()->ReturnType()->AsETSAsyncFuncReturnType()->PromiseType());
1843af6ab5fSopenharmony_ci        scriptFunc->Signature()->RemoveSignatureFlag(SignatureFlags::NEED_RETURN_TYPE);
1853af6ab5fSopenharmony_ci    }
1863af6ab5fSopenharmony_ci
1873af6ab5fSopenharmony_ci    if (node->Function()->IsOverload()) {
1883af6ab5fSopenharmony_ci        auto *baseOverloadImplMethod = node->BaseOverloadMethod()->AsyncPairMethod();
1893af6ab5fSopenharmony_ci        implMethod->Function()->Id()->SetVariable(baseOverloadImplMethod->Function()->Id()->Variable());
1903af6ab5fSopenharmony_ci        baseOverloadImplMethod->AddOverload(implMethod);
1913af6ab5fSopenharmony_ci    } else {
1923af6ab5fSopenharmony_ci        classDef->Body().push_back(implMethod);
1933af6ab5fSopenharmony_ci    }
1943af6ab5fSopenharmony_ci}
1953af6ab5fSopenharmony_ci
1963af6ab5fSopenharmony_civoid CheckPredefinedMethodReturnType(ETSChecker *checker, ir::ScriptFunction *scriptFunc)
1973af6ab5fSopenharmony_ci{
1983af6ab5fSopenharmony_ci    auto const &position = scriptFunc->Start();
1993af6ab5fSopenharmony_ci
2003af6ab5fSopenharmony_ci    if (scriptFunc->IsSetter() && (scriptFunc->Signature()->ReturnType() != checker->GlobalVoidType())) {
2013af6ab5fSopenharmony_ci        checker->LogTypeError("Setter must have void return type", position);
2023af6ab5fSopenharmony_ci    }
2033af6ab5fSopenharmony_ci
2043af6ab5fSopenharmony_ci    if (scriptFunc->IsGetter() && (scriptFunc->Signature()->ReturnType() == checker->GlobalVoidType())) {
2053af6ab5fSopenharmony_ci        checker->LogTypeError("Getter must return a value", position);
2063af6ab5fSopenharmony_ci    }
2073af6ab5fSopenharmony_ci
2083af6ab5fSopenharmony_ci    auto const name = scriptFunc->Id()->Name();
2093af6ab5fSopenharmony_ci    auto const methodName = std::string {ir::PREDEFINED_METHOD} + std::string {name.Utf8()};
2103af6ab5fSopenharmony_ci
2113af6ab5fSopenharmony_ci    if (name.Is(compiler::Signatures::GET_INDEX_METHOD)) {
2123af6ab5fSopenharmony_ci        if (scriptFunc->Signature()->ReturnType() == checker->GlobalVoidType()) {
2133af6ab5fSopenharmony_ci            checker->LogTypeError(methodName + "' shouldn't have void return type.", position);
2143af6ab5fSopenharmony_ci        }
2153af6ab5fSopenharmony_ci    } else if (name.Is(compiler::Signatures::SET_INDEX_METHOD)) {
2163af6ab5fSopenharmony_ci        if (scriptFunc->Signature()->ReturnType() != checker->GlobalVoidType()) {
2173af6ab5fSopenharmony_ci            checker->LogTypeError(methodName + "' should have void return type.", position);
2183af6ab5fSopenharmony_ci        }
2193af6ab5fSopenharmony_ci    } else if (name.Is(compiler::Signatures::ITERATOR_METHOD)) {
2203af6ab5fSopenharmony_ci        CheckIteratorMethodReturnType(checker, scriptFunc, position, methodName);
2213af6ab5fSopenharmony_ci    }
2223af6ab5fSopenharmony_ci}
2233af6ab5fSopenharmony_ci
2243af6ab5fSopenharmony_cistatic bool HasIteratorInterface(ETSObjectType const *const objectType)
2253af6ab5fSopenharmony_ci{
2263af6ab5fSopenharmony_ci    auto const hasIteratorInterfaceImpl = [](ETSObjectType const *const checkType,
2273af6ab5fSopenharmony_ci                                             auto &&iteratorInterfaceImpl) -> bool {
2283af6ab5fSopenharmony_ci        if (checkType->Name().Is(ir::ITERATOR_INTERFACE_NAME)) {
2293af6ab5fSopenharmony_ci            return true;
2303af6ab5fSopenharmony_ci        }
2313af6ab5fSopenharmony_ci        for (const auto *const interface : checkType->Interfaces()) {
2323af6ab5fSopenharmony_ci            if (iteratorInterfaceImpl(interface, iteratorInterfaceImpl)) {
2333af6ab5fSopenharmony_ci                return true;
2343af6ab5fSopenharmony_ci            }
2353af6ab5fSopenharmony_ci        }
2363af6ab5fSopenharmony_ci        return false;
2373af6ab5fSopenharmony_ci    };
2383af6ab5fSopenharmony_ci
2393af6ab5fSopenharmony_ci    return hasIteratorInterfaceImpl(objectType, hasIteratorInterfaceImpl);
2403af6ab5fSopenharmony_ci}
2413af6ab5fSopenharmony_ci
2423af6ab5fSopenharmony_civoid CheckIteratorMethodReturnType(ETSChecker *checker, ir::ScriptFunction *scriptFunc,
2433af6ab5fSopenharmony_ci                                   const lexer::SourcePosition &position, const std::string &methodName)
2443af6ab5fSopenharmony_ci{
2453af6ab5fSopenharmony_ci    const auto *returnType = scriptFunc->Signature()->ReturnType();
2463af6ab5fSopenharmony_ci
2473af6ab5fSopenharmony_ci    if (returnType == nullptr) {
2483af6ab5fSopenharmony_ci        checker->LogTypeError(methodName + "' doesn't have return type.", position);
2493af6ab5fSopenharmony_ci    }
2503af6ab5fSopenharmony_ci
2513af6ab5fSopenharmony_ci    if (returnType->IsETSTypeParameter()) {
2523af6ab5fSopenharmony_ci        returnType = checker->GetApparentType(returnType->AsETSTypeParameter()->GetConstraintType());
2533af6ab5fSopenharmony_ci    }
2543af6ab5fSopenharmony_ci
2553af6ab5fSopenharmony_ci    if (returnType->IsETSObjectType() && HasIteratorInterface(returnType->AsETSObjectType())) {
2563af6ab5fSopenharmony_ci        return;
2573af6ab5fSopenharmony_ci    }
2583af6ab5fSopenharmony_ci
2593af6ab5fSopenharmony_ci    while (returnType->IsETSObjectType() && returnType->AsETSObjectType()->SuperType() != nullptr) {
2603af6ab5fSopenharmony_ci        returnType = returnType->AsETSObjectType()->SuperType();
2613af6ab5fSopenharmony_ci        if (returnType->IsETSObjectType() && HasIteratorInterface(returnType->AsETSObjectType())) {
2623af6ab5fSopenharmony_ci            return;
2633af6ab5fSopenharmony_ci        }
2643af6ab5fSopenharmony_ci    }
2653af6ab5fSopenharmony_ci
2663af6ab5fSopenharmony_ci    checker->LogTypeError(
2673af6ab5fSopenharmony_ci        {"The return type of '", scriptFunc->Id()->Name(), "' must be a type that implements Iterator interface."},
2683af6ab5fSopenharmony_ci        position);
2693af6ab5fSopenharmony_ci}
2703af6ab5fSopenharmony_ci
2713af6ab5fSopenharmony_cichecker::Type *InitAnonymousLambdaCallee(checker::ETSChecker *checker, ir::Expression *callee,
2723af6ab5fSopenharmony_ci                                         checker::Type *calleeType)
2733af6ab5fSopenharmony_ci{
2743af6ab5fSopenharmony_ci    auto *const arrowFunc = callee->AsArrowFunctionExpression()->Function();
2753af6ab5fSopenharmony_ci
2763af6ab5fSopenharmony_ci    ArenaVector<ir::Expression *> params {checker->Allocator()->Adapter()};
2773af6ab5fSopenharmony_ci    checker->CopyParams(arrowFunc->Params(), params);
2783af6ab5fSopenharmony_ci    checker::Type *funcReturnType = nullptr;
2793af6ab5fSopenharmony_ci
2803af6ab5fSopenharmony_ci    auto *typeAnnotation = arrowFunc->ReturnTypeAnnotation();
2813af6ab5fSopenharmony_ci    if (typeAnnotation != nullptr) {
2823af6ab5fSopenharmony_ci        typeAnnotation = typeAnnotation->Clone(checker->Allocator(), nullptr);
2833af6ab5fSopenharmony_ci        typeAnnotation->SetTsType(arrowFunc->ReturnTypeAnnotation()->TsType());
2843af6ab5fSopenharmony_ci    } else if (arrowFunc->Signature()->ReturnType() != nullptr) {
2853af6ab5fSopenharmony_ci        auto newTypeAnnotation = callee->AsArrowFunctionExpression()->CreateTypeAnnotation(checker);
2863af6ab5fSopenharmony_ci        typeAnnotation = arrowFunc->ReturnTypeAnnotation();
2873af6ab5fSopenharmony_ci        funcReturnType = newTypeAnnotation->GetType(checker);
2883af6ab5fSopenharmony_ci    }
2893af6ab5fSopenharmony_ci
2903af6ab5fSopenharmony_ci    auto signature = ir::FunctionSignature(nullptr, std::move(params), typeAnnotation);
2913af6ab5fSopenharmony_ci    auto *funcType = checker->AllocNode<ir::ETSFunctionType>(std::move(signature), ir::ScriptFunctionFlags::NONE);
2923af6ab5fSopenharmony_ci
2933af6ab5fSopenharmony_ci    funcType->SetScope(arrowFunc->Scope()->AsFunctionScope()->ParamScope());
2943af6ab5fSopenharmony_ci    auto *const funcIface = typeAnnotation != nullptr ? funcType->Check(checker) : funcReturnType;
2953af6ab5fSopenharmony_ci    checker->Relation()->SetNode(callee);
2963af6ab5fSopenharmony_ci    checker->Relation()->IsAssignableTo(calleeType, funcIface);
2973af6ab5fSopenharmony_ci    return funcIface;
2983af6ab5fSopenharmony_ci}
2993af6ab5fSopenharmony_ci
3003af6ab5fSopenharmony_cichecker::Signature *ResolveCallExtensionFunction(checker::ETSFunctionType *functionType, checker::ETSChecker *checker,
3013af6ab5fSopenharmony_ci                                                 ir::CallExpression *expr)
3023af6ab5fSopenharmony_ci{
3033af6ab5fSopenharmony_ci    auto *memberExpr = expr->Callee()->AsMemberExpression();
3043af6ab5fSopenharmony_ci    expr->Arguments().insert(expr->Arguments().begin(), memberExpr->Object());
3053af6ab5fSopenharmony_ci    auto *signature =
3063af6ab5fSopenharmony_ci        checker->ResolveCallExpressionAndTrailingLambda(functionType->CallSignatures(), expr, expr->Start());
3073af6ab5fSopenharmony_ci    if (signature == nullptr) {
3083af6ab5fSopenharmony_ci        return nullptr;
3093af6ab5fSopenharmony_ci    }
3103af6ab5fSopenharmony_ci    if (!signature->Function()->IsExtensionMethod()) {
3113af6ab5fSopenharmony_ci        checker->LogTypeError({"Property '", memberExpr->Property()->AsIdentifier()->Name(),
3123af6ab5fSopenharmony_ci                               "' does not exist on type '", memberExpr->ObjType()->Name(), "'"},
3133af6ab5fSopenharmony_ci                              memberExpr->Property()->Start());
3143af6ab5fSopenharmony_ci    }
3153af6ab5fSopenharmony_ci    expr->SetSignature(signature);
3163af6ab5fSopenharmony_ci    expr->SetCallee(memberExpr->Property());
3173af6ab5fSopenharmony_ci    memberExpr->Property()->AsIdentifier()->SetParent(expr);
3183af6ab5fSopenharmony_ci    expr->Arguments()[0]->SetParent(expr);
3193af6ab5fSopenharmony_ci    checker->HandleUpdatedCallExpressionNode(expr);
3203af6ab5fSopenharmony_ci    // Set TsType for new Callee(original member expression's Object)
3213af6ab5fSopenharmony_ci    expr->Callee()->Check(checker);
3223af6ab5fSopenharmony_ci    return signature;
3233af6ab5fSopenharmony_ci}
3243af6ab5fSopenharmony_ci
3253af6ab5fSopenharmony_cichecker::Signature *ResolveCallForETSExtensionFuncHelperType(checker::ETSExtensionFuncHelperType *type,
3263af6ab5fSopenharmony_ci                                                             checker::ETSChecker *checker, ir::CallExpression *expr)
3273af6ab5fSopenharmony_ci{
3283af6ab5fSopenharmony_ci    checker::Signature *signature = checker->ResolveCallExpressionAndTrailingLambda(
3293af6ab5fSopenharmony_ci        type->ClassMethodType()->CallSignatures(), expr, expr->Start(), checker::TypeRelationFlag::NO_THROW);
3303af6ab5fSopenharmony_ci
3313af6ab5fSopenharmony_ci    if (signature != nullptr) {
3323af6ab5fSopenharmony_ci        if (expr->Callee()->IsMemberExpression()) {
3333af6ab5fSopenharmony_ci            auto memberExpr = expr->Callee()->AsMemberExpression();
3343af6ab5fSopenharmony_ci            auto var = type->ClassMethodType()->Variable();
3353af6ab5fSopenharmony_ci            memberExpr->Property()->AsIdentifier()->SetVariable(var);
3363af6ab5fSopenharmony_ci        }
3373af6ab5fSopenharmony_ci
3383af6ab5fSopenharmony_ci        return signature;
3393af6ab5fSopenharmony_ci    }
3403af6ab5fSopenharmony_ci
3413af6ab5fSopenharmony_ci    return ResolveCallExtensionFunction(type->ExtensionMethodType(), checker, expr);
3423af6ab5fSopenharmony_ci}
3433af6ab5fSopenharmony_ci
3443af6ab5fSopenharmony_ciArenaVector<checker::Signature *> GetUnionTypeSignatures(ETSChecker *checker, checker::ETSUnionType *etsUnionType)
3453af6ab5fSopenharmony_ci{
3463af6ab5fSopenharmony_ci    ArenaVector<checker::Signature *> callSignatures(checker->Allocator()->Adapter());
3473af6ab5fSopenharmony_ci
3483af6ab5fSopenharmony_ci    for (auto *constituentType : etsUnionType->ConstituentTypes()) {
3493af6ab5fSopenharmony_ci        if (constituentType->IsETSObjectType()) {
3503af6ab5fSopenharmony_ci            ArenaVector<checker::Signature *> tmpCallSignatures(checker->Allocator()->Adapter());
3513af6ab5fSopenharmony_ci            tmpCallSignatures = constituentType->AsETSObjectType()
3523af6ab5fSopenharmony_ci                                    ->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>("invoke0")
3533af6ab5fSopenharmony_ci                                    ->TsType()
3543af6ab5fSopenharmony_ci                                    ->AsETSFunctionType()
3553af6ab5fSopenharmony_ci                                    ->CallSignatures();
3563af6ab5fSopenharmony_ci            callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end());
3573af6ab5fSopenharmony_ci        }
3583af6ab5fSopenharmony_ci        if (constituentType->IsETSFunctionType()) {
3593af6ab5fSopenharmony_ci            ArenaVector<checker::Signature *> tmpCallSignatures(checker->Allocator()->Adapter());
3603af6ab5fSopenharmony_ci            tmpCallSignatures = constituentType->AsETSFunctionType()->CallSignatures();
3613af6ab5fSopenharmony_ci            callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end());
3623af6ab5fSopenharmony_ci        }
3633af6ab5fSopenharmony_ci        if (constituentType->IsETSUnionType()) {
3643af6ab5fSopenharmony_ci            ArenaVector<checker::Signature *> tmpCallSignatures(checker->Allocator()->Adapter());
3653af6ab5fSopenharmony_ci            tmpCallSignatures = GetUnionTypeSignatures(checker, constituentType->AsETSUnionType());
3663af6ab5fSopenharmony_ci            callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end());
3673af6ab5fSopenharmony_ci        }
3683af6ab5fSopenharmony_ci    }
3693af6ab5fSopenharmony_ci
3703af6ab5fSopenharmony_ci    return callSignatures;
3713af6ab5fSopenharmony_ci}
3723af6ab5fSopenharmony_ci
3733af6ab5fSopenharmony_ciArenaVector<checker::Signature *> &ChooseSignatures(ETSChecker *checker, checker::Type *calleeType,
3743af6ab5fSopenharmony_ci                                                    bool isConstructorCall, bool isFunctionalInterface,
3753af6ab5fSopenharmony_ci                                                    bool isUnionTypeWithFunctionalInterface)
3763af6ab5fSopenharmony_ci{
3773af6ab5fSopenharmony_ci    static ArenaVector<checker::Signature *> unionSignatures(checker->Allocator()->Adapter());
3783af6ab5fSopenharmony_ci    unionSignatures.clear();
3793af6ab5fSopenharmony_ci    if (isConstructorCall) {
3803af6ab5fSopenharmony_ci        return calleeType->AsETSObjectType()->ConstructSignatures();
3813af6ab5fSopenharmony_ci    }
3823af6ab5fSopenharmony_ci    if (isFunctionalInterface) {
3833af6ab5fSopenharmony_ci        return calleeType->AsETSObjectType()
3843af6ab5fSopenharmony_ci            ->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>(FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME)
3853af6ab5fSopenharmony_ci            ->TsType()
3863af6ab5fSopenharmony_ci            ->AsETSFunctionType()
3873af6ab5fSopenharmony_ci            ->CallSignatures();
3883af6ab5fSopenharmony_ci    }
3893af6ab5fSopenharmony_ci    if (isUnionTypeWithFunctionalInterface) {
3903af6ab5fSopenharmony_ci        unionSignatures = GetUnionTypeSignatures(checker, calleeType->AsETSUnionType());
3913af6ab5fSopenharmony_ci        return unionSignatures;
3923af6ab5fSopenharmony_ci    }
3933af6ab5fSopenharmony_ci    return calleeType->AsETSFunctionType()->CallSignatures();
3943af6ab5fSopenharmony_ci}
3953af6ab5fSopenharmony_ci
3963af6ab5fSopenharmony_cichecker::ETSObjectType *ChooseCalleeObj(ETSChecker *checker, ir::CallExpression *expr, checker::Type *calleeType,
3973af6ab5fSopenharmony_ci                                        bool isConstructorCall)
3983af6ab5fSopenharmony_ci{
3993af6ab5fSopenharmony_ci    if (isConstructorCall) {
4003af6ab5fSopenharmony_ci        return calleeType->AsETSObjectType();
4013af6ab5fSopenharmony_ci    }
4023af6ab5fSopenharmony_ci    if (expr->Callee()->IsIdentifier()) {
4033af6ab5fSopenharmony_ci        return checker->Context().ContainingClass();
4043af6ab5fSopenharmony_ci    }
4053af6ab5fSopenharmony_ci    ASSERT(expr->Callee()->IsMemberExpression());
4063af6ab5fSopenharmony_ci    return expr->Callee()->AsMemberExpression()->ObjType();
4073af6ab5fSopenharmony_ci}
4083af6ab5fSopenharmony_ci
4093af6ab5fSopenharmony_civoid ProcessExclamationMark(ETSChecker *checker, ir::UnaryExpression *expr, checker::Type *operandType)
4103af6ab5fSopenharmony_ci{
4113af6ab5fSopenharmony_ci    if (checker->IsNullLikeOrVoidExpression(expr->Argument())) {
4123af6ab5fSopenharmony_ci        auto tsType = checker->CreateETSBooleanType(true);
4133af6ab5fSopenharmony_ci        tsType->AddTypeFlag(checker::TypeFlag::CONSTANT);
4143af6ab5fSopenharmony_ci        expr->SetTsType(tsType);
4153af6ab5fSopenharmony_ci        return;
4163af6ab5fSopenharmony_ci    }
4173af6ab5fSopenharmony_ci
4183af6ab5fSopenharmony_ci    if (operandType == nullptr || !operandType->IsConditionalExprType()) {
4193af6ab5fSopenharmony_ci        checker->LogTypeError("Bad operand type, the type of the operand must be boolean type.",
4203af6ab5fSopenharmony_ci                              expr->Argument()->Start());
4213af6ab5fSopenharmony_ci        expr->SetTsType(checker->GlobalTypeError());
4223af6ab5fSopenharmony_ci        return;
4233af6ab5fSopenharmony_ci    }
4243af6ab5fSopenharmony_ci
4253af6ab5fSopenharmony_ci    auto exprRes = operandType->ResolveConditionExpr();
4263af6ab5fSopenharmony_ci    if (std::get<0>(exprRes)) {
4273af6ab5fSopenharmony_ci        auto tsType = checker->CreateETSBooleanType(!std::get<1>(exprRes));
4283af6ab5fSopenharmony_ci        tsType->AddTypeFlag(checker::TypeFlag::CONSTANT);
4293af6ab5fSopenharmony_ci        expr->SetTsType(tsType);
4303af6ab5fSopenharmony_ci        return;
4313af6ab5fSopenharmony_ci    }
4323af6ab5fSopenharmony_ci
4333af6ab5fSopenharmony_ci    expr->SetTsType(checker->GlobalETSBooleanType());
4343af6ab5fSopenharmony_ci}
4353af6ab5fSopenharmony_ci
4363af6ab5fSopenharmony_civoid SetTsTypeForUnaryExpression(ETSChecker *checker, ir::UnaryExpression *expr, checker::Type *operandType)
4373af6ab5fSopenharmony_ci{
4383af6ab5fSopenharmony_ci    switch (expr->OperatorType()) {
4393af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MINUS:
4403af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_PLUS: {
4413af6ab5fSopenharmony_ci            if (operandType == nullptr || !operandType->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) {
4423af6ab5fSopenharmony_ci                checker->LogTypeError("Bad operand type, the type of the operand must be numeric type.",
4433af6ab5fSopenharmony_ci                                      expr->Argument()->Start());
4443af6ab5fSopenharmony_ci                expr->SetTsType(checker->GlobalTypeError());
4453af6ab5fSopenharmony_ci                break;
4463af6ab5fSopenharmony_ci            }
4473af6ab5fSopenharmony_ci
4483af6ab5fSopenharmony_ci            if (operandType->HasTypeFlag(checker::TypeFlag::CONSTANT) &&
4493af6ab5fSopenharmony_ci                expr->OperatorType() == lexer::TokenType::PUNCTUATOR_MINUS) {
4503af6ab5fSopenharmony_ci                expr->SetTsType(checker->NegateNumericType(operandType, expr));
4513af6ab5fSopenharmony_ci                break;
4523af6ab5fSopenharmony_ci            }
4533af6ab5fSopenharmony_ci
4543af6ab5fSopenharmony_ci            expr->SetTsType(operandType);
4553af6ab5fSopenharmony_ci            break;
4563af6ab5fSopenharmony_ci        }
4573af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_TILDE: {
4583af6ab5fSopenharmony_ci            if (operandType == nullptr || !operandType->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) {
4593af6ab5fSopenharmony_ci                checker->LogTypeError("Bad operand type, the type of the operand must be numeric type.",
4603af6ab5fSopenharmony_ci                                      expr->Argument()->Start());
4613af6ab5fSopenharmony_ci                expr->SetTsType(checker->GlobalTypeError());
4623af6ab5fSopenharmony_ci                break;
4633af6ab5fSopenharmony_ci            }
4643af6ab5fSopenharmony_ci
4653af6ab5fSopenharmony_ci            if (operandType->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
4663af6ab5fSopenharmony_ci                expr->SetTsType(checker->BitwiseNegateNumericType(operandType, expr));
4673af6ab5fSopenharmony_ci                break;
4683af6ab5fSopenharmony_ci            }
4693af6ab5fSopenharmony_ci
4703af6ab5fSopenharmony_ci            expr->SetTsType(checker->SelectGlobalIntegerTypeForNumeric(operandType));
4713af6ab5fSopenharmony_ci            break;
4723af6ab5fSopenharmony_ci        }
4733af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: {
4743af6ab5fSopenharmony_ci            ProcessExclamationMark(checker, expr, operandType);
4753af6ab5fSopenharmony_ci            break;
4763af6ab5fSopenharmony_ci        }
4773af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_DOLLAR_DOLLAR: {
4783af6ab5fSopenharmony_ci            expr->SetTsType(expr->Argument()->TsType());
4793af6ab5fSopenharmony_ci            break;
4803af6ab5fSopenharmony_ci        }
4813af6ab5fSopenharmony_ci        default: {
4823af6ab5fSopenharmony_ci            UNREACHABLE();
4833af6ab5fSopenharmony_ci            break;
4843af6ab5fSopenharmony_ci        }
4853af6ab5fSopenharmony_ci    }
4863af6ab5fSopenharmony_ci}
4873af6ab5fSopenharmony_ci
4883af6ab5fSopenharmony_cichecker::ETSObjectType *CreateSyntheticType(ETSChecker *checker, util::StringView const &syntheticName,
4893af6ab5fSopenharmony_ci                                            checker::ETSObjectType *lastObjectType, ir::Identifier *id)
4903af6ab5fSopenharmony_ci{
4913af6ab5fSopenharmony_ci    auto *syntheticObjType = checker->Allocator()->New<checker::ETSObjectType>(
4923af6ab5fSopenharmony_ci        checker->Allocator(), syntheticName, syntheticName,
4933af6ab5fSopenharmony_ci        std::make_tuple(id, checker::ETSObjectFlags::NO_OPTS, checker->Relation()));
4943af6ab5fSopenharmony_ci
4953af6ab5fSopenharmony_ci    auto *classDecl = checker->Allocator()->New<varbinder::ClassDecl>(syntheticName);
4963af6ab5fSopenharmony_ci    varbinder::LocalVariable *var =
4973af6ab5fSopenharmony_ci        checker->Allocator()->New<varbinder::LocalVariable>(classDecl, varbinder::VariableFlags::CLASS);
4983af6ab5fSopenharmony_ci    var->SetTsType(syntheticObjType);
4993af6ab5fSopenharmony_ci    lastObjectType->AddProperty<checker::PropertyType::STATIC_FIELD>(var);
5003af6ab5fSopenharmony_ci    syntheticObjType->SetEnclosingType(lastObjectType);
5013af6ab5fSopenharmony_ci    return syntheticObjType;
5023af6ab5fSopenharmony_ci}
5033af6ab5fSopenharmony_ci
5043af6ab5fSopenharmony_ci// NOLINTBEGIN(modernize-avoid-c-arrays)
5053af6ab5fSopenharmony_cistatic constexpr char const INVALID_CONST_ASSIGNMENT[] = "Cannot assign a value to a constant variable ";
5063af6ab5fSopenharmony_cistatic constexpr char const INVALID_READONLY_ASSIGNMENT[] = "Cannot assign a value to a readonly variable ";
5073af6ab5fSopenharmony_cistatic constexpr char const ITERATOR_TYPE_ABSENT[] = "Cannot obtain iterator type in 'for-of' statement.";
5083af6ab5fSopenharmony_ci// NOLINTEND(modernize-avoid-c-arrays)
5093af6ab5fSopenharmony_ci
5103af6ab5fSopenharmony_cichecker::Type *GetIteratorType(ETSChecker *checker, checker::Type *elemType, ir::AstNode *left)
5113af6ab5fSopenharmony_ci{
5123af6ab5fSopenharmony_ci    // Just to avoid extra nested level(s)
5133af6ab5fSopenharmony_ci    auto const getIterType = [checker, elemType](ir::VariableDeclarator *const declarator) -> checker::Type * {
5143af6ab5fSopenharmony_ci        if (declarator->TsType() == nullptr) {
5153af6ab5fSopenharmony_ci            if (auto *resolved = checker->FindVariableInFunctionScope(declarator->Id()->AsIdentifier()->Name(),
5163af6ab5fSopenharmony_ci                                                                      varbinder::ResolveBindingOptions::ALL_NON_TYPE);
5173af6ab5fSopenharmony_ci                resolved != nullptr) {
5183af6ab5fSopenharmony_ci                resolved->SetTsType(elemType);
5193af6ab5fSopenharmony_ci                return elemType;
5203af6ab5fSopenharmony_ci            }
5213af6ab5fSopenharmony_ci        } else {
5223af6ab5fSopenharmony_ci            return declarator->TsType();
5233af6ab5fSopenharmony_ci        }
5243af6ab5fSopenharmony_ci        return checker->GlobalTypeError();
5253af6ab5fSopenharmony_ci    };
5263af6ab5fSopenharmony_ci
5273af6ab5fSopenharmony_ci    checker::Type *iterType = nullptr;
5283af6ab5fSopenharmony_ci    if (left->IsIdentifier()) {
5293af6ab5fSopenharmony_ci        if (auto *const variable = left->AsIdentifier()->Variable(); variable != nullptr) {
5303af6ab5fSopenharmony_ci            auto *decl = variable->Declaration();
5313af6ab5fSopenharmony_ci            if (decl->IsConstDecl() || decl->IsReadonlyDecl()) {
5323af6ab5fSopenharmony_ci                std::string_view errorMsg =
5333af6ab5fSopenharmony_ci                    decl->IsConstDecl() ? INVALID_CONST_ASSIGNMENT : INVALID_READONLY_ASSIGNMENT;
5343af6ab5fSopenharmony_ci                checker->LogTypeError({errorMsg, variable->Name()}, decl->Node()->Start());
5353af6ab5fSopenharmony_ci            }
5363af6ab5fSopenharmony_ci        }
5373af6ab5fSopenharmony_ci        iterType = left->AsIdentifier()->TsType();
5383af6ab5fSopenharmony_ci    } else if (left->IsVariableDeclaration()) {
5393af6ab5fSopenharmony_ci        if (auto const &declarators = left->AsVariableDeclaration()->Declarators(); !declarators.empty()) {
5403af6ab5fSopenharmony_ci            iterType = getIterType(declarators.front());
5413af6ab5fSopenharmony_ci        }
5423af6ab5fSopenharmony_ci    }
5433af6ab5fSopenharmony_ci
5443af6ab5fSopenharmony_ci    if (iterType == nullptr) {
5453af6ab5fSopenharmony_ci        checker->LogTypeError(ITERATOR_TYPE_ABSENT, left->Start());
5463af6ab5fSopenharmony_ci        return checker->GlobalTypeError();
5473af6ab5fSopenharmony_ci    }
5483af6ab5fSopenharmony_ci    return iterType;
5493af6ab5fSopenharmony_ci}
5503af6ab5fSopenharmony_ci
5513af6ab5fSopenharmony_cibool CheckArgumentVoidType(checker::Type *&funcReturnType, ETSChecker *checker, const std::string &name,
5523af6ab5fSopenharmony_ci                           ir::ReturnStatement *st)
5533af6ab5fSopenharmony_ci{
5543af6ab5fSopenharmony_ci    if (name.find(compiler::Signatures::ETS_MAIN_WITH_MANGLE_BEGIN) != std::string::npos) {
5553af6ab5fSopenharmony_ci        if (!funcReturnType->IsETSVoidType() && !funcReturnType->IsIntType()) {
5563af6ab5fSopenharmony_ci            checker->LogTypeError("Bad return type, main enable only void or int type.", st->Start());
5573af6ab5fSopenharmony_ci        }
5583af6ab5fSopenharmony_ci    }
5593af6ab5fSopenharmony_ci    return true;
5603af6ab5fSopenharmony_ci}
5613af6ab5fSopenharmony_ci
5623af6ab5fSopenharmony_cibool CheckReturnType(ETSChecker *checker, checker::Type *funcReturnType, checker::Type *argumentType,
5633af6ab5fSopenharmony_ci                     ir::Expression *stArgument, bool isAsync)
5643af6ab5fSopenharmony_ci{
5653af6ab5fSopenharmony_ci    if (funcReturnType->IsETSVoidType() || funcReturnType == checker->GlobalVoidType()) {
5663af6ab5fSopenharmony_ci        if (argumentType != checker->GlobalVoidType()) {
5673af6ab5fSopenharmony_ci            checker->LogTypeError("Unexpected return value, enclosing method return type is void.",
5683af6ab5fSopenharmony_ci                                  stArgument->Start());
5693af6ab5fSopenharmony_ci            return false;
5703af6ab5fSopenharmony_ci        }
5713af6ab5fSopenharmony_ci        if (!checker::AssignmentContext(checker->Relation(), stArgument, argumentType, funcReturnType,
5723af6ab5fSopenharmony_ci                                        stArgument->Start(), {},
5733af6ab5fSopenharmony_ci                                        checker::TypeRelationFlag::DIRECT_RETURN | checker::TypeRelationFlag::NO_THROW)
5743af6ab5fSopenharmony_ci                 .IsAssignable()) {
5753af6ab5fSopenharmony_ci            checker->LogTypeError({"Return statement type is not compatible with the enclosing method's return type."},
5763af6ab5fSopenharmony_ci                                  stArgument->Start());
5773af6ab5fSopenharmony_ci            return false;
5783af6ab5fSopenharmony_ci        }
5793af6ab5fSopenharmony_ci        return true;
5803af6ab5fSopenharmony_ci    }
5813af6ab5fSopenharmony_ci
5823af6ab5fSopenharmony_ci    if (isAsync && funcReturnType->IsETSObjectType() &&
5833af6ab5fSopenharmony_ci        funcReturnType->AsETSObjectType()->GetOriginalBaseType() == checker->GlobalBuiltinPromiseType()) {
5843af6ab5fSopenharmony_ci        auto promiseArg = funcReturnType->AsETSObjectType()->TypeArguments()[0];
5853af6ab5fSopenharmony_ci        checker::AssignmentContext(checker->Relation(), stArgument, argumentType, promiseArg, stArgument->Start(), {},
5863af6ab5fSopenharmony_ci                                   checker::TypeRelationFlag::DIRECT_RETURN | checker::TypeRelationFlag::NO_THROW);
5873af6ab5fSopenharmony_ci        if (checker->Relation()->IsTrue()) {
5883af6ab5fSopenharmony_ci            return true;
5893af6ab5fSopenharmony_ci        }
5903af6ab5fSopenharmony_ci    }
5913af6ab5fSopenharmony_ci
5923af6ab5fSopenharmony_ci    const Type *targetType = checker->TryGettingFunctionTypeFromInvokeFunction(funcReturnType);
5933af6ab5fSopenharmony_ci    const Type *sourceType = checker->TryGettingFunctionTypeFromInvokeFunction(argumentType);
5943af6ab5fSopenharmony_ci    if (!checker::AssignmentContext(checker->Relation(), stArgument, argumentType, funcReturnType, stArgument->Start(),
5953af6ab5fSopenharmony_ci                                    {}, checker::TypeRelationFlag::DIRECT_RETURN | checker::TypeRelationFlag::NO_THROW)
5963af6ab5fSopenharmony_ci             .IsAssignable()) {
5973af6ab5fSopenharmony_ci        checker->LogTypeError(
5983af6ab5fSopenharmony_ci            {"Type '", sourceType, "' is not compatible with the enclosing method's return type '", targetType, "'"},
5993af6ab5fSopenharmony_ci            stArgument->Start());
6003af6ab5fSopenharmony_ci        return false;
6013af6ab5fSopenharmony_ci    }
6023af6ab5fSopenharmony_ci    return true;
6033af6ab5fSopenharmony_ci}
6043af6ab5fSopenharmony_ci
6053af6ab5fSopenharmony_civoid InferReturnType(ETSChecker *checker, ir::ScriptFunction *containingFunc, checker::Type *&funcReturnType,
6063af6ab5fSopenharmony_ci                     ir::Expression *stArgument)
6073af6ab5fSopenharmony_ci{
6083af6ab5fSopenharmony_ci    //  First (or single) return statement in the function:
6093af6ab5fSopenharmony_ci    funcReturnType =
6103af6ab5fSopenharmony_ci        stArgument == nullptr ? checker->GlobalVoidType() : checker->GetNonConstantType(stArgument->Check(checker));
6113af6ab5fSopenharmony_ci    /*
6123af6ab5fSopenharmony_ci    when st_argment is ArrowFunctionExpression, need infer type for st_argment
6133af6ab5fSopenharmony_ci    example code:
6143af6ab5fSopenharmony_ci    ```
6153af6ab5fSopenharmony_ci    return () => {}
6163af6ab5fSopenharmony_ci    ```
6173af6ab5fSopenharmony_ci    */
6183af6ab5fSopenharmony_ci    if (stArgument != nullptr && stArgument->IsArrowFunctionExpression()) {
6193af6ab5fSopenharmony_ci        auto arrowFunc = stArgument->AsArrowFunctionExpression();
6203af6ab5fSopenharmony_ci        auto typeAnnotation = arrowFunc->CreateTypeAnnotation(checker);
6213af6ab5fSopenharmony_ci
6223af6ab5fSopenharmony_ci        auto *argumentType = arrowFunc->TsType();
6233af6ab5fSopenharmony_ci        funcReturnType = typeAnnotation->GetType(checker);
6243af6ab5fSopenharmony_ci
6253af6ab5fSopenharmony_ci        const Type *sourceType = checker->TryGettingFunctionTypeFromInvokeFunction(argumentType);
6263af6ab5fSopenharmony_ci        const Type *targetType = checker->TryGettingFunctionTypeFromInvokeFunction(funcReturnType);
6273af6ab5fSopenharmony_ci
6283af6ab5fSopenharmony_ci        if (!checker::AssignmentContext(checker->Relation(), arrowFunc, argumentType, funcReturnType,
6293af6ab5fSopenharmony_ci                                        stArgument->Start(), {},
6303af6ab5fSopenharmony_ci                                        checker::TypeRelationFlag::DIRECT_RETURN | checker::TypeRelationFlag::NO_THROW)
6313af6ab5fSopenharmony_ci                 .IsAssignable()) {
6323af6ab5fSopenharmony_ci            checker->LogTypeError({"Type '", sourceType,
6333af6ab5fSopenharmony_ci                                   "' is not compatible with the enclosing method's return type '", targetType, "'"},
6343af6ab5fSopenharmony_ci                                  stArgument->Start());
6353af6ab5fSopenharmony_ci            funcReturnType = checker->GlobalTypeError();
6363af6ab5fSopenharmony_ci            return;
6373af6ab5fSopenharmony_ci        }
6383af6ab5fSopenharmony_ci    }
6393af6ab5fSopenharmony_ci
6403af6ab5fSopenharmony_ci    containingFunc->Signature()->SetReturnType(funcReturnType);
6413af6ab5fSopenharmony_ci    containingFunc->Signature()->RemoveSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE);
6423af6ab5fSopenharmony_ci    containingFunc->Signature()->AddSignatureFlag(checker::SignatureFlags::INFERRED_RETURN_TYPE);
6433af6ab5fSopenharmony_ci    checker->VarBinder()->AsETSBinder()->BuildFunctionName(containingFunc);
6443af6ab5fSopenharmony_ci
6453af6ab5fSopenharmony_ci    if (stArgument != nullptr && stArgument->IsObjectExpression()) {
6463af6ab5fSopenharmony_ci        stArgument->AsObjectExpression()->SetPreferredType(funcReturnType);
6473af6ab5fSopenharmony_ci    }
6483af6ab5fSopenharmony_ci}
6493af6ab5fSopenharmony_ci
6503af6ab5fSopenharmony_civoid ProcessReturnStatements(ETSChecker *checker, ir::ScriptFunction *containingFunc, checker::Type *&funcReturnType,
6513af6ab5fSopenharmony_ci                             ir::ReturnStatement *st, ir::Expression *stArgument)
6523af6ab5fSopenharmony_ci{
6533af6ab5fSopenharmony_ci    funcReturnType = containingFunc->Signature()->ReturnType();
6543af6ab5fSopenharmony_ci
6553af6ab5fSopenharmony_ci    if (stArgument == nullptr) {
6563af6ab5fSopenharmony_ci        // previous return statement(s) have value
6573af6ab5fSopenharmony_ci        if (!funcReturnType->IsETSVoidType() && funcReturnType != checker->GlobalVoidType()) {
6583af6ab5fSopenharmony_ci            checker->LogTypeError("All return statements in the function should be empty or have a value.",
6593af6ab5fSopenharmony_ci                                  st->Start());
6603af6ab5fSopenharmony_ci            return;
6613af6ab5fSopenharmony_ci        }
6623af6ab5fSopenharmony_ci    } else {
6633af6ab5fSopenharmony_ci        if (stArgument->IsObjectExpression()) {
6643af6ab5fSopenharmony_ci            stArgument->AsObjectExpression()->SetPreferredType(funcReturnType);
6653af6ab5fSopenharmony_ci        }
6663af6ab5fSopenharmony_ci
6673af6ab5fSopenharmony_ci        if (stArgument->IsMemberExpression()) {
6683af6ab5fSopenharmony_ci            checker->SetArrayPreferredTypeForNestedMemberExpressions(stArgument->AsMemberExpression(), funcReturnType);
6693af6ab5fSopenharmony_ci        }
6703af6ab5fSopenharmony_ci
6713af6ab5fSopenharmony_ci        checker::Type *argumentType = checker->GetNonConstantType(stArgument->Check(checker));
6723af6ab5fSopenharmony_ci
6733af6ab5fSopenharmony_ci        //  previous return statement(s) don't have any value
6743af6ab5fSopenharmony_ci        if (funcReturnType->IsETSVoidType() && !argumentType->IsETSVoidType()) {
6753af6ab5fSopenharmony_ci            checker->LogTypeError("All return statements in the function should be empty or have a value.",
6763af6ab5fSopenharmony_ci                                  stArgument->Start());
6773af6ab5fSopenharmony_ci            return;
6783af6ab5fSopenharmony_ci        }
6793af6ab5fSopenharmony_ci
6803af6ab5fSopenharmony_ci        const auto name = containingFunc->Scope()->InternalName().Mutf8();
6813af6ab5fSopenharmony_ci        if (!CheckArgumentVoidType(funcReturnType, checker, name, st)) {
6823af6ab5fSopenharmony_ci            return;
6833af6ab5fSopenharmony_ci        }
6843af6ab5fSopenharmony_ci
6853af6ab5fSopenharmony_ci        auto *const relation = checker->Relation();
6863af6ab5fSopenharmony_ci        relation->SetNode(stArgument);
6873af6ab5fSopenharmony_ci
6883af6ab5fSopenharmony_ci        if (!relation->IsIdenticalTo(funcReturnType, argumentType)) {
6893af6ab5fSopenharmony_ci            checker->ResolveReturnStatement(funcReturnType, argumentType, containingFunc, st);
6903af6ab5fSopenharmony_ci        }
6913af6ab5fSopenharmony_ci
6923af6ab5fSopenharmony_ci        relation->SetNode(nullptr);
6933af6ab5fSopenharmony_ci        relation->SetFlags(checker::TypeRelationFlag::NONE);
6943af6ab5fSopenharmony_ci    }
6953af6ab5fSopenharmony_ci}
6963af6ab5fSopenharmony_ci
6973af6ab5fSopenharmony_ciETSObjectType *CreateOptionalSignaturesForFunctionalType(ETSChecker *checker, ir::ETSFunctionType *node,
6983af6ab5fSopenharmony_ci                                                         ETSObjectType *genericInterfaceType,
6993af6ab5fSopenharmony_ci                                                         Substitution *substitution, size_t optionalParameterIndex)
7003af6ab5fSopenharmony_ci{
7013af6ab5fSopenharmony_ci    const auto &params = node->Params();
7023af6ab5fSopenharmony_ci    auto returnType = node->ReturnType()->GetType(checker);
7033af6ab5fSopenharmony_ci
7043af6ab5fSopenharmony_ci    for (size_t i = 0; i < optionalParameterIndex; i++) {
7053af6ab5fSopenharmony_ci        checker::ETSChecker::EmplaceSubstituted(
7063af6ab5fSopenharmony_ci            substitution, genericInterfaceType->TypeArguments()[i]->AsETSTypeParameter()->GetOriginal(),
7073af6ab5fSopenharmony_ci            InstantiateBoxedPrimitiveType(checker, params[i],
7083af6ab5fSopenharmony_ci                                          params[i]->AsETSParameterExpression()->TypeAnnotation()->GetType(checker)));
7093af6ab5fSopenharmony_ci    }
7103af6ab5fSopenharmony_ci
7113af6ab5fSopenharmony_ci    for (size_t i = optionalParameterIndex; i < params.size(); i++) {
7123af6ab5fSopenharmony_ci        checker::ETSChecker::EmplaceSubstituted(
7133af6ab5fSopenharmony_ci            substitution, genericInterfaceType->TypeArguments()[i]->AsETSTypeParameter()->GetOriginal(),
7143af6ab5fSopenharmony_ci            CreateParamTypeWithDefaultParam(checker, params[i]));
7153af6ab5fSopenharmony_ci    }
7163af6ab5fSopenharmony_ci
7173af6ab5fSopenharmony_ci    checker::ETSChecker::EmplaceSubstituted(
7183af6ab5fSopenharmony_ci        substitution,
7193af6ab5fSopenharmony_ci        genericInterfaceType->TypeArguments()[genericInterfaceType->TypeArguments().size() - 1]
7203af6ab5fSopenharmony_ci            ->AsETSTypeParameter()
7213af6ab5fSopenharmony_ci            ->GetOriginal(),
7223af6ab5fSopenharmony_ci        InstantiateBoxedPrimitiveType(checker, node->ReturnType(), returnType));
7233af6ab5fSopenharmony_ci
7243af6ab5fSopenharmony_ci    return genericInterfaceType->Substitute(checker->Relation(), substitution)->AsETSObjectType();
7253af6ab5fSopenharmony_ci}
7263af6ab5fSopenharmony_ci
7273af6ab5fSopenharmony_ciETSObjectType *CreateInterfaceTypeForETSFunctionType(ETSChecker *checker, ir::ETSFunctionType *node,
7283af6ab5fSopenharmony_ci                                                     ETSObjectType *genericInterfaceType, Substitution *substitution)
7293af6ab5fSopenharmony_ci{
7303af6ab5fSopenharmony_ci    size_t i = 0;
7313af6ab5fSopenharmony_ci    if (auto const &params = node->Params(); params.size() < checker->GlobalBuiltinFunctionTypeVariadicThreshold()) {
7323af6ab5fSopenharmony_ci        for (; i < params.size(); i++) {
7333af6ab5fSopenharmony_ci            checker::ETSChecker::EmplaceSubstituted(
7343af6ab5fSopenharmony_ci                substitution, genericInterfaceType->TypeArguments()[i]->AsETSTypeParameter()->GetOriginal(),
7353af6ab5fSopenharmony_ci                InstantiateBoxedPrimitiveType(
7363af6ab5fSopenharmony_ci                    checker, params[i], params[i]->AsETSParameterExpression()->TypeAnnotation()->GetType(checker)));
7373af6ab5fSopenharmony_ci        }
7383af6ab5fSopenharmony_ci    }
7393af6ab5fSopenharmony_ci
7403af6ab5fSopenharmony_ci    checker::ETSChecker::EmplaceSubstituted(
7413af6ab5fSopenharmony_ci        substitution, genericInterfaceType->TypeArguments()[i]->AsETSTypeParameter()->GetOriginal(),
7423af6ab5fSopenharmony_ci        InstantiateBoxedPrimitiveType(checker, node->ReturnType(), node->ReturnType()->GetType(checker)));
7433af6ab5fSopenharmony_ci    return genericInterfaceType->Substitute(checker->Relation(), substitution)->AsETSObjectType();
7443af6ab5fSopenharmony_ci}
7453af6ab5fSopenharmony_ci
7463af6ab5fSopenharmony_ciType *CreateParamTypeWithDefaultParam(ETSChecker *checker, ir::Expression *param)
7473af6ab5fSopenharmony_ci{
7483af6ab5fSopenharmony_ci    if (!param->AsETSParameterExpression()->IsDefault()) {
7493af6ab5fSopenharmony_ci        checker->LogTypeError({"Expected initializer for ", param->AsETSParameterExpression()->Ident()->Name()},
7503af6ab5fSopenharmony_ci                              param->Start());
7513af6ab5fSopenharmony_ci    }
7523af6ab5fSopenharmony_ci
7533af6ab5fSopenharmony_ci    ArenaVector<Type *> types(checker->Allocator()->Adapter());
7543af6ab5fSopenharmony_ci    types.push_back(InstantiateBoxedPrimitiveType(
7553af6ab5fSopenharmony_ci        checker, param, param->AsETSParameterExpression()->TypeAnnotation()->GetType(checker)));
7563af6ab5fSopenharmony_ci
7573af6ab5fSopenharmony_ci    if (param->AsETSParameterExpression()->Initializer()->IsUndefinedLiteral()) {
7583af6ab5fSopenharmony_ci        types.push_back(checker->GlobalETSUndefinedType());
7593af6ab5fSopenharmony_ci    }
7603af6ab5fSopenharmony_ci
7613af6ab5fSopenharmony_ci    return checker->CreateETSUnionType(Span<Type *const>(types));
7623af6ab5fSopenharmony_ci}
7633af6ab5fSopenharmony_ci
7643af6ab5fSopenharmony_ciType *InstantiateBoxedPrimitiveType(ETSChecker *checker, ir::Expression *param, Type *paramType)
7653af6ab5fSopenharmony_ci{
7663af6ab5fSopenharmony_ci    if (paramType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
7673af6ab5fSopenharmony_ci        auto node = checker->Relation()->GetNode();
7683af6ab5fSopenharmony_ci        checker->Relation()->SetNode(param);
7693af6ab5fSopenharmony_ci        auto *const boxedTypeArg = checker->PrimitiveTypeAsETSBuiltinType(paramType);
7703af6ab5fSopenharmony_ci        ASSERT(boxedTypeArg);
7713af6ab5fSopenharmony_ci        paramType =
7723af6ab5fSopenharmony_ci            boxedTypeArg->Instantiate(checker->Allocator(), checker->Relation(), checker->GetGlobalTypesHolder());
7733af6ab5fSopenharmony_ci        checker->Relation()->SetNode(node);
7743af6ab5fSopenharmony_ci    }
7753af6ab5fSopenharmony_ci
7763af6ab5fSopenharmony_ci    return paramType;
7773af6ab5fSopenharmony_ci}
7783af6ab5fSopenharmony_ci}  // namespace ark::es2panda::checker
779