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 "utils/logger.h"
173af6ab5fSopenharmony_ci#include "varbinder/ETSBinder.h"
183af6ab5fSopenharmony_ci#include "checker/ETSchecker.h"
193af6ab5fSopenharmony_ci#include "checker/ets/castingContext.h"
203af6ab5fSopenharmony_ci#include "checker/ets/function_helpers.h"
213af6ab5fSopenharmony_ci#include "checker/ets/typeRelationContext.h"
223af6ab5fSopenharmony_ci#include "checker/types/ets/etsAsyncFuncReturnType.h"
233af6ab5fSopenharmony_ci#include "checker/types/ets/etsObjectType.h"
243af6ab5fSopenharmony_ci#include "ir/base/catchClause.h"
253af6ab5fSopenharmony_ci#include "ir/base/classDefinition.h"
263af6ab5fSopenharmony_ci#include "ir/base/classProperty.h"
273af6ab5fSopenharmony_ci#include "ir/base/methodDefinition.h"
283af6ab5fSopenharmony_ci#include "ir/base/scriptFunction.h"
293af6ab5fSopenharmony_ci#include "ir/base/spreadElement.h"
303af6ab5fSopenharmony_ci#include "ir/ets/etsFunctionType.h"
313af6ab5fSopenharmony_ci#include "ir/ets/etsParameterExpression.h"
323af6ab5fSopenharmony_ci#include "ir/ets/etsTypeReference.h"
333af6ab5fSopenharmony_ci#include "ir/ets/etsTypeReferencePart.h"
343af6ab5fSopenharmony_ci#include "ir/ets/etsUnionType.h"
353af6ab5fSopenharmony_ci#include "ir/expressions/arrowFunctionExpression.h"
363af6ab5fSopenharmony_ci#include "ir/expressions/assignmentExpression.h"
373af6ab5fSopenharmony_ci#include "ir/expressions/callExpression.h"
383af6ab5fSopenharmony_ci#include "ir/expressions/functionExpression.h"
393af6ab5fSopenharmony_ci#include "ir/expressions/identifier.h"
403af6ab5fSopenharmony_ci#include "ir/expressions/literals/numberLiteral.h"
413af6ab5fSopenharmony_ci#include "ir/expressions/literals/undefinedLiteral.h"
423af6ab5fSopenharmony_ci#include "ir/expressions/memberExpression.h"
433af6ab5fSopenharmony_ci#include "ir/expressions/objectExpression.h"
443af6ab5fSopenharmony_ci#include "ir/expressions/thisExpression.h"
453af6ab5fSopenharmony_ci#include "ir/statements/blockStatement.h"
463af6ab5fSopenharmony_ci#include "ir/statements/doWhileStatement.h"
473af6ab5fSopenharmony_ci#include "ir/statements/expressionStatement.h"
483af6ab5fSopenharmony_ci#include "ir/statements/forInStatement.h"
493af6ab5fSopenharmony_ci#include "ir/statements/forOfStatement.h"
503af6ab5fSopenharmony_ci#include "ir/statements/forUpdateStatement.h"
513af6ab5fSopenharmony_ci#include "ir/statements/returnStatement.h"
523af6ab5fSopenharmony_ci#include "ir/statements/switchStatement.h"
533af6ab5fSopenharmony_ci#include "ir/statements/whileStatement.h"
543af6ab5fSopenharmony_ci#include "ir/ts/tsTypeAliasDeclaration.h"
553af6ab5fSopenharmony_ci#include "ir/ts/tsTypeParameter.h"
563af6ab5fSopenharmony_ci#include "ir/ts/tsTypeParameterInstantiation.h"
573af6ab5fSopenharmony_ci#include "parser/program/program.h"
583af6ab5fSopenharmony_ci#include "util/helpers.h"
593af6ab5fSopenharmony_ci#include "util/language.h"
603af6ab5fSopenharmony_ci
613af6ab5fSopenharmony_cinamespace ark::es2panda::checker {
623af6ab5fSopenharmony_ci
633af6ab5fSopenharmony_ci// NOTE: #14993 merge with InstantiationContext::ValidateTypeArg
643af6ab5fSopenharmony_cibool ETSChecker::IsCompatibleTypeArgument(ETSTypeParameter *typeParam, Type *typeArgument,
653af6ab5fSopenharmony_ci                                          const Substitution *substitution)
663af6ab5fSopenharmony_ci{
673af6ab5fSopenharmony_ci    if (typeArgument->IsWildcardType()) {
683af6ab5fSopenharmony_ci        return true;
693af6ab5fSopenharmony_ci    }
703af6ab5fSopenharmony_ci    ASSERT(IsReferenceType(typeArgument) || typeArgument->IsETSVoidType());
713af6ab5fSopenharmony_ci    auto *constraint = typeParam->GetConstraintType()->Substitute(Relation(), substitution);
723af6ab5fSopenharmony_ci    bool retVal = false;
733af6ab5fSopenharmony_ci    if (typeArgument->IsETSVoidType()) {
743af6ab5fSopenharmony_ci        retVal = Relation()->IsSupertypeOf(constraint, GlobalETSUndefinedType());
753af6ab5fSopenharmony_ci    } else if (typeArgument->IsETSFunctionType()) {
763af6ab5fSopenharmony_ci        retVal = Relation()->IsSupertypeOf(
773af6ab5fSopenharmony_ci            constraint,
783af6ab5fSopenharmony_ci            this->FunctionTypeToFunctionalInterfaceType(typeArgument->AsETSFunctionType()->CallSignatures().front()));
793af6ab5fSopenharmony_ci    } else {
803af6ab5fSopenharmony_ci        retVal = Relation()->IsSupertypeOf(constraint, typeArgument);
813af6ab5fSopenharmony_ci    }
823af6ab5fSopenharmony_ci
833af6ab5fSopenharmony_ci    return retVal;
843af6ab5fSopenharmony_ci}
853af6ab5fSopenharmony_ci
863af6ab5fSopenharmony_cibool ETSChecker::HasTypeArgsOfObject(Type *argType, Type *paramType)
873af6ab5fSopenharmony_ci{
883af6ab5fSopenharmony_ci    return paramType->IsETSObjectType() && argType->IsETSObjectType() &&
893af6ab5fSopenharmony_ci           !argType->AsETSObjectType()->TypeArguments().empty() &&
903af6ab5fSopenharmony_ci           !paramType->AsETSObjectType()->TypeArguments().empty();
913af6ab5fSopenharmony_ci}
923af6ab5fSopenharmony_ci
933af6ab5fSopenharmony_cibool ETSChecker::InsertTypeIntoSubstitution(const ArenaVector<Type *> &typeParams, const Type *typeParam,
943af6ab5fSopenharmony_ci                                            const size_t index, Substitution *substitution, Type *objectParam)
953af6ab5fSopenharmony_ci{
963af6ab5fSopenharmony_ci    // Check if the type parameter is in the signature, and the type argument is not already in the return vector
973af6ab5fSopenharmony_ci    if (typeParams.size() > index &&
983af6ab5fSopenharmony_ci        IsCompatibleTypeArgument(typeParams[index]->AsETSTypeParameter(), objectParam, substitution) &&
993af6ab5fSopenharmony_ci        std::find(typeParams.begin(), typeParams.end(), typeParam) != typeParams.end()) {
1003af6ab5fSopenharmony_ci        substitution->emplace(typeParams[index]->AsETSTypeParameter(), objectParam);
1013af6ab5fSopenharmony_ci        return true;
1023af6ab5fSopenharmony_ci    }
1033af6ab5fSopenharmony_ci
1043af6ab5fSopenharmony_ci    return false;
1053af6ab5fSopenharmony_ci}
1063af6ab5fSopenharmony_ci
1073af6ab5fSopenharmony_cibool ETSChecker::EnhanceSubstitutionForGenericType(const ArenaVector<Type *> &typeParams, const Type *argType,
1083af6ab5fSopenharmony_ci                                                   const Type *paramType, Substitution *substitution)
1093af6ab5fSopenharmony_ci{
1103af6ab5fSopenharmony_ci    ArenaVector<Type *> objectParams(Allocator()->Adapter());
1113af6ab5fSopenharmony_ci
1123af6ab5fSopenharmony_ci    if (!argType->AsETSObjectType()->GetDeclNode()->IsClassDefinition()) {
1133af6ab5fSopenharmony_ci        return false;
1143af6ab5fSopenharmony_ci    }
1153af6ab5fSopenharmony_ci
1163af6ab5fSopenharmony_ci    const auto paramTypeArgs = paramType->AsETSObjectType()->TypeArguments();
1173af6ab5fSopenharmony_ci
1183af6ab5fSopenharmony_ci    for (const auto it : typeParams) {
1193af6ab5fSopenharmony_ci        bool found = false;
1203af6ab5fSopenharmony_ci
1213af6ab5fSopenharmony_ci        for (size_t i = 0; i < paramTypeArgs.size() && !found; i++) {
1223af6ab5fSopenharmony_ci            if (paramTypeArgs[i] == it) {
1233af6ab5fSopenharmony_ci                objectParams.push_back(argType->AsETSObjectType()->TypeArguments()[i]);
1243af6ab5fSopenharmony_ci                found = true;
1253af6ab5fSopenharmony_ci            }
1263af6ab5fSopenharmony_ci        }
1273af6ab5fSopenharmony_ci
1283af6ab5fSopenharmony_ci        if (!found) {
1293af6ab5fSopenharmony_ci            objectParams.push_back(nullptr);
1303af6ab5fSopenharmony_ci        }
1313af6ab5fSopenharmony_ci    }
1323af6ab5fSopenharmony_ci
1333af6ab5fSopenharmony_ci    if (objectParams.size() < paramTypeArgs.size()) {
1343af6ab5fSopenharmony_ci        return false;
1353af6ab5fSopenharmony_ci    }
1363af6ab5fSopenharmony_ci
1373af6ab5fSopenharmony_ci    bool res = true;
1383af6ab5fSopenharmony_ci    for (size_t j = 0; j < paramTypeArgs.size() && res; ++j) {
1393af6ab5fSopenharmony_ci        if (objectParams[j] != nullptr) {
1403af6ab5fSopenharmony_ci            res = InsertTypeIntoSubstitution(typeParams, paramTypeArgs[j], j, substitution, objectParams[j]);
1413af6ab5fSopenharmony_ci        } else {
1423af6ab5fSopenharmony_ci            res = EnhanceSubstitutionForType(typeParams, paramTypeArgs[j],
1433af6ab5fSopenharmony_ci                                             argType->AsETSObjectType()->TypeArguments()[j], substitution);
1443af6ab5fSopenharmony_ci        }
1453af6ab5fSopenharmony_ci    }
1463af6ab5fSopenharmony_ci
1473af6ab5fSopenharmony_ci    return res;
1483af6ab5fSopenharmony_ci}
1493af6ab5fSopenharmony_ci
1503af6ab5fSopenharmony_cibool ETSChecker::EnhanceSubstitutionForReadonly(const ArenaVector<Type *> &typeParams, ETSReadonlyType *paramType,
1513af6ab5fSopenharmony_ci                                                Type *argumentType, Substitution *substitution)
1523af6ab5fSopenharmony_ci{
1533af6ab5fSopenharmony_ci    return EnhanceSubstitutionForType(typeParams, paramType->GetUnderlying(), GetReadonlyType(argumentType),
1543af6ab5fSopenharmony_ci                                      substitution);
1553af6ab5fSopenharmony_ci}
1563af6ab5fSopenharmony_ci
1573af6ab5fSopenharmony_ci/* A very rough and imprecise partial type inference */
1583af6ab5fSopenharmony_cibool ETSChecker::EnhanceSubstitutionForType(const ArenaVector<Type *> &typeParams, Type *paramType, Type *argumentType,
1593af6ab5fSopenharmony_ci                                            Substitution *substitution)
1603af6ab5fSopenharmony_ci{
1613af6ab5fSopenharmony_ci    if (argumentType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
1623af6ab5fSopenharmony_ci        argumentType = PrimitiveTypeAsETSBuiltinType(argumentType);
1633af6ab5fSopenharmony_ci    }
1643af6ab5fSopenharmony_ci    if (paramType->IsETSTypeParameter()) {
1653af6ab5fSopenharmony_ci        auto *const tparam = paramType->AsETSTypeParameter();
1663af6ab5fSopenharmony_ci        auto *const originalTparam = tparam->GetOriginal();
1673af6ab5fSopenharmony_ci        if (std::find(typeParams.begin(), typeParams.end(), originalTparam) != typeParams.end() &&
1683af6ab5fSopenharmony_ci            substitution->count(originalTparam) == 0) {
1693af6ab5fSopenharmony_ci            if (!IsReferenceType(argumentType)) {
1703af6ab5fSopenharmony_ci                LogTypeError({argumentType, " is not compatible with type ", tparam}, tparam->GetDeclNode()->Start());
1713af6ab5fSopenharmony_ci                return false;
1723af6ab5fSopenharmony_ci            }
1733af6ab5fSopenharmony_ci
1743af6ab5fSopenharmony_ci            ETSChecker::EmplaceSubstituted(substitution, originalTparam, argumentType);
1753af6ab5fSopenharmony_ci            return IsCompatibleTypeArgument(tparam, argumentType, substitution);
1763af6ab5fSopenharmony_ci        }
1773af6ab5fSopenharmony_ci    }
1783af6ab5fSopenharmony_ci
1793af6ab5fSopenharmony_ci    if (paramType->IsETSReadonlyType()) {
1803af6ab5fSopenharmony_ci        return EnhanceSubstitutionForReadonly(typeParams, paramType->AsETSReadonlyType(), argumentType, substitution);
1813af6ab5fSopenharmony_ci    }
1823af6ab5fSopenharmony_ci    if (paramType->IsETSUnionType()) {
1833af6ab5fSopenharmony_ci        return EnhanceSubstitutionForUnion(typeParams, paramType->AsETSUnionType(), argumentType, substitution);
1843af6ab5fSopenharmony_ci    }
1853af6ab5fSopenharmony_ci    if (paramType->IsETSObjectType()) {
1863af6ab5fSopenharmony_ci        if (HasTypeArgsOfObject(argumentType, paramType) &&
1873af6ab5fSopenharmony_ci            EnhanceSubstitutionForGenericType(typeParams, argumentType, paramType, substitution)) {
1883af6ab5fSopenharmony_ci            return true;
1893af6ab5fSopenharmony_ci        }
1903af6ab5fSopenharmony_ci        return EnhanceSubstitutionForObject(typeParams, paramType->AsETSObjectType(), argumentType, substitution);
1913af6ab5fSopenharmony_ci    }
1923af6ab5fSopenharmony_ci    if (paramType->IsETSArrayType()) {
1933af6ab5fSopenharmony_ci        return EnhanceSubstitutionForArray(typeParams, paramType->AsETSArrayType(), argumentType, substitution);
1943af6ab5fSopenharmony_ci    }
1953af6ab5fSopenharmony_ci
1963af6ab5fSopenharmony_ci    return true;
1973af6ab5fSopenharmony_ci}
1983af6ab5fSopenharmony_ci
1993af6ab5fSopenharmony_cibool ETSChecker::EnhanceSubstitutionForUnion(const ArenaVector<Type *> &typeParams, ETSUnionType *paramUn,
2003af6ab5fSopenharmony_ci                                             Type *argumentType, Substitution *substitution)
2013af6ab5fSopenharmony_ci{
2023af6ab5fSopenharmony_ci    if (!argumentType->IsETSUnionType()) {
2033af6ab5fSopenharmony_ci        return std::any_of(
2043af6ab5fSopenharmony_ci            paramUn->ConstituentTypes().begin(), paramUn->ConstituentTypes().end(),
2053af6ab5fSopenharmony_ci            [this, typeParams, argumentType, substitution](Type *ctype) {
2063af6ab5fSopenharmony_ci                return EnhanceSubstitutionForType(typeParams, ctype, argumentType, substitution) &&
2073af6ab5fSopenharmony_ci                       (!ctype->IsETSTypeParameter() ||
2083af6ab5fSopenharmony_ci                        (substitution->find(ctype->AsETSTypeParameter()) != substitution->end() &&
2093af6ab5fSopenharmony_ci                         Relation()->IsAssignableTo(argumentType, substitution->at(ctype->AsETSTypeParameter()))));
2103af6ab5fSopenharmony_ci            });
2113af6ab5fSopenharmony_ci    }
2123af6ab5fSopenharmony_ci    auto *const argUn = argumentType->AsETSUnionType();
2133af6ab5fSopenharmony_ci
2143af6ab5fSopenharmony_ci    ArenaVector<Type *> paramWlist(Allocator()->Adapter());
2153af6ab5fSopenharmony_ci    ArenaVector<Type *> argWlist(Allocator()->Adapter());
2163af6ab5fSopenharmony_ci
2173af6ab5fSopenharmony_ci    for (auto *pc : paramUn->ConstituentTypes()) {
2183af6ab5fSopenharmony_ci        for (auto *ac : argUn->ConstituentTypes()) {
2193af6ab5fSopenharmony_ci            if (ETSChecker::GetOriginalBaseType(pc) != ETSChecker::GetOriginalBaseType(ac)) {
2203af6ab5fSopenharmony_ci                paramWlist.push_back(pc);
2213af6ab5fSopenharmony_ci                argWlist.push_back(ac);
2223af6ab5fSopenharmony_ci                continue;
2233af6ab5fSopenharmony_ci            }
2243af6ab5fSopenharmony_ci            if (!EnhanceSubstitutionForType(typeParams, pc, ac, substitution)) {
2253af6ab5fSopenharmony_ci                return false;
2263af6ab5fSopenharmony_ci            }
2273af6ab5fSopenharmony_ci        }
2283af6ab5fSopenharmony_ci    }
2293af6ab5fSopenharmony_ci    auto *const newArg = CreateETSUnionType(std::move(argWlist));
2303af6ab5fSopenharmony_ci
2313af6ab5fSopenharmony_ci    for (auto *pc : paramWlist) {
2323af6ab5fSopenharmony_ci        if (!EnhanceSubstitutionForType(typeParams, pc, newArg, substitution)) {
2333af6ab5fSopenharmony_ci            return false;
2343af6ab5fSopenharmony_ci        }
2353af6ab5fSopenharmony_ci    }
2363af6ab5fSopenharmony_ci    return true;
2373af6ab5fSopenharmony_ci}
2383af6ab5fSopenharmony_ci
2393af6ab5fSopenharmony_cibool ETSChecker::EnhanceSubstitutionForObject(const ArenaVector<Type *> &typeParams, ETSObjectType *paramType,
2403af6ab5fSopenharmony_ci                                              Type *argumentType, Substitution *substitution)
2413af6ab5fSopenharmony_ci{
2423af6ab5fSopenharmony_ci    auto *paramObjType = paramType->AsETSObjectType();
2433af6ab5fSopenharmony_ci
2443af6ab5fSopenharmony_ci    auto const enhance = [this, typeParams, substitution](Type *ptype, Type *atype) {
2453af6ab5fSopenharmony_ci        return EnhanceSubstitutionForType(typeParams, ptype, atype, substitution);
2463af6ab5fSopenharmony_ci    };
2473af6ab5fSopenharmony_ci
2483af6ab5fSopenharmony_ci    if (argumentType->IsETSObjectType()) {
2493af6ab5fSopenharmony_ci        auto *argObjType = argumentType->AsETSObjectType();
2503af6ab5fSopenharmony_ci        if (GetOriginalBaseType(argObjType) != GetOriginalBaseType(paramObjType)) {
2513af6ab5fSopenharmony_ci            return true;  // don't attempt anything fancy for now
2523af6ab5fSopenharmony_ci        }
2533af6ab5fSopenharmony_ci        bool res = true;
2543af6ab5fSopenharmony_ci        for (size_t i = 0; i < argObjType->TypeArguments().size(); i++) {
2553af6ab5fSopenharmony_ci            res &= enhance(paramObjType->TypeArguments()[i], argObjType->TypeArguments()[i]);
2563af6ab5fSopenharmony_ci        }
2573af6ab5fSopenharmony_ci        return res;
2583af6ab5fSopenharmony_ci    }
2593af6ab5fSopenharmony_ci
2603af6ab5fSopenharmony_ci    if (argumentType->IsETSFunctionType() && paramObjType->HasObjectFlag(ETSObjectFlags::FUNCTIONAL_INTERFACE)) {
2613af6ab5fSopenharmony_ci        auto &parameterSignatures =
2623af6ab5fSopenharmony_ci            paramObjType
2633af6ab5fSopenharmony_ci                ->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>(FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME)
2643af6ab5fSopenharmony_ci                ->TsType()
2653af6ab5fSopenharmony_ci                ->AsETSFunctionType()
2663af6ab5fSopenharmony_ci                ->CallSignatures();
2673af6ab5fSopenharmony_ci        auto &argumentSignatures = argumentType->AsETSFunctionType()->CallSignatures();
2683af6ab5fSopenharmony_ci        ASSERT(argumentSignatures.size() == 1);
2693af6ab5fSopenharmony_ci        ASSERT(parameterSignatures.size() == 1);
2703af6ab5fSopenharmony_ci        auto *argumentSignature = argumentSignatures[0];
2713af6ab5fSopenharmony_ci        auto *parameterSignature = parameterSignatures[0];
2723af6ab5fSopenharmony_ci        // NOTE(gogabr): handle rest parameter for argumentSignature
2733af6ab5fSopenharmony_ci        if (parameterSignature->GetSignatureInfo()->params.size() !=
2743af6ab5fSopenharmony_ci            argumentSignature->GetSignatureInfo()->params.size()) {
2753af6ab5fSopenharmony_ci            return false;
2763af6ab5fSopenharmony_ci        }
2773af6ab5fSopenharmony_ci        bool res = true;
2783af6ab5fSopenharmony_ci        for (size_t idx = 0; idx < argumentSignature->GetSignatureInfo()->params.size(); idx++) {
2793af6ab5fSopenharmony_ci            res &= enhance(parameterSignature->GetSignatureInfo()->params[idx]->TsType(),
2803af6ab5fSopenharmony_ci                           argumentSignature->GetSignatureInfo()->params[idx]->TsType());
2813af6ab5fSopenharmony_ci        }
2823af6ab5fSopenharmony_ci        res &= enhance(parameterSignature->ReturnType(), argumentSignature->ReturnType());
2833af6ab5fSopenharmony_ci        return res;
2843af6ab5fSopenharmony_ci    }
2853af6ab5fSopenharmony_ci
2863af6ab5fSopenharmony_ci    return true;
2873af6ab5fSopenharmony_ci}
2883af6ab5fSopenharmony_ci
2893af6ab5fSopenharmony_cibool ETSChecker::EnhanceSubstitutionForArray(const ArenaVector<Type *> &typeParams, ETSArrayType *const paramType,
2903af6ab5fSopenharmony_ci                                             Type *const argumentType, Substitution *const substitution)
2913af6ab5fSopenharmony_ci{
2923af6ab5fSopenharmony_ci    auto *const elementType =
2933af6ab5fSopenharmony_ci        argumentType->IsETSArrayType() ? argumentType->AsETSArrayType()->ElementType() : argumentType;
2943af6ab5fSopenharmony_ci
2953af6ab5fSopenharmony_ci    return EnhanceSubstitutionForType(typeParams, paramType->ElementType(), elementType, substitution);
2963af6ab5fSopenharmony_ci}
2973af6ab5fSopenharmony_ci
2983af6ab5fSopenharmony_ciSignature *ETSChecker::ValidateParameterlessConstructor(Signature *signature, const lexer::SourcePosition &pos,
2993af6ab5fSopenharmony_ci                                                        TypeRelationFlag flags)
3003af6ab5fSopenharmony_ci{
3013af6ab5fSopenharmony_ci    std::size_t const parameterCount = signature->MinArgCount();
3023af6ab5fSopenharmony_ci    auto const reportError = (flags & TypeRelationFlag::NO_THROW) == 0;
3033af6ab5fSopenharmony_ci
3043af6ab5fSopenharmony_ci    if (parameterCount != 0) {
3053af6ab5fSopenharmony_ci        if (reportError) {
3063af6ab5fSopenharmony_ci            LogTypeError({"No Matching Parameterless Constructor, parameter count ", parameterCount}, pos);
3073af6ab5fSopenharmony_ci        }
3083af6ab5fSopenharmony_ci        return nullptr;
3093af6ab5fSopenharmony_ci    }
3103af6ab5fSopenharmony_ci    return signature;
3113af6ab5fSopenharmony_ci}
3123af6ab5fSopenharmony_ci
3133af6ab5fSopenharmony_cibool ETSChecker::CheckOptionalLambdaFunction(ir::Expression *argument, Signature *substitutedSig, std::size_t index)
3143af6ab5fSopenharmony_ci{
3153af6ab5fSopenharmony_ci    if (argument->IsArrowFunctionExpression()) {
3163af6ab5fSopenharmony_ci        auto *const arrowFuncExpr = argument->AsArrowFunctionExpression();
3173af6ab5fSopenharmony_ci
3183af6ab5fSopenharmony_ci        if (ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
3193af6ab5fSopenharmony_ci            CheckLambdaAssignable(substitutedSig->Function()->Params()[index], lambda)) {
3203af6ab5fSopenharmony_ci            if (arrowFuncExpr->TsTypeOrError() != nullptr) {
3213af6ab5fSopenharmony_ci                arrowFuncExpr->Check(this);
3223af6ab5fSopenharmony_ci                return true;
3233af6ab5fSopenharmony_ci            }
3243af6ab5fSopenharmony_ci        }
3253af6ab5fSopenharmony_ci    }
3263af6ab5fSopenharmony_ci
3273af6ab5fSopenharmony_ci    return false;
3283af6ab5fSopenharmony_ci}
3293af6ab5fSopenharmony_ci
3303af6ab5fSopenharmony_cibool ETSChecker::ValidateArgumentAsIdentifier(const ir::Identifier *identifier)
3313af6ab5fSopenharmony_ci{
3323af6ab5fSopenharmony_ci    auto result = Scope()->Find(identifier->Name());
3333af6ab5fSopenharmony_ci    return result.variable != nullptr && (result.variable->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE));
3343af6ab5fSopenharmony_ci}
3353af6ab5fSopenharmony_ci
3363af6ab5fSopenharmony_cibool ETSChecker::ValidateSignatureRequiredParams(Signature *substitutedSig,
3373af6ab5fSopenharmony_ci                                                 const ArenaVector<ir::Expression *> &arguments, TypeRelationFlag flags,
3383af6ab5fSopenharmony_ci                                                 const std::vector<bool> &argTypeInferenceRequired, bool reportError)
3393af6ab5fSopenharmony_ci{
3403af6ab5fSopenharmony_ci    std::size_t const argumentCount = arguments.size();
3413af6ab5fSopenharmony_ci    std::size_t const parameterCount = substitutedSig->MinArgCount();
3423af6ab5fSopenharmony_ci    auto count = std::min(parameterCount, argumentCount);
3433af6ab5fSopenharmony_ci    for (std::size_t index = 0; index < count; ++index) {
3443af6ab5fSopenharmony_ci        auto &argument = arguments[index];
3453af6ab5fSopenharmony_ci
3463af6ab5fSopenharmony_ci        if (argument->IsObjectExpression()) {
3473af6ab5fSopenharmony_ci            if (substitutedSig->Params()[index]->TsType()->IsETSObjectType()) {
3483af6ab5fSopenharmony_ci                // No chance to check the argument at this point
3493af6ab5fSopenharmony_ci                continue;
3503af6ab5fSopenharmony_ci            }
3513af6ab5fSopenharmony_ci            return false;
3523af6ab5fSopenharmony_ci        }
3533af6ab5fSopenharmony_ci
3543af6ab5fSopenharmony_ci        if (argument->IsMemberExpression()) {
3553af6ab5fSopenharmony_ci            SetArrayPreferredTypeForNestedMemberExpressions(arguments[index]->AsMemberExpression(),
3563af6ab5fSopenharmony_ci                                                            substitutedSig->Params()[index]->TsType());
3573af6ab5fSopenharmony_ci        } else if (argument->IsSpreadElement()) {
3583af6ab5fSopenharmony_ci            if (reportError) {
3593af6ab5fSopenharmony_ci                LogTypeError("Spread argument cannot be passed for ordinary parameter.", argument->Start());
3603af6ab5fSopenharmony_ci            }
3613af6ab5fSopenharmony_ci            return false;
3623af6ab5fSopenharmony_ci        }
3633af6ab5fSopenharmony_ci
3643af6ab5fSopenharmony_ci        if (argTypeInferenceRequired[index]) {
3653af6ab5fSopenharmony_ci            ASSERT(argument->IsArrowFunctionExpression());
3663af6ab5fSopenharmony_ci            auto *const arrowFuncExpr = argument->AsArrowFunctionExpression();
3673af6ab5fSopenharmony_ci            ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
3683af6ab5fSopenharmony_ci            if (CheckLambdaAssignable(substitutedSig->Function()->Params()[index], lambda)) {
3693af6ab5fSopenharmony_ci                continue;
3703af6ab5fSopenharmony_ci            }
3713af6ab5fSopenharmony_ci            return false;
3723af6ab5fSopenharmony_ci        }
3733af6ab5fSopenharmony_ci
3743af6ab5fSopenharmony_ci        if (argument->IsArrayExpression()) {
3753af6ab5fSopenharmony_ci            argument->AsArrayExpression()->GetPrefferedTypeFromFuncParam(
3763af6ab5fSopenharmony_ci                this, substitutedSig->Function()->Params()[index], flags);
3773af6ab5fSopenharmony_ci        }
3783af6ab5fSopenharmony_ci
3793af6ab5fSopenharmony_ci        if (!CheckInvokable(substitutedSig, argument, index, flags)) {
3803af6ab5fSopenharmony_ci            return false;
3813af6ab5fSopenharmony_ci        }
3823af6ab5fSopenharmony_ci
3833af6ab5fSopenharmony_ci        if (argument->IsIdentifier() && ValidateArgumentAsIdentifier(argument->AsIdentifier())) {
3843af6ab5fSopenharmony_ci            LogTypeError("Class name can't be the argument of function or method.", argument->Start());
3853af6ab5fSopenharmony_ci            return false;
3863af6ab5fSopenharmony_ci        }
3873af6ab5fSopenharmony_ci
3883af6ab5fSopenharmony_ci        // clang-format off
3893af6ab5fSopenharmony_ci        if (!ValidateSignatureInvocationContext(
3903af6ab5fSopenharmony_ci            substitutedSig, argument,
3913af6ab5fSopenharmony_ci            TryGettingFunctionTypeFromInvokeFunction(substitutedSig->Params()[index]->TsType()), index, flags)) {
3923af6ab5fSopenharmony_ci            // clang-format on
3933af6ab5fSopenharmony_ci            return false;
3943af6ab5fSopenharmony_ci        }
3953af6ab5fSopenharmony_ci    }
3963af6ab5fSopenharmony_ci
3973af6ab5fSopenharmony_ci    return true;
3983af6ab5fSopenharmony_ci}
3993af6ab5fSopenharmony_ci
4003af6ab5fSopenharmony_cibool ETSChecker::CheckInvokable(Signature *substitutedSig, ir::Expression *argument, std::size_t index,
4013af6ab5fSopenharmony_ci                                TypeRelationFlag flags)
4023af6ab5fSopenharmony_ci{
4033af6ab5fSopenharmony_ci    auto *argumentType = argument->Check(this);
4043af6ab5fSopenharmony_ci    auto *targetType = substitutedSig->Params()[index]->TsType();
4053af6ab5fSopenharmony_ci
4063af6ab5fSopenharmony_ci    auto const invocationCtx =
4073af6ab5fSopenharmony_ci        checker::InvocationContext(Relation(), argument, argumentType, targetType, argument->Start(),
4083af6ab5fSopenharmony_ci                                   {"Type '", argumentType, "' is not compatible with type '",
4093af6ab5fSopenharmony_ci                                    TryGettingFunctionTypeFromInvokeFunction(targetType), "' at index ", index + 1},
4103af6ab5fSopenharmony_ci                                   flags);
4113af6ab5fSopenharmony_ci    return invocationCtx.IsInvocable() || CheckOptionalLambdaFunction(argument, substitutedSig, index);
4123af6ab5fSopenharmony_ci}
4133af6ab5fSopenharmony_ci
4143af6ab5fSopenharmony_cibool ETSChecker::ValidateSignatureInvocationContext(Signature *substitutedSig, ir::Expression *argument,
4153af6ab5fSopenharmony_ci                                                    const Type *targetType, std::size_t index, TypeRelationFlag flags)
4163af6ab5fSopenharmony_ci{
4173af6ab5fSopenharmony_ci    Type *argumentType = argument->Check(this);
4183af6ab5fSopenharmony_ci    auto const invocationCtx = checker::InvocationContext(
4193af6ab5fSopenharmony_ci        Relation(), argument, argumentType, substitutedSig->Params()[index]->TsType(), argument->Start(),
4203af6ab5fSopenharmony_ci        {"Type '", argumentType, "' is not compatible with type '", targetType, "' at index ", index + 1}, flags);
4213af6ab5fSopenharmony_ci    if (!invocationCtx.IsInvocable()) {
4223af6ab5fSopenharmony_ci        return CheckOptionalLambdaFunction(argument, substitutedSig, index);
4233af6ab5fSopenharmony_ci    }
4243af6ab5fSopenharmony_ci
4253af6ab5fSopenharmony_ci    return true;
4263af6ab5fSopenharmony_ci}
4273af6ab5fSopenharmony_ci
4283af6ab5fSopenharmony_cibool ETSChecker::ValidateSignatureRestParams(Signature *substitutedSig, const ArenaVector<ir::Expression *> &arguments,
4293af6ab5fSopenharmony_ci                                             TypeRelationFlag flags, bool reportError)
4303af6ab5fSopenharmony_ci{
4313af6ab5fSopenharmony_ci    std::size_t const argumentCount = arguments.size();
4323af6ab5fSopenharmony_ci    std::size_t const parameterCount = substitutedSig->MinArgCount();
4333af6ab5fSopenharmony_ci    auto count = std::min(parameterCount, argumentCount);
4343af6ab5fSopenharmony_ci    auto const restCount = argumentCount - count;
4353af6ab5fSopenharmony_ci
4363af6ab5fSopenharmony_ci    for (std::size_t index = count; index < argumentCount; ++index) {
4373af6ab5fSopenharmony_ci        auto &argument = arguments[index];
4383af6ab5fSopenharmony_ci
4393af6ab5fSopenharmony_ci        if (!argument->IsSpreadElement()) {
4403af6ab5fSopenharmony_ci            auto *const argumentType = argument->Check(this);
4413af6ab5fSopenharmony_ci            const Type *targetType = TryGettingFunctionTypeFromInvokeFunction(
4423af6ab5fSopenharmony_ci                substitutedSig->RestVar()->TsType()->AsETSArrayType()->ElementType());
4433af6ab5fSopenharmony_ci            const Type *sourceType = TryGettingFunctionTypeFromInvokeFunction(argumentType);
4443af6ab5fSopenharmony_ci            auto const invocationCtx = checker::InvocationContext(
4453af6ab5fSopenharmony_ci                Relation(), argument, argumentType,
4463af6ab5fSopenharmony_ci                substitutedSig->RestVar()->TsType()->AsETSArrayType()->ElementType(), argument->Start(),
4473af6ab5fSopenharmony_ci                {"Type '", sourceType, "' is not compatible with rest parameter type '", targetType, "' at index ",
4483af6ab5fSopenharmony_ci                 index + 1},
4493af6ab5fSopenharmony_ci                flags);
4503af6ab5fSopenharmony_ci            if (!invocationCtx.IsInvocable()) {
4513af6ab5fSopenharmony_ci                return false;
4523af6ab5fSopenharmony_ci            }
4533af6ab5fSopenharmony_ci            continue;
4543af6ab5fSopenharmony_ci        }
4553af6ab5fSopenharmony_ci
4563af6ab5fSopenharmony_ci        if (restCount > 1U) {
4573af6ab5fSopenharmony_ci            if (reportError) {
4583af6ab5fSopenharmony_ci                LogTypeError("Spread argument for the rest parameter can be only one.", argument->Start());
4593af6ab5fSopenharmony_ci            }
4603af6ab5fSopenharmony_ci            return false;
4613af6ab5fSopenharmony_ci        }
4623af6ab5fSopenharmony_ci
4633af6ab5fSopenharmony_ci        auto *const restArgument = argument->AsSpreadElement()->Argument();
4643af6ab5fSopenharmony_ci        auto *const argumentType = restArgument->Check(this);
4653af6ab5fSopenharmony_ci        const Type *targetType = TryGettingFunctionTypeFromInvokeFunction(substitutedSig->RestVar()->TsType());
4663af6ab5fSopenharmony_ci        const Type *sourceType = TryGettingFunctionTypeFromInvokeFunction(argumentType);
4673af6ab5fSopenharmony_ci
4683af6ab5fSopenharmony_ci        auto const invocationCtx = checker::InvocationContext(
4693af6ab5fSopenharmony_ci            Relation(), restArgument, argumentType, substitutedSig->RestVar()->TsType(), argument->Start(),
4703af6ab5fSopenharmony_ci            {"Type '", sourceType, "' is not compatible with rest parameter type '", targetType, "' at index ",
4713af6ab5fSopenharmony_ci             index + 1},
4723af6ab5fSopenharmony_ci            flags);
4733af6ab5fSopenharmony_ci        if (!invocationCtx.IsInvocable()) {
4743af6ab5fSopenharmony_ci            return false;
4753af6ab5fSopenharmony_ci        }
4763af6ab5fSopenharmony_ci    }
4773af6ab5fSopenharmony_ci
4783af6ab5fSopenharmony_ci    return true;
4793af6ab5fSopenharmony_ci}
4803af6ab5fSopenharmony_ci
4813af6ab5fSopenharmony_civoid ETSChecker::MaybeSubstituteLambdaArgumentsInFunctionCall(ir::CallExpression *callExpr)
4823af6ab5fSopenharmony_ci{
4833af6ab5fSopenharmony_ci    ir::AstNode *expr = callExpr;
4843af6ab5fSopenharmony_ci
4853af6ab5fSopenharmony_ci    while (!expr->IsFunctionExpression()) {
4863af6ab5fSopenharmony_ci        if (expr->Parent() == nullptr || expr->Parent()->IsClassDefinition()) {
4873af6ab5fSopenharmony_ci            return;
4883af6ab5fSopenharmony_ci        }
4893af6ab5fSopenharmony_ci        expr = expr->Parent();
4903af6ab5fSopenharmony_ci    }
4913af6ab5fSopenharmony_ci
4923af6ab5fSopenharmony_ci    for (const auto it : expr->AsFunctionExpression()->Function()->Params()) {
4933af6ab5fSopenharmony_ci        if (const auto ident = it->AsETSParameterExpression()->Ident();
4943af6ab5fSopenharmony_ci            callExpr->Callee()->IsIdentifier() && ident->Name() == callExpr->Callee()->AsIdentifier()->Name() &&
4953af6ab5fSopenharmony_ci            ident->IsAnnotatedExpression()) {
4963af6ab5fSopenharmony_ci            if (ident->AsAnnotatedExpression()->TypeAnnotation()->IsETSFunctionType()) {
4973af6ab5fSopenharmony_ci                MaybeSubstituteLambdaArguments(
4983af6ab5fSopenharmony_ci                    ident->AsAnnotatedExpression()->TypeAnnotation()->AsETSFunctionType()->Params(), callExpr);
4993af6ab5fSopenharmony_ci            }
5003af6ab5fSopenharmony_ci        }
5013af6ab5fSopenharmony_ci    }
5023af6ab5fSopenharmony_ci}
5033af6ab5fSopenharmony_ci
5043af6ab5fSopenharmony_civoid ETSChecker::MaybeSubstituteLambdaArgumentsInFunctionCallHelper(ir::CallExpression *callExpr, ir::Identifier *ident)
5053af6ab5fSopenharmony_ci{
5063af6ab5fSopenharmony_ci    ir::ETSFunctionType *funcType = nullptr;
5073af6ab5fSopenharmony_ci    ir::TypeNode *typeAnnotation = ident->TypeAnnotation();
5083af6ab5fSopenharmony_ci
5093af6ab5fSopenharmony_ci    if (typeAnnotation->IsETSTypeReference()) {
5103af6ab5fSopenharmony_ci        auto typeAnnotationIdentifier = ident->TypeAnnotation()->AsETSTypeReference()->Part()->Name()->Variable();
5113af6ab5fSopenharmony_ci        typeAnnotation = typeAnnotationIdentifier->Declaration()->Node()->AsTSTypeAliasDeclaration()->TypeAnnotation();
5123af6ab5fSopenharmony_ci    }
5133af6ab5fSopenharmony_ci
5143af6ab5fSopenharmony_ci    if (typeAnnotation->IsETSFunctionType()) {
5153af6ab5fSopenharmony_ci        funcType = typeAnnotation->AsETSFunctionType();
5163af6ab5fSopenharmony_ci    } else if (typeAnnotation->IsETSUnionType()) {
5173af6ab5fSopenharmony_ci        auto found = std::find_if(typeAnnotation->AsETSUnionType()->Types().begin(),
5183af6ab5fSopenharmony_ci                                  typeAnnotation->AsETSUnionType()->Types().end(),
5193af6ab5fSopenharmony_ci                                  [](ir::TypeNode *const type) { return type->IsETSFunctionType(); });
5203af6ab5fSopenharmony_ci        if (found != typeAnnotation->AsETSUnionType()->Types().end()) {
5213af6ab5fSopenharmony_ci            funcType = (*found)->AsETSFunctionType();
5223af6ab5fSopenharmony_ci        }
5233af6ab5fSopenharmony_ci    }
5243af6ab5fSopenharmony_ci
5253af6ab5fSopenharmony_ci    if (funcType == nullptr) {
5263af6ab5fSopenharmony_ci        return;
5273af6ab5fSopenharmony_ci    }
5283af6ab5fSopenharmony_ci
5293af6ab5fSopenharmony_ci    MaybeSubstituteLambdaArguments(funcType->AsETSFunctionType()->Params(), callExpr);
5303af6ab5fSopenharmony_ci}
5313af6ab5fSopenharmony_ci
5323af6ab5fSopenharmony_civoid ETSChecker::MaybeSubstituteLambdaArguments(const ArenaVector<ir::Expression *> &params,
5333af6ab5fSopenharmony_ci                                                ir::CallExpression *callExpr)
5343af6ab5fSopenharmony_ci{
5353af6ab5fSopenharmony_ci    for (size_t i = 0; i < params.size(); i++) {
5363af6ab5fSopenharmony_ci        if (params[i]->AsETSParameterExpression()->IsDefault() && callExpr->Arguments().size() <= i &&
5373af6ab5fSopenharmony_ci            params[i]->AsETSParameterExpression()->Initializer() != nullptr) {
5383af6ab5fSopenharmony_ci            callExpr->Arguments().push_back(
5393af6ab5fSopenharmony_ci                params[i]->AsETSParameterExpression()->Initializer()->Clone(Allocator(), callExpr)->AsExpression());
5403af6ab5fSopenharmony_ci        }
5413af6ab5fSopenharmony_ci    }
5423af6ab5fSopenharmony_ci}
5433af6ab5fSopenharmony_ci
5443af6ab5fSopenharmony_ciSignature *ETSChecker::ValidateSignature(
5453af6ab5fSopenharmony_ci    std::tuple<Signature *, const ir::TSTypeParameterInstantiation *, TypeRelationFlag> info,
5463af6ab5fSopenharmony_ci    const ArenaVector<ir::Expression *> &arguments, const lexer::SourcePosition &pos,
5473af6ab5fSopenharmony_ci    const std::vector<bool> &argTypeInferenceRequired)
5483af6ab5fSopenharmony_ci{
5493af6ab5fSopenharmony_ci    auto [signature, typeArguments, flags] = info;
5503af6ab5fSopenharmony_ci    Signature *substitutedSig = MaybeSubstituteTypeParameters(this, signature, typeArguments, arguments, pos, flags);
5513af6ab5fSopenharmony_ci    if (substitutedSig == nullptr) {
5523af6ab5fSopenharmony_ci        return nullptr;
5533af6ab5fSopenharmony_ci    }
5543af6ab5fSopenharmony_ci
5553af6ab5fSopenharmony_ci    fflush(stdout);
5563af6ab5fSopenharmony_ci
5573af6ab5fSopenharmony_ci    auto const hasRestParameter = substitutedSig->RestVar() != nullptr;
5583af6ab5fSopenharmony_ci    std::size_t const argumentCount = arguments.size();
5593af6ab5fSopenharmony_ci    std::size_t const parameterCount = substitutedSig->MinArgCount();
5603af6ab5fSopenharmony_ci    auto const reportError = (flags & TypeRelationFlag::NO_THROW) == 0;
5613af6ab5fSopenharmony_ci
5623af6ab5fSopenharmony_ci    if (argumentCount < parameterCount || (argumentCount > parameterCount && !hasRestParameter)) {
5633af6ab5fSopenharmony_ci        if (reportError) {
5643af6ab5fSopenharmony_ci            LogTypeError({"Expected ", parameterCount, " arguments, got ", argumentCount, "."}, pos);
5653af6ab5fSopenharmony_ci        }
5663af6ab5fSopenharmony_ci        return nullptr;
5673af6ab5fSopenharmony_ci    }
5683af6ab5fSopenharmony_ci
5693af6ab5fSopenharmony_ci    if (argumentCount > parameterCount && hasRestParameter && (flags & TypeRelationFlag::IGNORE_REST_PARAM) != 0) {
5703af6ab5fSopenharmony_ci        return nullptr;
5713af6ab5fSopenharmony_ci    }
5723af6ab5fSopenharmony_ci
5733af6ab5fSopenharmony_ci    auto count = std::min(parameterCount, argumentCount);
5743af6ab5fSopenharmony_ci    // Check all required formal parameter(s) first
5753af6ab5fSopenharmony_ci    if (!ValidateSignatureRequiredParams(substitutedSig, arguments, flags, argTypeInferenceRequired, reportError)) {
5763af6ab5fSopenharmony_ci        return nullptr;
5773af6ab5fSopenharmony_ci    }
5783af6ab5fSopenharmony_ci
5793af6ab5fSopenharmony_ci    // Check rest parameter(s) if any exists
5803af6ab5fSopenharmony_ci    if (!hasRestParameter || count >= argumentCount) {
5813af6ab5fSopenharmony_ci        return substitutedSig;
5823af6ab5fSopenharmony_ci    }
5833af6ab5fSopenharmony_ci    if (!ValidateSignatureRestParams(substitutedSig, arguments, flags, reportError)) {
5843af6ab5fSopenharmony_ci        return nullptr;
5853af6ab5fSopenharmony_ci    }
5863af6ab5fSopenharmony_ci
5873af6ab5fSopenharmony_ci    return substitutedSig;
5883af6ab5fSopenharmony_ci}
5893af6ab5fSopenharmony_ci
5903af6ab5fSopenharmony_ciSignature *ETSChecker::CollectParameterlessConstructor(ArenaVector<Signature *> &signatures,
5913af6ab5fSopenharmony_ci                                                       const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)
5923af6ab5fSopenharmony_ci{
5933af6ab5fSopenharmony_ci    Signature *compatibleSignature = nullptr;
5943af6ab5fSopenharmony_ci
5953af6ab5fSopenharmony_ci    auto collectSignatures = [&](TypeRelationFlag relationFlags) {
5963af6ab5fSopenharmony_ci        for (auto *sig : signatures) {
5973af6ab5fSopenharmony_ci            if (auto *concreteSig = ValidateParameterlessConstructor(sig, pos, relationFlags); concreteSig != nullptr) {
5983af6ab5fSopenharmony_ci                compatibleSignature = concreteSig;
5993af6ab5fSopenharmony_ci                break;
6003af6ab5fSopenharmony_ci            }
6013af6ab5fSopenharmony_ci        }
6023af6ab5fSopenharmony_ci    };
6033af6ab5fSopenharmony_ci
6043af6ab5fSopenharmony_ci    // We are able to provide more specific error messages.
6053af6ab5fSopenharmony_ci    if (signatures.size() == 1) {
6063af6ab5fSopenharmony_ci        collectSignatures(resolveFlags);
6073af6ab5fSopenharmony_ci    } else {
6083af6ab5fSopenharmony_ci        collectSignatures(resolveFlags | TypeRelationFlag::NO_THROW);
6093af6ab5fSopenharmony_ci    }
6103af6ab5fSopenharmony_ci
6113af6ab5fSopenharmony_ci    if (compatibleSignature == nullptr) {
6123af6ab5fSopenharmony_ci        if ((resolveFlags & TypeRelationFlag::NO_THROW) == 0) {
6133af6ab5fSopenharmony_ci            LogTypeError({"No matching parameterless constructor"}, pos);
6143af6ab5fSopenharmony_ci        }
6153af6ab5fSopenharmony_ci    }
6163af6ab5fSopenharmony_ci    return compatibleSignature;
6173af6ab5fSopenharmony_ci}
6183af6ab5fSopenharmony_ci
6193af6ab5fSopenharmony_cibool IsSignatureAccessible(Signature *sig, ETSObjectType *containingClass, TypeRelation *relation)
6203af6ab5fSopenharmony_ci{
6213af6ab5fSopenharmony_ci    // NOTE(vivienvoros): this check can be removed if signature is implicitly declared as public according to the spec.
6223af6ab5fSopenharmony_ci    if (!sig->HasSignatureFlag(SignatureFlags::PUBLIC | SignatureFlags::PROTECTED | SignatureFlags::PRIVATE |
6233af6ab5fSopenharmony_ci                               SignatureFlags::INTERNAL)) {
6243af6ab5fSopenharmony_ci        return true;
6253af6ab5fSopenharmony_ci    }
6263af6ab5fSopenharmony_ci
6273af6ab5fSopenharmony_ci    // NOTE(vivienvoros): take care of SignatureFlags::INTERNAL and SignatureFlags::INTERNAL_PROTECTED
6283af6ab5fSopenharmony_ci    if (sig->HasSignatureFlag(SignatureFlags::INTERNAL) && !sig->HasSignatureFlag(SignatureFlags::PROTECTED)) {
6293af6ab5fSopenharmony_ci        return true;
6303af6ab5fSopenharmony_ci    }
6313af6ab5fSopenharmony_ci
6323af6ab5fSopenharmony_ci    if (sig->HasSignatureFlag(SignatureFlags::PUBLIC) || sig->Owner() == containingClass ||
6333af6ab5fSopenharmony_ci        (sig->HasSignatureFlag(SignatureFlags::PROTECTED) && relation->IsSupertypeOf(sig->Owner(), containingClass))) {
6343af6ab5fSopenharmony_ci        return true;
6353af6ab5fSopenharmony_ci    }
6363af6ab5fSopenharmony_ci
6373af6ab5fSopenharmony_ci    return false;
6383af6ab5fSopenharmony_ci}
6393af6ab5fSopenharmony_ci
6403af6ab5fSopenharmony_ci// NOLINTNEXTLINE(readability-magic-numbers)
6413af6ab5fSopenharmony_cistd::array<TypeRelationFlag, 9U> GetFlagVariants()
6423af6ab5fSopenharmony_ci{
6433af6ab5fSopenharmony_ci    // NOTE(boglarkahaag): Not in sync with specification, but solves the issues with rest params for now (#17483)
6443af6ab5fSopenharmony_ci    return {
6453af6ab5fSopenharmony_ci        TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_BOXING |
6463af6ab5fSopenharmony_ci            TypeRelationFlag::IGNORE_REST_PARAM,
6473af6ab5fSopenharmony_ci        TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_BOXING,
6483af6ab5fSopenharmony_ci        TypeRelationFlag::NO_THROW | TypeRelationFlag::IGNORE_REST_PARAM,
6493af6ab5fSopenharmony_ci        TypeRelationFlag::NO_THROW,
6503af6ab5fSopenharmony_ci        TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING | TypeRelationFlag::NO_UNBOXING |
6513af6ab5fSopenharmony_ci            TypeRelationFlag::NO_BOXING | TypeRelationFlag::IGNORE_REST_PARAM,
6523af6ab5fSopenharmony_ci        TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING | TypeRelationFlag::NO_UNBOXING |
6533af6ab5fSopenharmony_ci            TypeRelationFlag::NO_BOXING,
6543af6ab5fSopenharmony_ci        TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING | TypeRelationFlag::IGNORE_REST_PARAM,
6553af6ab5fSopenharmony_ci        TypeRelationFlag::NO_THROW | TypeRelationFlag::WIDENING,
6563af6ab5fSopenharmony_ci        TypeRelationFlag::NO_THROW | TypeRelationFlag::STRING_TO_CHAR,
6573af6ab5fSopenharmony_ci    };
6583af6ab5fSopenharmony_ci}
6593af6ab5fSopenharmony_ciArenaVector<Signature *> ETSChecker::CollectSignatures(ArenaVector<Signature *> &signatures,
6603af6ab5fSopenharmony_ci                                                       const ir::TSTypeParameterInstantiation *typeArguments,
6613af6ab5fSopenharmony_ci                                                       const ArenaVector<ir::Expression *> &arguments,
6623af6ab5fSopenharmony_ci                                                       const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)
6633af6ab5fSopenharmony_ci{
6643af6ab5fSopenharmony_ci    ArenaVector<Signature *> compatibleSignatures(Allocator()->Adapter());
6653af6ab5fSopenharmony_ci    std::vector<bool> argTypeInferenceRequired = FindTypeInferenceArguments(arguments);
6663af6ab5fSopenharmony_ci    Signature *notVisibleSignature = nullptr;
6673af6ab5fSopenharmony_ci
6683af6ab5fSopenharmony_ci    auto collectSignatures = [&](TypeRelationFlag relationFlags) {
6693af6ab5fSopenharmony_ci        for (auto *sig : signatures) {
6703af6ab5fSopenharmony_ci            if (notVisibleSignature != nullptr &&
6713af6ab5fSopenharmony_ci                !IsSignatureAccessible(sig, Context().ContainingClass(), Relation())) {
6723af6ab5fSopenharmony_ci                continue;
6733af6ab5fSopenharmony_ci            }
6743af6ab5fSopenharmony_ci            auto *concreteSig = ValidateSignature(std::make_tuple(sig, typeArguments, relationFlags), arguments, pos,
6753af6ab5fSopenharmony_ci                                                  argTypeInferenceRequired);
6763af6ab5fSopenharmony_ci            if (concreteSig == nullptr) {
6773af6ab5fSopenharmony_ci                continue;
6783af6ab5fSopenharmony_ci            }
6793af6ab5fSopenharmony_ci            if (notVisibleSignature == nullptr &&
6803af6ab5fSopenharmony_ci                !IsSignatureAccessible(sig, Context().ContainingClass(), Relation())) {
6813af6ab5fSopenharmony_ci                notVisibleSignature = concreteSig;
6823af6ab5fSopenharmony_ci            } else {
6833af6ab5fSopenharmony_ci                compatibleSignatures.push_back(concreteSig);
6843af6ab5fSopenharmony_ci            }
6853af6ab5fSopenharmony_ci        }
6863af6ab5fSopenharmony_ci    };
6873af6ab5fSopenharmony_ci
6883af6ab5fSopenharmony_ci    // If there's only one signature, we don't need special checks for boxing/unboxing/widening.
6893af6ab5fSopenharmony_ci    // We are also able to provide more specific error messages.
6903af6ab5fSopenharmony_ci    if (signatures.size() == 1) {
6913af6ab5fSopenharmony_ci        TypeRelationFlag flags = TypeRelationFlag::WIDENING | TypeRelationFlag::STRING_TO_CHAR | resolveFlags;
6923af6ab5fSopenharmony_ci        collectSignatures(flags);
6933af6ab5fSopenharmony_ci    } else {
6943af6ab5fSopenharmony_ci        for (auto flags : GetFlagVariants()) {
6953af6ab5fSopenharmony_ci            flags = flags | resolveFlags;
6963af6ab5fSopenharmony_ci            collectSignatures(flags);
6973af6ab5fSopenharmony_ci            if (!compatibleSignatures.empty()) {
6983af6ab5fSopenharmony_ci                break;
6993af6ab5fSopenharmony_ci            }
7003af6ab5fSopenharmony_ci        }
7013af6ab5fSopenharmony_ci    }
7023af6ab5fSopenharmony_ci
7033af6ab5fSopenharmony_ci    if (compatibleSignatures.empty() && notVisibleSignature != nullptr) {
7043af6ab5fSopenharmony_ci        LogTypeError(
7053af6ab5fSopenharmony_ci            {"Signature ", notVisibleSignature->Function()->Id()->Name(), notVisibleSignature, " is not visible here."},
7063af6ab5fSopenharmony_ci            pos);
7073af6ab5fSopenharmony_ci    }
7083af6ab5fSopenharmony_ci    return compatibleSignatures;
7093af6ab5fSopenharmony_ci}
7103af6ab5fSopenharmony_ci
7113af6ab5fSopenharmony_ciSignature *ETSChecker::GetMostSpecificSignature(ArenaVector<Signature *> &compatibleSignatures,
7123af6ab5fSopenharmony_ci                                                const ArenaVector<ir::Expression *> &arguments,
7133af6ab5fSopenharmony_ci                                                const lexer::SourcePosition &pos, TypeRelationFlag resolveFlags)
7143af6ab5fSopenharmony_ci{
7153af6ab5fSopenharmony_ci    std::vector<bool> argTypeInferenceRequired = FindTypeInferenceArguments(arguments);
7163af6ab5fSopenharmony_ci    Signature *mostSpecificSignature = ChooseMostSpecificSignature(compatibleSignatures, argTypeInferenceRequired, pos);
7173af6ab5fSopenharmony_ci
7183af6ab5fSopenharmony_ci    if (mostSpecificSignature == nullptr) {
7193af6ab5fSopenharmony_ci        LogTypeError({"Reference to ", compatibleSignatures.front()->Function()->Id()->Name(), " is ambiguous"}, pos);
7203af6ab5fSopenharmony_ci        return nullptr;
7213af6ab5fSopenharmony_ci    }
7223af6ab5fSopenharmony_ci
7233af6ab5fSopenharmony_ci    if (!TypeInference(mostSpecificSignature, arguments, resolveFlags)) {
7243af6ab5fSopenharmony_ci        return nullptr;
7253af6ab5fSopenharmony_ci    }
7263af6ab5fSopenharmony_ci
7273af6ab5fSopenharmony_ci    return mostSpecificSignature;
7283af6ab5fSopenharmony_ci}
7293af6ab5fSopenharmony_ci
7303af6ab5fSopenharmony_ciSignature *ETSChecker::ValidateSignatures(ArenaVector<Signature *> &signatures,
7313af6ab5fSopenharmony_ci                                          const ir::TSTypeParameterInstantiation *typeArguments,
7323af6ab5fSopenharmony_ci                                          const ArenaVector<ir::Expression *> &arguments,
7333af6ab5fSopenharmony_ci                                          const lexer::SourcePosition &pos, std::string_view signatureKind,
7343af6ab5fSopenharmony_ci                                          TypeRelationFlag resolveFlags)
7353af6ab5fSopenharmony_ci{
7363af6ab5fSopenharmony_ci    auto compatibleSignatures = CollectSignatures(signatures, typeArguments, arguments, pos, resolveFlags);
7373af6ab5fSopenharmony_ci    if (!compatibleSignatures.empty()) {
7383af6ab5fSopenharmony_ci        return GetMostSpecificSignature(compatibleSignatures, arguments, pos, resolveFlags);
7393af6ab5fSopenharmony_ci    }
7403af6ab5fSopenharmony_ci
7413af6ab5fSopenharmony_ci    if ((resolveFlags & TypeRelationFlag::NO_THROW) == 0 && !arguments.empty() && !signatures.empty()) {
7423af6ab5fSopenharmony_ci        std::stringstream ss;
7433af6ab5fSopenharmony_ci
7443af6ab5fSopenharmony_ci        if (signatures[0]->Function()->IsConstructor()) {
7453af6ab5fSopenharmony_ci            ss << util::Helpers::GetClassDefiniton(signatures[0]->Function())->PrivateId().Mutf8();
7463af6ab5fSopenharmony_ci        } else {
7473af6ab5fSopenharmony_ci            ss << signatures[0]->Function()->Id()->Name().Mutf8();
7483af6ab5fSopenharmony_ci        }
7493af6ab5fSopenharmony_ci
7503af6ab5fSopenharmony_ci        ss << "(";
7513af6ab5fSopenharmony_ci
7523af6ab5fSopenharmony_ci        for (uint32_t index = 0; index < arguments.size(); ++index) {
7533af6ab5fSopenharmony_ci            if (arguments[index]->IsArrowFunctionExpression()) {
7543af6ab5fSopenharmony_ci                // NOTE(peterseres): Refactor this case and add test case
7553af6ab5fSopenharmony_ci                break;
7563af6ab5fSopenharmony_ci            }
7573af6ab5fSopenharmony_ci
7583af6ab5fSopenharmony_ci            arguments[index]->Check(this);
7593af6ab5fSopenharmony_ci            arguments[index]->TsType()->ToString(ss);
7603af6ab5fSopenharmony_ci
7613af6ab5fSopenharmony_ci            if (index == arguments.size() - 1) {
7623af6ab5fSopenharmony_ci                ss << ")";
7633af6ab5fSopenharmony_ci                LogTypeError({"No matching ", signatureKind, " signature for ", ss.str().c_str()}, pos);
7643af6ab5fSopenharmony_ci                return nullptr;
7653af6ab5fSopenharmony_ci            }
7663af6ab5fSopenharmony_ci
7673af6ab5fSopenharmony_ci            ss << ", ";
7683af6ab5fSopenharmony_ci        }
7693af6ab5fSopenharmony_ci    }
7703af6ab5fSopenharmony_ci
7713af6ab5fSopenharmony_ci    if ((resolveFlags & TypeRelationFlag::NO_THROW) == 0) {
7723af6ab5fSopenharmony_ci        LogTypeError({"No matching ", signatureKind, " signature"}, pos);
7733af6ab5fSopenharmony_ci    }
7743af6ab5fSopenharmony_ci
7753af6ab5fSopenharmony_ci    return nullptr;
7763af6ab5fSopenharmony_ci}
7773af6ab5fSopenharmony_ci
7783af6ab5fSopenharmony_ciSignature *ETSChecker::FindMostSpecificSignature(const ArenaVector<Signature *> &signatures,
7793af6ab5fSopenharmony_ci                                                 const ArenaMultiMap<size_t, Signature *> &bestSignaturesForParameter,
7803af6ab5fSopenharmony_ci                                                 size_t paramCount)
7813af6ab5fSopenharmony_ci{
7823af6ab5fSopenharmony_ci    Signature *mostSpecificSignature = nullptr;
7833af6ab5fSopenharmony_ci
7843af6ab5fSopenharmony_ci    for (auto *sig : signatures) {
7853af6ab5fSopenharmony_ci        bool mostSpecific = true;
7863af6ab5fSopenharmony_ci
7873af6ab5fSopenharmony_ci        for (size_t paramIdx = 0; paramIdx < paramCount; ++paramIdx) {
7883af6ab5fSopenharmony_ci            const auto range = bestSignaturesForParameter.equal_range(paramIdx);
7893af6ab5fSopenharmony_ci            // Check if signature is most specific for i. parameter type.
7903af6ab5fSopenharmony_ci            mostSpecific = std::any_of(range.first, range.second, [&sig](auto entry) { return entry.second == sig; });
7913af6ab5fSopenharmony_ci            if (!mostSpecific) {
7923af6ab5fSopenharmony_ci                break;
7933af6ab5fSopenharmony_ci            }
7943af6ab5fSopenharmony_ci        }
7953af6ab5fSopenharmony_ci
7963af6ab5fSopenharmony_ci        if (!mostSpecific) {
7973af6ab5fSopenharmony_ci            continue;
7983af6ab5fSopenharmony_ci        }
7993af6ab5fSopenharmony_ci        if (mostSpecificSignature == nullptr) {
8003af6ab5fSopenharmony_ci            mostSpecificSignature = sig;
8013af6ab5fSopenharmony_ci            continue;
8023af6ab5fSopenharmony_ci        }
8033af6ab5fSopenharmony_ci        if (mostSpecificSignature->Owner() == sig->Owner()) {
8043af6ab5fSopenharmony_ci            // NOTE: audovichenko. Remove this 'if' when #12443 gets resolved
8053af6ab5fSopenharmony_ci            if (mostSpecificSignature->Function() == sig->Function()) {
8063af6ab5fSopenharmony_ci                // The same signature
8073af6ab5fSopenharmony_ci                continue;
8083af6ab5fSopenharmony_ci            }
8093af6ab5fSopenharmony_ci            return nullptr;
8103af6ab5fSopenharmony_ci        }
8113af6ab5fSopenharmony_ci    }
8123af6ab5fSopenharmony_ci    return mostSpecificSignature;
8133af6ab5fSopenharmony_ci}
8143af6ab5fSopenharmony_ci
8153af6ab5fSopenharmony_cistatic void InitMostSpecificType(const ArenaVector<Signature *> &signatures, [[maybe_unused]] Type *&mostSpecificType,
8163af6ab5fSopenharmony_ci                                 [[maybe_unused]] Signature *&prevSig, const size_t idx)
8173af6ab5fSopenharmony_ci{
8183af6ab5fSopenharmony_ci    for (auto *sig : signatures) {
8193af6ab5fSopenharmony_ci        if (Type *sigType = sig->Params().at(idx)->TsType();
8203af6ab5fSopenharmony_ci            sigType->IsETSObjectType() && !sigType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
8213af6ab5fSopenharmony_ci            mostSpecificType = sigType;
8223af6ab5fSopenharmony_ci            prevSig = sig;
8233af6ab5fSopenharmony_ci            return;
8243af6ab5fSopenharmony_ci        }
8253af6ab5fSopenharmony_ci    }
8263af6ab5fSopenharmony_ci}
8273af6ab5fSopenharmony_ci
8283af6ab5fSopenharmony_civoid ETSChecker::SearchAmongMostSpecificTypes(
8293af6ab5fSopenharmony_ci    Type *&mostSpecificType, Signature *&prevSig,
8303af6ab5fSopenharmony_ci    std::tuple<const lexer::SourcePosition &, size_t, size_t, size_t, Signature *> info, bool lookForClassType)
8313af6ab5fSopenharmony_ci{
8323af6ab5fSopenharmony_ci    auto [pos, argumentsSize, paramCount, idx, sig] = info;
8333af6ab5fSopenharmony_ci    if (lookForClassType && argumentsSize == ULONG_MAX) {
8343af6ab5fSopenharmony_ci        [[maybe_unused]] const bool equalParamSize = sig->Params().size() == paramCount;
8353af6ab5fSopenharmony_ci        ASSERT(equalParamSize);
8363af6ab5fSopenharmony_ci    }
8373af6ab5fSopenharmony_ci    Type *sigType = sig->Params().at(idx)->TsType();
8383af6ab5fSopenharmony_ci    const bool isClassType =
8393af6ab5fSopenharmony_ci        sigType->IsETSObjectType() && !sigType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE);
8403af6ab5fSopenharmony_ci    if (isClassType == lookForClassType) {
8413af6ab5fSopenharmony_ci        if (Relation()->IsIdenticalTo(sigType, mostSpecificType)) {
8423af6ab5fSopenharmony_ci            return;
8433af6ab5fSopenharmony_ci        }
8443af6ab5fSopenharmony_ci        if (Relation()->IsAssignableTo(sigType, mostSpecificType)) {
8453af6ab5fSopenharmony_ci            mostSpecificType = sigType;
8463af6ab5fSopenharmony_ci            prevSig = sig;
8473af6ab5fSopenharmony_ci        } else if (sigType->IsETSObjectType() && mostSpecificType->IsETSObjectType() &&
8483af6ab5fSopenharmony_ci                   !Relation()->IsAssignableTo(mostSpecificType, sigType)) {
8493af6ab5fSopenharmony_ci            auto funcName = sig->Function()->Id()->Name();
8503af6ab5fSopenharmony_ci            LogTypeError({"Call to `", funcName, "` is ambiguous as `2` versions of `", funcName, "` are available: `",
8513af6ab5fSopenharmony_ci                          funcName, prevSig, "` and `", funcName, sig, "`"},
8523af6ab5fSopenharmony_ci                         pos);
8533af6ab5fSopenharmony_ci        }
8543af6ab5fSopenharmony_ci    }
8553af6ab5fSopenharmony_ci}
8563af6ab5fSopenharmony_ci
8573af6ab5fSopenharmony_ciArenaMultiMap<size_t, Signature *> ETSChecker::GetSuitableSignaturesForParameter(
8583af6ab5fSopenharmony_ci    const std::vector<bool> &argTypeInferenceRequired, size_t paramCount, ArenaVector<Signature *> &signatures,
8593af6ab5fSopenharmony_ci    const lexer::SourcePosition &pos, size_t argumentsSize)
8603af6ab5fSopenharmony_ci{
8613af6ab5fSopenharmony_ci    // Collect which signatures are most specific for each parameter.
8623af6ab5fSopenharmony_ci    ArenaMultiMap<size_t /* parameter index */, Signature *> bestSignaturesForParameter(Allocator()->Adapter());
8633af6ab5fSopenharmony_ci
8643af6ab5fSopenharmony_ci    const checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(Relation(),
8653af6ab5fSopenharmony_ci                                                                          TypeRelationFlag::ONLY_CHECK_WIDENING);
8663af6ab5fSopenharmony_ci
8673af6ab5fSopenharmony_ci    for (size_t i = 0; i < paramCount; ++i) {
8683af6ab5fSopenharmony_ci        if (argTypeInferenceRequired[i]) {
8693af6ab5fSopenharmony_ci            for (auto *sig : signatures) {
8703af6ab5fSopenharmony_ci                bestSignaturesForParameter.insert({i, sig});
8713af6ab5fSopenharmony_ci            }
8723af6ab5fSopenharmony_ci            continue;
8733af6ab5fSopenharmony_ci        }
8743af6ab5fSopenharmony_ci        // 1st step: check which is the most specific parameter type for i. parameter.
8753af6ab5fSopenharmony_ci        Type *mostSpecificType = signatures.front()->Params().at(i)->TsType();
8763af6ab5fSopenharmony_ci        Signature *prevSig = signatures.front();
8773af6ab5fSopenharmony_ci
8783af6ab5fSopenharmony_ci        InitMostSpecificType(signatures, mostSpecificType, prevSig, i);
8793af6ab5fSopenharmony_ci        for (auto *sig : signatures) {
8803af6ab5fSopenharmony_ci            SearchAmongMostSpecificTypes(mostSpecificType, prevSig,
8813af6ab5fSopenharmony_ci                                         std::make_tuple(pos, argumentsSize, paramCount, i, sig), true);
8823af6ab5fSopenharmony_ci        }
8833af6ab5fSopenharmony_ci        for (auto *sig : signatures) {
8843af6ab5fSopenharmony_ci            SearchAmongMostSpecificTypes(mostSpecificType, prevSig,
8853af6ab5fSopenharmony_ci                                         std::make_tuple(pos, argumentsSize, paramCount, i, sig), false);
8863af6ab5fSopenharmony_ci        }
8873af6ab5fSopenharmony_ci
8883af6ab5fSopenharmony_ci        for (auto *sig : signatures) {
8893af6ab5fSopenharmony_ci            Type *sigType = sig->Params().at(i)->TsType();
8903af6ab5fSopenharmony_ci            if (Relation()->IsIdenticalTo(sigType, mostSpecificType)) {
8913af6ab5fSopenharmony_ci                bestSignaturesForParameter.insert({i, sig});
8923af6ab5fSopenharmony_ci            }
8933af6ab5fSopenharmony_ci        }
8943af6ab5fSopenharmony_ci    }
8953af6ab5fSopenharmony_ci    return bestSignaturesForParameter;
8963af6ab5fSopenharmony_ci}
8973af6ab5fSopenharmony_ci
8983af6ab5fSopenharmony_ciSignature *ETSChecker::ChooseMostSpecificSignature(ArenaVector<Signature *> &signatures,
8993af6ab5fSopenharmony_ci                                                   const std::vector<bool> &argTypeInferenceRequired,
9003af6ab5fSopenharmony_ci                                                   const lexer::SourcePosition &pos, size_t argumentsSize)
9013af6ab5fSopenharmony_ci{
9023af6ab5fSopenharmony_ci    ASSERT(signatures.empty() == false);
9033af6ab5fSopenharmony_ci
9043af6ab5fSopenharmony_ci    if (signatures.size() == 1) {
9053af6ab5fSopenharmony_ci        return signatures.front();
9063af6ab5fSopenharmony_ci    }
9073af6ab5fSopenharmony_ci
9083af6ab5fSopenharmony_ci    size_t paramCount = signatures.front()->Params().size();
9093af6ab5fSopenharmony_ci    if (argumentsSize != ULONG_MAX) {
9103af6ab5fSopenharmony_ci        paramCount = argumentsSize;
9113af6ab5fSopenharmony_ci    }
9123af6ab5fSopenharmony_ci    // Multiple signatures with zero parameter because of inheritance.
9133af6ab5fSopenharmony_ci    // Return the closest one in inheritance chain that is defined at the beginning of the vector.
9143af6ab5fSopenharmony_ci    if (paramCount == 0) {
9153af6ab5fSopenharmony_ci        auto zeroParamSignature = std::find_if(signatures.begin(), signatures.end(),
9163af6ab5fSopenharmony_ci                                               [](auto *signature) { return signature->RestVar() == nullptr; });
9173af6ab5fSopenharmony_ci        // If there is a zero parameter signature, return that
9183af6ab5fSopenharmony_ci        if (zeroParamSignature != signatures.end()) {
9193af6ab5fSopenharmony_ci            return *zeroParamSignature;
9203af6ab5fSopenharmony_ci        }
9213af6ab5fSopenharmony_ci        // If there are multiple rest parameter signatures with different argument types, throw error
9223af6ab5fSopenharmony_ci        if (signatures.size() > 1 && std::any_of(signatures.begin(), signatures.end(), [signatures](const auto *param) {
9233af6ab5fSopenharmony_ci                return param->RestVar()->TsType() != signatures.front()->RestVar()->TsType();
9243af6ab5fSopenharmony_ci            })) {
9253af6ab5fSopenharmony_ci            ThrowTypeError({"Call to `", signatures.front()->Function()->Id()->Name(), "` is ambiguous "}, pos);
9263af6ab5fSopenharmony_ci        }
9273af6ab5fSopenharmony_ci        // Else return the signature with the rest parameter
9283af6ab5fSopenharmony_ci        auto restParamSignature = std::find_if(signatures.begin(), signatures.end(),
9293af6ab5fSopenharmony_ci                                               [](auto *signature) { return signature->RestVar() != nullptr; });
9303af6ab5fSopenharmony_ci        return *restParamSignature;
9313af6ab5fSopenharmony_ci    }
9323af6ab5fSopenharmony_ci
9333af6ab5fSopenharmony_ci    ArenaMultiMap<size_t /* parameter index */, Signature *> bestSignaturesForParameter =
9343af6ab5fSopenharmony_ci        GetSuitableSignaturesForParameter(argTypeInferenceRequired, paramCount, signatures, pos, argumentsSize);
9353af6ab5fSopenharmony_ci    // Find the signature that are most specific for all parameters.
9363af6ab5fSopenharmony_ci    Signature *mostSpecificSignature = FindMostSpecificSignature(signatures, bestSignaturesForParameter, paramCount);
9373af6ab5fSopenharmony_ci
9383af6ab5fSopenharmony_ci    return mostSpecificSignature;
9393af6ab5fSopenharmony_ci}
9403af6ab5fSopenharmony_ci
9413af6ab5fSopenharmony_ciSignature *ETSChecker::ResolveCallExpressionAndTrailingLambda(ArenaVector<Signature *> &signatures,
9423af6ab5fSopenharmony_ci                                                              ir::CallExpression *callExpr,
9433af6ab5fSopenharmony_ci                                                              const lexer::SourcePosition &pos,
9443af6ab5fSopenharmony_ci                                                              const TypeRelationFlag reportFlag)
9453af6ab5fSopenharmony_ci{
9463af6ab5fSopenharmony_ci    Signature *sig = nullptr;
9473af6ab5fSopenharmony_ci    if (callExpr->TrailingBlock() == nullptr) {
9483af6ab5fSopenharmony_ci        for (auto it : signatures) {
9493af6ab5fSopenharmony_ci            MaybeSubstituteLambdaArguments(it->Function()->Params(), callExpr);
9503af6ab5fSopenharmony_ci
9513af6ab5fSopenharmony_ci            if (callExpr->Arguments().size() != it->Function()->Params().size()) {
9523af6ab5fSopenharmony_ci                MaybeSubstituteLambdaArgumentsInFunctionCall(callExpr);
9533af6ab5fSopenharmony_ci            }
9543af6ab5fSopenharmony_ci        }
9553af6ab5fSopenharmony_ci
9563af6ab5fSopenharmony_ci        sig = ValidateSignatures(signatures, callExpr->TypeParams(), callExpr->Arguments(), pos, "call", reportFlag);
9573af6ab5fSopenharmony_ci        return sig;
9583af6ab5fSopenharmony_ci    }
9593af6ab5fSopenharmony_ci
9603af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
9613af6ab5fSopenharmony_ci    auto arguments = ExtendArgumentsWithFakeLamda(callExpr);
9623af6ab5fSopenharmony_ci    sig = ValidateSignatures(signatures, callExpr->TypeParams(), arguments, pos, "call",
9633af6ab5fSopenharmony_ci                             TypeRelationFlag::NO_THROW | TypeRelationFlag::NO_CHECK_TRAILING_LAMBDA);
9643af6ab5fSopenharmony_ci    if (sig != nullptr) {
9653af6ab5fSopenharmony_ci        // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
9663af6ab5fSopenharmony_ci        TransformTraillingLambda(callExpr);
9673af6ab5fSopenharmony_ci        TypeInference(sig, callExpr->Arguments());
9683af6ab5fSopenharmony_ci        return sig;
9693af6ab5fSopenharmony_ci    }
9703af6ab5fSopenharmony_ci
9713af6ab5fSopenharmony_ci    sig = ValidateSignatures(signatures, callExpr->TypeParams(), callExpr->Arguments(), pos, "call", reportFlag);
9723af6ab5fSopenharmony_ci    if (sig != nullptr) {
9733af6ab5fSopenharmony_ci        EnsureValidCurlyBrace(callExpr);
9743af6ab5fSopenharmony_ci    }
9753af6ab5fSopenharmony_ci
9763af6ab5fSopenharmony_ci    return sig;
9773af6ab5fSopenharmony_ci}
9783af6ab5fSopenharmony_ci
9793af6ab5fSopenharmony_ciSignature *ETSChecker::ResolveConstructExpression(ETSObjectType *type, const ArenaVector<ir::Expression *> &arguments,
9803af6ab5fSopenharmony_ci                                                  const lexer::SourcePosition &pos)
9813af6ab5fSopenharmony_ci{
9823af6ab5fSopenharmony_ci    return ValidateSignatures(type->ConstructSignatures(), nullptr, arguments, pos, "construct");
9833af6ab5fSopenharmony_ci}
9843af6ab5fSopenharmony_ci
9853af6ab5fSopenharmony_ci/*
9863af6ab5fSopenharmony_ci * Object literals do not get checked in the process of call resolution; we need to check them separately
9873af6ab5fSopenharmony_ci * afterwards.
9883af6ab5fSopenharmony_ci */
9893af6ab5fSopenharmony_civoid ETSChecker::CheckObjectLiteralArguments(Signature *signature, ArenaVector<ir::Expression *> const &arguments)
9903af6ab5fSopenharmony_ci{
9913af6ab5fSopenharmony_ci    for (uint32_t index = 0; index < arguments.size(); index++) {
9923af6ab5fSopenharmony_ci        if (!arguments[index]->IsObjectExpression()) {
9933af6ab5fSopenharmony_ci            continue;
9943af6ab5fSopenharmony_ci        }
9953af6ab5fSopenharmony_ci
9963af6ab5fSopenharmony_ci        Type *tp;
9973af6ab5fSopenharmony_ci        if (index >= signature->MinArgCount()) {
9983af6ab5fSopenharmony_ci            ASSERT(signature->RestVar());
9993af6ab5fSopenharmony_ci            tp = signature->RestVar()->TsType();
10003af6ab5fSopenharmony_ci        } else {
10013af6ab5fSopenharmony_ci            tp = signature->Params()[index]->TsType();
10023af6ab5fSopenharmony_ci        }
10033af6ab5fSopenharmony_ci
10043af6ab5fSopenharmony_ci        arguments[index]->AsObjectExpression()->SetPreferredType(tp);
10053af6ab5fSopenharmony_ci        arguments[index]->Check(this);
10063af6ab5fSopenharmony_ci    }
10073af6ab5fSopenharmony_ci}
10083af6ab5fSopenharmony_ci
10093af6ab5fSopenharmony_cichecker::ETSFunctionType *ETSChecker::BuildMethodSignature(ir::MethodDefinition *method)
10103af6ab5fSopenharmony_ci{
10113af6ab5fSopenharmony_ci    if (method->TsTypeOrError() != nullptr) {
10123af6ab5fSopenharmony_ci        return method->TsTypeOrError()->AsETSFunctionType();
10133af6ab5fSopenharmony_ci    }
10143af6ab5fSopenharmony_ci
10153af6ab5fSopenharmony_ci    bool isConstructSig = method->IsConstructor();
10163af6ab5fSopenharmony_ci
10173af6ab5fSopenharmony_ci    method->Function()->Id()->SetVariable(method->Id()->Variable());
10183af6ab5fSopenharmony_ci    BuildFunctionSignature(method->Function(), isConstructSig);
10193af6ab5fSopenharmony_ci    if (method->Function()->Signature() == nullptr) {
10203af6ab5fSopenharmony_ci        return nullptr;
10213af6ab5fSopenharmony_ci    }
10223af6ab5fSopenharmony_ci    auto *funcType = BuildNamedFunctionType(method->Function());
10233af6ab5fSopenharmony_ci    std::vector<checker::ETSFunctionType *> overloads;
10243af6ab5fSopenharmony_ci
10253af6ab5fSopenharmony_ci    for (ir::MethodDefinition *const currentFunc : method->Overloads()) {
10263af6ab5fSopenharmony_ci        currentFunc->Function()->Id()->SetVariable(currentFunc->Id()->Variable());
10273af6ab5fSopenharmony_ci        BuildFunctionSignature(currentFunc->Function(), isConstructSig);
10283af6ab5fSopenharmony_ci        if (currentFunc->Function()->Signature() == nullptr) {
10293af6ab5fSopenharmony_ci            return nullptr;
10303af6ab5fSopenharmony_ci        }
10313af6ab5fSopenharmony_ci        auto *const overloadType = BuildNamedFunctionType(currentFunc->Function());
10323af6ab5fSopenharmony_ci        CheckIdenticalOverloads(funcType, overloadType, currentFunc);
10333af6ab5fSopenharmony_ci        currentFunc->SetTsType(overloadType);
10343af6ab5fSopenharmony_ci        funcType->AddCallSignature(currentFunc->Function()->Signature());
10353af6ab5fSopenharmony_ci        overloads.push_back(overloadType);
10363af6ab5fSopenharmony_ci    }
10373af6ab5fSopenharmony_ci    for (size_t baseFuncCounter = 0; baseFuncCounter < overloads.size(); ++baseFuncCounter) {
10383af6ab5fSopenharmony_ci        auto *overloadType = overloads.at(baseFuncCounter);
10393af6ab5fSopenharmony_ci        for (size_t compareFuncCounter = baseFuncCounter + 1; compareFuncCounter < overloads.size();
10403af6ab5fSopenharmony_ci             compareFuncCounter++) {
10413af6ab5fSopenharmony_ci            auto *compareOverloadType = overloads.at(compareFuncCounter);
10423af6ab5fSopenharmony_ci            CheckIdenticalOverloads(overloadType, compareOverloadType, method->Overloads()[compareFuncCounter]);
10433af6ab5fSopenharmony_ci        }
10443af6ab5fSopenharmony_ci    }
10453af6ab5fSopenharmony_ci
10463af6ab5fSopenharmony_ci    method->Id()->Variable()->SetTsType(funcType);
10473af6ab5fSopenharmony_ci    return funcType;
10483af6ab5fSopenharmony_ci}
10493af6ab5fSopenharmony_ci
10503af6ab5fSopenharmony_civoid ETSChecker::CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType *overload,
10513af6ab5fSopenharmony_ci                                         const ir::MethodDefinition *const currentFunc)
10523af6ab5fSopenharmony_ci{
10533af6ab5fSopenharmony_ci    SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK);
10543af6ab5fSopenharmony_ci
10553af6ab5fSopenharmony_ci    Relation()->IsIdenticalTo(func, overload);
10563af6ab5fSopenharmony_ci    if (Relation()->IsTrue() && func->CallSignatures()[0]->GetSignatureInfo()->restVar ==
10573af6ab5fSopenharmony_ci                                    overload->CallSignatures()[0]->GetSignatureInfo()->restVar) {
10583af6ab5fSopenharmony_ci        LogTypeError("Function " + func->Name().Mutf8() + " is already declared.", currentFunc->Start());
10593af6ab5fSopenharmony_ci        return;
10603af6ab5fSopenharmony_ci    }
10613af6ab5fSopenharmony_ci    if (HasSameAssemblySignatures(func, overload)) {
10623af6ab5fSopenharmony_ci        LogTypeError("Function " + func->Name().Mutf8() + " with this assembly signature already declared.",
10633af6ab5fSopenharmony_ci                     currentFunc->Start());
10643af6ab5fSopenharmony_ci    }
10653af6ab5fSopenharmony_ci}
10663af6ab5fSopenharmony_ci
10673af6ab5fSopenharmony_ciSignature *ETSChecker::ComposeSignature(ir::ScriptFunction *func, SignatureInfo *signatureInfo, Type *returnType,
10683af6ab5fSopenharmony_ci                                        varbinder::Variable *nameVar)
10693af6ab5fSopenharmony_ci{
10703af6ab5fSopenharmony_ci    auto *signature = CreateSignature(signatureInfo, returnType, func);
10713af6ab5fSopenharmony_ci    signature->SetOwner(Context().ContainingClass());
10723af6ab5fSopenharmony_ci    signature->SetOwnerVar(nameVar);
10733af6ab5fSopenharmony_ci
10743af6ab5fSopenharmony_ci    const auto *returnTypeAnnotation = func->ReturnTypeAnnotation();
10753af6ab5fSopenharmony_ci    if (returnTypeAnnotation == nullptr && ((func->Flags() & ir::ScriptFunctionFlags::HAS_RETURN) != 0)) {
10763af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::NEED_RETURN_TYPE);
10773af6ab5fSopenharmony_ci    }
10783af6ab5fSopenharmony_ci
10793af6ab5fSopenharmony_ci    if (returnTypeAnnotation != nullptr && returnTypeAnnotation->IsTSThisType()) {
10803af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::THIS_RETURN_TYPE);
10813af6ab5fSopenharmony_ci    }
10823af6ab5fSopenharmony_ci
10833af6ab5fSopenharmony_ci    if (func->IsAbstract()) {
10843af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::ABSTRACT);
10853af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::VIRTUAL);
10863af6ab5fSopenharmony_ci    }
10873af6ab5fSopenharmony_ci
10883af6ab5fSopenharmony_ci    if (func->IsStatic()) {
10893af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::STATIC);
10903af6ab5fSopenharmony_ci    }
10913af6ab5fSopenharmony_ci
10923af6ab5fSopenharmony_ci    if (func->IsConstructor()) {
10933af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::CONSTRUCTOR);
10943af6ab5fSopenharmony_ci    }
10953af6ab5fSopenharmony_ci
10963af6ab5fSopenharmony_ci    if (signature->Owner()->GetDeclNode()->IsFinal() || func->IsFinal()) {
10973af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::FINAL);
10983af6ab5fSopenharmony_ci    }
10993af6ab5fSopenharmony_ci
11003af6ab5fSopenharmony_ci    if (func->IsPublic()) {
11013af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::PUBLIC);
11023af6ab5fSopenharmony_ci    } else if (func->IsInternal()) {
11033af6ab5fSopenharmony_ci        if (func->IsProtected()) {
11043af6ab5fSopenharmony_ci            signature->AddSignatureFlag(SignatureFlags::INTERNAL_PROTECTED);
11053af6ab5fSopenharmony_ci        } else {
11063af6ab5fSopenharmony_ci            signature->AddSignatureFlag(SignatureFlags::INTERNAL);
11073af6ab5fSopenharmony_ci        }
11083af6ab5fSopenharmony_ci    } else if (func->IsProtected()) {
11093af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::PROTECTED);
11103af6ab5fSopenharmony_ci    } else if (func->IsPrivate()) {
11113af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::PRIVATE);
11123af6ab5fSopenharmony_ci    }
11133af6ab5fSopenharmony_ci
11143af6ab5fSopenharmony_ci    return signature;
11153af6ab5fSopenharmony_ci}
11163af6ab5fSopenharmony_ci
11173af6ab5fSopenharmony_ciType *ETSChecker::ComposeReturnType(ir::ScriptFunction *func)
11183af6ab5fSopenharmony_ci{
11193af6ab5fSopenharmony_ci    auto *const returnTypeAnnotation = func->ReturnTypeAnnotation();
11203af6ab5fSopenharmony_ci    checker::Type *returnType {};
11213af6ab5fSopenharmony_ci
11223af6ab5fSopenharmony_ci    if (returnTypeAnnotation == nullptr) {
11233af6ab5fSopenharmony_ci        // implicit void return type
11243af6ab5fSopenharmony_ci        returnType = GlobalVoidType();
11253af6ab5fSopenharmony_ci
11263af6ab5fSopenharmony_ci        if (func->IsAsyncFunc()) {
11273af6ab5fSopenharmony_ci            auto implicitPromiseVoid = [this]() {
11283af6ab5fSopenharmony_ci                const auto &promiseGlobal = GlobalBuiltinPromiseType()->AsETSObjectType();
11293af6ab5fSopenharmony_ci                auto promiseType =
11303af6ab5fSopenharmony_ci                    promiseGlobal->Instantiate(Allocator(), Relation(), GetGlobalTypesHolder())->AsETSObjectType();
11313af6ab5fSopenharmony_ci                promiseType->AddTypeFlag(checker::TypeFlag::GENERIC);
11323af6ab5fSopenharmony_ci                promiseType->TypeArguments().clear();
11333af6ab5fSopenharmony_ci                promiseType->TypeArguments().emplace_back(GlobalVoidType());
11343af6ab5fSopenharmony_ci                return promiseType;
11353af6ab5fSopenharmony_ci            };
11363af6ab5fSopenharmony_ci
11373af6ab5fSopenharmony_ci            returnType = implicitPromiseVoid();
11383af6ab5fSopenharmony_ci        }
11393af6ab5fSopenharmony_ci    } else if (func->IsEntryPoint() && returnTypeAnnotation->GetType(this) == GlobalVoidType()) {
11403af6ab5fSopenharmony_ci        returnType = GlobalVoidType();
11413af6ab5fSopenharmony_ci    } else {
11423af6ab5fSopenharmony_ci        returnType = returnTypeAnnotation->GetType(this);
11433af6ab5fSopenharmony_ci        returnTypeAnnotation->SetTsType(returnType);
11443af6ab5fSopenharmony_ci    }
11453af6ab5fSopenharmony_ci
11463af6ab5fSopenharmony_ci    return returnType;
11473af6ab5fSopenharmony_ci}
11483af6ab5fSopenharmony_ci
11493af6ab5fSopenharmony_ciSignatureInfo *ETSChecker::ComposeSignatureInfo(ir::ScriptFunction *func)
11503af6ab5fSopenharmony_ci{
11513af6ab5fSopenharmony_ci    auto *signatureInfo = CreateSignatureInfo();
11523af6ab5fSopenharmony_ci    signatureInfo->restVar = nullptr;
11533af6ab5fSopenharmony_ci    signatureInfo->minArgCount = 0;
11543af6ab5fSopenharmony_ci
11553af6ab5fSopenharmony_ci    if ((func->IsConstructor() || !func->IsStatic()) && !func->IsArrow()) {
11563af6ab5fSopenharmony_ci        auto *thisVar = func->Scope()->ParamScope()->Params().front();
11573af6ab5fSopenharmony_ci        thisVar->SetTsType(Context().ContainingClass());
11583af6ab5fSopenharmony_ci    }
11593af6ab5fSopenharmony_ci
11603af6ab5fSopenharmony_ci    if (func->TypeParams() != nullptr) {
11613af6ab5fSopenharmony_ci        auto [typeParamTypes, ok] = CreateUnconstrainedTypeParameters(func->TypeParams());
11623af6ab5fSopenharmony_ci        signatureInfo->typeParams = std::move(typeParamTypes);
11633af6ab5fSopenharmony_ci        if (ok) {
11643af6ab5fSopenharmony_ci            AssignTypeParameterConstraints(func->TypeParams());
11653af6ab5fSopenharmony_ci        }
11663af6ab5fSopenharmony_ci    }
11673af6ab5fSopenharmony_ci
11683af6ab5fSopenharmony_ci    for (auto *const it : func->Params()) {
11693af6ab5fSopenharmony_ci        auto *const param = it->AsETSParameterExpression();
11703af6ab5fSopenharmony_ci
11713af6ab5fSopenharmony_ci        if (param->IsRestParameter()) {
11723af6ab5fSopenharmony_ci            auto const *const restIdent = param->Ident();
11733af6ab5fSopenharmony_ci
11743af6ab5fSopenharmony_ci            ASSERT(restIdent->Variable());
11753af6ab5fSopenharmony_ci            signatureInfo->restVar = restIdent->Variable()->AsLocalVariable();
11763af6ab5fSopenharmony_ci
11773af6ab5fSopenharmony_ci            auto *const restParamTypeAnnotation = param->TypeAnnotation();
11783af6ab5fSopenharmony_ci            ASSERT(restParamTypeAnnotation);
11793af6ab5fSopenharmony_ci
11803af6ab5fSopenharmony_ci            signatureInfo->restVar->SetTsType(restParamTypeAnnotation->GetType(this));
11813af6ab5fSopenharmony_ci            auto arrayType = signatureInfo->restVar->TsType()->AsETSArrayType();
11823af6ab5fSopenharmony_ci            CreateBuiltinArraySignature(arrayType, arrayType->Rank());
11833af6ab5fSopenharmony_ci        } else {
11843af6ab5fSopenharmony_ci            auto *const paramIdent = param->Ident();
11853af6ab5fSopenharmony_ci
11863af6ab5fSopenharmony_ci            varbinder::Variable *const paramVar = paramIdent->Variable();
11873af6ab5fSopenharmony_ci            ASSERT(paramVar);
11883af6ab5fSopenharmony_ci
11893af6ab5fSopenharmony_ci            auto *const paramTypeAnnotation = param->TypeAnnotation();
11903af6ab5fSopenharmony_ci            if (paramIdent->TsType() == nullptr && paramTypeAnnotation == nullptr) {
11913af6ab5fSopenharmony_ci                LogTypeError({"The type of parameter '", paramIdent->Name(), "' cannot be determined"}, param->Start());
11923af6ab5fSopenharmony_ci                return nullptr;
11933af6ab5fSopenharmony_ci            }
11943af6ab5fSopenharmony_ci
11953af6ab5fSopenharmony_ci            if (paramIdent->TsType() == nullptr) {
11963af6ab5fSopenharmony_ci                ASSERT(paramTypeAnnotation);
11973af6ab5fSopenharmony_ci
11983af6ab5fSopenharmony_ci                paramVar->SetTsType(paramTypeAnnotation->GetType(this));
11993af6ab5fSopenharmony_ci            } else {
12003af6ab5fSopenharmony_ci                paramVar->SetTsType(paramIdent->TsTypeOrError());
12013af6ab5fSopenharmony_ci            }
12023af6ab5fSopenharmony_ci            signatureInfo->params.push_back(paramVar->AsLocalVariable());
12033af6ab5fSopenharmony_ci            ++signatureInfo->minArgCount;
12043af6ab5fSopenharmony_ci        }
12053af6ab5fSopenharmony_ci    }
12063af6ab5fSopenharmony_ci
12073af6ab5fSopenharmony_ci    return signatureInfo;
12083af6ab5fSopenharmony_ci}
12093af6ab5fSopenharmony_ci
12103af6ab5fSopenharmony_ciArenaVector<SignatureInfo *> ETSChecker::ComposeSignatureInfosForArrowFunction(
12113af6ab5fSopenharmony_ci    ir::ArrowFunctionExpression *arrowFuncExpr)
12123af6ab5fSopenharmony_ci{
12133af6ab5fSopenharmony_ci    ArenaVector<SignatureInfo *> signatureInfos(Allocator()->Adapter());
12143af6ab5fSopenharmony_ci
12153af6ab5fSopenharmony_ci    for (size_t i = arrowFuncExpr->Function()->DefaultParamIndex(); i < arrowFuncExpr->Function()->Params().size();
12163af6ab5fSopenharmony_ci         i++) {
12173af6ab5fSopenharmony_ci        auto *signatureInfo = CreateSignatureInfo();
12183af6ab5fSopenharmony_ci        signatureInfo->restVar = nullptr;
12193af6ab5fSopenharmony_ci        signatureInfo->minArgCount = 0;
12203af6ab5fSopenharmony_ci
12213af6ab5fSopenharmony_ci        if (arrowFuncExpr->Function()->TypeParams() != nullptr) {
12223af6ab5fSopenharmony_ci            signatureInfo->typeParams =
12233af6ab5fSopenharmony_ci                CreateUnconstrainedTypeParameters(arrowFuncExpr->Function()->TypeParams()).first;
12243af6ab5fSopenharmony_ci        }
12253af6ab5fSopenharmony_ci
12263af6ab5fSopenharmony_ci        for (size_t j = 0; j < i; j++) {
12273af6ab5fSopenharmony_ci            SetParamForSignatureInfoOfArrowFunction(signatureInfo,
12283af6ab5fSopenharmony_ci                                                    arrowFuncExpr->Function()->Params()[j]->AsETSParameterExpression());
12293af6ab5fSopenharmony_ci        }
12303af6ab5fSopenharmony_ci
12313af6ab5fSopenharmony_ci        signatureInfos.push_back(signatureInfo);
12323af6ab5fSopenharmony_ci    }
12333af6ab5fSopenharmony_ci
12343af6ab5fSopenharmony_ci    return signatureInfos;
12353af6ab5fSopenharmony_ci}
12363af6ab5fSopenharmony_ci
12373af6ab5fSopenharmony_civoid ETSChecker::SetParamForSignatureInfoOfArrowFunction(SignatureInfo *signatureInfo,
12383af6ab5fSopenharmony_ci                                                         ir::ETSParameterExpression *param)
12393af6ab5fSopenharmony_ci{
12403af6ab5fSopenharmony_ci    if (param->IsRestParameter()) {
12413af6ab5fSopenharmony_ci        auto const *const restIdent = param->Ident();
12423af6ab5fSopenharmony_ci
12433af6ab5fSopenharmony_ci        ASSERT(restIdent->Variable());
12443af6ab5fSopenharmony_ci        signatureInfo->restVar = restIdent->Variable()->AsLocalVariable();
12453af6ab5fSopenharmony_ci
12463af6ab5fSopenharmony_ci        auto *const restParamTypeAnnotation = param->TypeAnnotation();
12473af6ab5fSopenharmony_ci        ASSERT(restParamTypeAnnotation);
12483af6ab5fSopenharmony_ci
12493af6ab5fSopenharmony_ci        signatureInfo->restVar->SetTsType(restParamTypeAnnotation->GetType(this));
12503af6ab5fSopenharmony_ci        auto arrayType = signatureInfo->restVar->TsType()->AsETSArrayType();
12513af6ab5fSopenharmony_ci        CreateBuiltinArraySignature(arrayType, arrayType->Rank());
12523af6ab5fSopenharmony_ci    } else {
12533af6ab5fSopenharmony_ci        auto *const paramIdent = param->Ident();
12543af6ab5fSopenharmony_ci
12553af6ab5fSopenharmony_ci        varbinder::Variable *const paramVar = paramIdent->Variable();
12563af6ab5fSopenharmony_ci        ASSERT(paramVar);
12573af6ab5fSopenharmony_ci
12583af6ab5fSopenharmony_ci        auto *const paramTypeAnnotation = param->TypeAnnotation();
12593af6ab5fSopenharmony_ci        if (paramIdent->TsType() == nullptr) {
12603af6ab5fSopenharmony_ci            ASSERT(paramTypeAnnotation);
12613af6ab5fSopenharmony_ci
12623af6ab5fSopenharmony_ci            paramVar->SetTsType(paramTypeAnnotation->GetType(this));
12633af6ab5fSopenharmony_ci        } else {
12643af6ab5fSopenharmony_ci            paramVar->SetTsType(paramIdent->TsType());
12653af6ab5fSopenharmony_ci        }
12663af6ab5fSopenharmony_ci        signatureInfo->params.push_back(paramVar->AsLocalVariable());
12673af6ab5fSopenharmony_ci        ++signatureInfo->minArgCount;
12683af6ab5fSopenharmony_ci    }
12693af6ab5fSopenharmony_ci}
12703af6ab5fSopenharmony_ci
12713af6ab5fSopenharmony_civoid ETSChecker::ValidateMainSignature(ir::ScriptFunction *func)
12723af6ab5fSopenharmony_ci{
12733af6ab5fSopenharmony_ci    if (func->Params().size() >= 2U) {
12743af6ab5fSopenharmony_ci        LogTypeError("0 or 1 argument are allowed", func->Start());
12753af6ab5fSopenharmony_ci        return;
12763af6ab5fSopenharmony_ci    }
12773af6ab5fSopenharmony_ci
12783af6ab5fSopenharmony_ci    if (func->Params().size() == 1) {
12793af6ab5fSopenharmony_ci        auto const *const param = func->Params()[0]->AsETSParameterExpression();
12803af6ab5fSopenharmony_ci
12813af6ab5fSopenharmony_ci        if (param->IsRestParameter()) {
12823af6ab5fSopenharmony_ci            LogTypeError("Rest parameter is not allowed in the 'main' function.", param->Start());
12833af6ab5fSopenharmony_ci        }
12843af6ab5fSopenharmony_ci
12853af6ab5fSopenharmony_ci        const auto paramType = param->Variable()->TsType();
12863af6ab5fSopenharmony_ci        if (!paramType->IsETSArrayType() || !paramType->AsETSArrayType()->ElementType()->IsETSStringType()) {
12873af6ab5fSopenharmony_ci            LogTypeError("Only 'string[]' type argument is allowed.", param->Start());
12883af6ab5fSopenharmony_ci        }
12893af6ab5fSopenharmony_ci    }
12903af6ab5fSopenharmony_ci}
12913af6ab5fSopenharmony_ci
12923af6ab5fSopenharmony_cistatic void AddSignatureFlags(const ir::ScriptFunction *const func, Signature *const signature)
12933af6ab5fSopenharmony_ci{
12943af6ab5fSopenharmony_ci    if (func->IsAbstract()) {
12953af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::ABSTRACT);
12963af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::VIRTUAL);
12973af6ab5fSopenharmony_ci    }
12983af6ab5fSopenharmony_ci
12993af6ab5fSopenharmony_ci    if (func->IsStatic()) {
13003af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::STATIC);
13013af6ab5fSopenharmony_ci    }
13023af6ab5fSopenharmony_ci
13033af6ab5fSopenharmony_ci    if (func->IsConstructor()) {
13043af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::CONSTRUCTOR);
13053af6ab5fSopenharmony_ci    }
13063af6ab5fSopenharmony_ci
13073af6ab5fSopenharmony_ci    if (func->Signature()->Owner()->GetDeclNode()->IsFinal() || func->IsFinal()) {
13083af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::FINAL);
13093af6ab5fSopenharmony_ci    }
13103af6ab5fSopenharmony_ci
13113af6ab5fSopenharmony_ci    if (func->IsPublic()) {
13123af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::PUBLIC);
13133af6ab5fSopenharmony_ci    } else if (func->IsInternal()) {
13143af6ab5fSopenharmony_ci        if (func->IsProtected()) {
13153af6ab5fSopenharmony_ci            signature->AddSignatureFlag(SignatureFlags::INTERNAL_PROTECTED);
13163af6ab5fSopenharmony_ci        } else {
13173af6ab5fSopenharmony_ci            signature->AddSignatureFlag(SignatureFlags::INTERNAL);
13183af6ab5fSopenharmony_ci        }
13193af6ab5fSopenharmony_ci    } else if (func->IsProtected()) {
13203af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::PROTECTED);
13213af6ab5fSopenharmony_ci    } else if (func->IsPrivate()) {
13223af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::PRIVATE);
13233af6ab5fSopenharmony_ci    }
13243af6ab5fSopenharmony_ci
13253af6ab5fSopenharmony_ci    if (func->IsSetter()) {
13263af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::SETTER);
13273af6ab5fSopenharmony_ci    } else if (func->IsGetter()) {
13283af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::GETTER);
13293af6ab5fSopenharmony_ci    }
13303af6ab5fSopenharmony_ci}
13313af6ab5fSopenharmony_ci
13323af6ab5fSopenharmony_civoid ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig)
13333af6ab5fSopenharmony_ci{
13343af6ab5fSopenharmony_ci    bool isArrow = func->IsArrow();
13353af6ab5fSopenharmony_ci    auto *nameVar = isArrow ? nullptr : func->Id()->Variable();
13363af6ab5fSopenharmony_ci    auto funcName = nameVar == nullptr ? util::StringView() : nameVar->Name();
13373af6ab5fSopenharmony_ci
13383af6ab5fSopenharmony_ci    auto *signatureInfo = ComposeSignatureInfo(func);
13393af6ab5fSopenharmony_ci    if (signatureInfo == nullptr) {
13403af6ab5fSopenharmony_ci        return;
13413af6ab5fSopenharmony_ci    }
13423af6ab5fSopenharmony_ci
13433af6ab5fSopenharmony_ci    if (funcName.Is(compiler::Signatures::MAIN) &&
13443af6ab5fSopenharmony_ci        func->Scope()->Name().Utf8().find(compiler::Signatures::ETS_GLOBAL) != std::string::npos) {
13453af6ab5fSopenharmony_ci        func->AddFlag(ir::ScriptFunctionFlags::ENTRY_POINT);
13463af6ab5fSopenharmony_ci    }
13473af6ab5fSopenharmony_ci    if (func->IsEntryPoint()) {
13483af6ab5fSopenharmony_ci        ValidateMainSignature(func);
13493af6ab5fSopenharmony_ci    }
13503af6ab5fSopenharmony_ci
13513af6ab5fSopenharmony_ci    auto *returnType = ComposeReturnType(func);
13523af6ab5fSopenharmony_ci    auto *signature = ComposeSignature(func, signatureInfo, returnType, nameVar);
13533af6ab5fSopenharmony_ci    if (isConstructSig) {
13543af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::CONSTRUCT);
13553af6ab5fSopenharmony_ci    } else {
13563af6ab5fSopenharmony_ci        signature->AddSignatureFlag(SignatureFlags::CALL);
13573af6ab5fSopenharmony_ci    }
13583af6ab5fSopenharmony_ci    func->SetSignature(signature);
13593af6ab5fSopenharmony_ci    AddSignatureFlags(func, signature);
13603af6ab5fSopenharmony_ci    VarBinder()->AsETSBinder()->BuildFunctionName(func);
13613af6ab5fSopenharmony_ci}
13623af6ab5fSopenharmony_ci
13633af6ab5fSopenharmony_cichecker::ETSFunctionType *ETSChecker::BuildNamedFunctionType(ir::ScriptFunction *func)
13643af6ab5fSopenharmony_ci{
13653af6ab5fSopenharmony_ci    ASSERT(!func->IsArrow());
13663af6ab5fSopenharmony_ci    auto *nameVar = func->Id()->Variable();
13673af6ab5fSopenharmony_ci    auto *funcType = CreateETSFunctionType(func, func->Signature(), nameVar->Name());
13683af6ab5fSopenharmony_ci    funcType->SetVariable(nameVar);
13693af6ab5fSopenharmony_ci    return funcType;
13703af6ab5fSopenharmony_ci}
13713af6ab5fSopenharmony_ci
13723af6ab5fSopenharmony_ciSignature *ETSChecker::CheckEveryAbstractSignatureIsOverridden(ETSFunctionType *target, ETSFunctionType *source)
13733af6ab5fSopenharmony_ci{
13743af6ab5fSopenharmony_ci    for (auto targetSig = target->CallSignatures().begin(); targetSig != target->CallSignatures().end();) {
13753af6ab5fSopenharmony_ci        if (!(*targetSig)->HasSignatureFlag(SignatureFlags::ABSTRACT)) {
13763af6ab5fSopenharmony_ci            continue;
13773af6ab5fSopenharmony_ci        }
13783af6ab5fSopenharmony_ci
13793af6ab5fSopenharmony_ci        bool isOverridden = false;
13803af6ab5fSopenharmony_ci        for (auto sourceSig : source->CallSignatures()) {
13813af6ab5fSopenharmony_ci            if ((*targetSig)->Function()->Id()->Name() == sourceSig->Function()->Id()->Name() &&
13823af6ab5fSopenharmony_ci                Relation()->IsCompatibleTo(*targetSig, sourceSig)) {
13833af6ab5fSopenharmony_ci                target->CallSignatures().erase(targetSig);
13843af6ab5fSopenharmony_ci                isOverridden = true;
13853af6ab5fSopenharmony_ci                break;
13863af6ab5fSopenharmony_ci            }
13873af6ab5fSopenharmony_ci            sourceSig++;
13883af6ab5fSopenharmony_ci        }
13893af6ab5fSopenharmony_ci
13903af6ab5fSopenharmony_ci        if (!isOverridden) {
13913af6ab5fSopenharmony_ci            return *targetSig;
13923af6ab5fSopenharmony_ci        }
13933af6ab5fSopenharmony_ci    }
13943af6ab5fSopenharmony_ci
13953af6ab5fSopenharmony_ci    return nullptr;
13963af6ab5fSopenharmony_ci}
13973af6ab5fSopenharmony_ci
13983af6ab5fSopenharmony_cibool ETSChecker::IsOverridableIn(Signature *signature)
13993af6ab5fSopenharmony_ci{
14003af6ab5fSopenharmony_ci    if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) {
14013af6ab5fSopenharmony_ci        return false;
14023af6ab5fSopenharmony_ci    }
14033af6ab5fSopenharmony_ci
14043af6ab5fSopenharmony_ci    // NOTE: #15095 workaround, separate internal visibility check
14053af6ab5fSopenharmony_ci    if (signature->HasSignatureFlag(SignatureFlags::PUBLIC | SignatureFlags::INTERNAL)) {
14063af6ab5fSopenharmony_ci        return true;
14073af6ab5fSopenharmony_ci    }
14083af6ab5fSopenharmony_ci
14093af6ab5fSopenharmony_ci    return signature->HasSignatureFlag(SignatureFlags::PROTECTED);
14103af6ab5fSopenharmony_ci}
14113af6ab5fSopenharmony_ci
14123af6ab5fSopenharmony_cibool ETSChecker::IsMethodOverridesOther(Signature *base, Signature *derived)
14133af6ab5fSopenharmony_ci{
14143af6ab5fSopenharmony_ci    if (derived->Function()->IsConstructor()) {
14153af6ab5fSopenharmony_ci        return false;
14163af6ab5fSopenharmony_ci    }
14173af6ab5fSopenharmony_ci
14183af6ab5fSopenharmony_ci    if (base == derived) {
14193af6ab5fSopenharmony_ci        return true;
14203af6ab5fSopenharmony_ci    }
14213af6ab5fSopenharmony_ci
14223af6ab5fSopenharmony_ci    if (derived->HasSignatureFlag(SignatureFlags::STATIC) != base->HasSignatureFlag(SignatureFlags::STATIC)) {
14233af6ab5fSopenharmony_ci        return false;
14243af6ab5fSopenharmony_ci    }
14253af6ab5fSopenharmony_ci
14263af6ab5fSopenharmony_ci    if (IsOverridableIn(base)) {
14273af6ab5fSopenharmony_ci        SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::NO_RETURN_TYPE_CHECK |
14283af6ab5fSopenharmony_ci                                                                    TypeRelationFlag::OVERRIDING_CONTEXT);
14293af6ab5fSopenharmony_ci        if (Relation()->IsCompatibleTo(base, derived)) {
14303af6ab5fSopenharmony_ci            CheckThrowMarkers(base, derived);
14313af6ab5fSopenharmony_ci
14323af6ab5fSopenharmony_ci            if (derived->HasSignatureFlag(SignatureFlags::STATIC)) {
14333af6ab5fSopenharmony_ci                return false;
14343af6ab5fSopenharmony_ci            }
14353af6ab5fSopenharmony_ci
14363af6ab5fSopenharmony_ci            derived->Function()->SetOverride();
14373af6ab5fSopenharmony_ci            return true;
14383af6ab5fSopenharmony_ci        }
14393af6ab5fSopenharmony_ci    }
14403af6ab5fSopenharmony_ci
14413af6ab5fSopenharmony_ci    return false;
14423af6ab5fSopenharmony_ci}
14433af6ab5fSopenharmony_ci
14443af6ab5fSopenharmony_cibool ETSChecker::CheckThrowMarkers(Signature *source, Signature *target)
14453af6ab5fSopenharmony_ci{
14463af6ab5fSopenharmony_ci    ir::ScriptFunctionFlags throwMarkers = ir::ScriptFunctionFlags::THROWS | ir::ScriptFunctionFlags::RETHROWS;
14473af6ab5fSopenharmony_ci    if ((source->Function()->Flags() & throwMarkers) == (target->Function()->Flags() & throwMarkers)) {
14483af6ab5fSopenharmony_ci        return true;
14493af6ab5fSopenharmony_ci    }
14503af6ab5fSopenharmony_ci
14513af6ab5fSopenharmony_ci    if ((source->Function()->IsRethrowing() && target->Function()->IsThrowing()) ||
14523af6ab5fSopenharmony_ci        (!source->Function()->IsThrowing() &&
14533af6ab5fSopenharmony_ci         (target->Function()->IsRethrowing() || target->Function()->IsThrowing()))) {
14543af6ab5fSopenharmony_ci        ThrowTypeError(
14553af6ab5fSopenharmony_ci            "A method that overrides or hides another method cannot change throw or rethrow clauses of the "
14563af6ab5fSopenharmony_ci            "overridden "
14573af6ab5fSopenharmony_ci            "or hidden method.",
14583af6ab5fSopenharmony_ci            target->Function()->Body() == nullptr ? target->Function()->Start() : target->Function()->Body()->Start());
14593af6ab5fSopenharmony_ci        return false;
14603af6ab5fSopenharmony_ci    }
14613af6ab5fSopenharmony_ci    return true;
14623af6ab5fSopenharmony_ci}
14633af6ab5fSopenharmony_ci
14643af6ab5fSopenharmony_ciOverrideErrorCode ETSChecker::CheckOverride(Signature *signature, Signature *other)
14653af6ab5fSopenharmony_ci{
14663af6ab5fSopenharmony_ci    if (other->HasSignatureFlag(SignatureFlags::STATIC)) {
14673af6ab5fSopenharmony_ci        ASSERT(signature->HasSignatureFlag(SignatureFlags::STATIC));
14683af6ab5fSopenharmony_ci        return OverrideErrorCode::NO_ERROR;
14693af6ab5fSopenharmony_ci    }
14703af6ab5fSopenharmony_ci
14713af6ab5fSopenharmony_ci    if (other->IsFinal()) {
14723af6ab5fSopenharmony_ci        return OverrideErrorCode::OVERRIDDEN_FINAL;
14733af6ab5fSopenharmony_ci    }
14743af6ab5fSopenharmony_ci
14753af6ab5fSopenharmony_ci    if (!other->ReturnType()->IsETSTypeParameter()) {
14763af6ab5fSopenharmony_ci        if (!IsReturnTypeSubstitutable(signature, other)) {
14773af6ab5fSopenharmony_ci            return OverrideErrorCode::INCOMPATIBLE_RETURN;
14783af6ab5fSopenharmony_ci        }
14793af6ab5fSopenharmony_ci    } else {
14803af6ab5fSopenharmony_ci        // We need to have this branch to allow generic overriding of the form:
14813af6ab5fSopenharmony_ci        // foo<T>(x: T): T -> foo<someClass>(x: someClass): someClass
14823af6ab5fSopenharmony_ci        if (!signature->ReturnType()->IsETSReferenceType()) {
14833af6ab5fSopenharmony_ci            return OverrideErrorCode::INCOMPATIBLE_RETURN;
14843af6ab5fSopenharmony_ci        }
14853af6ab5fSopenharmony_ci    }
14863af6ab5fSopenharmony_ci
14873af6ab5fSopenharmony_ci    if (signature->ProtectionFlag() > other->ProtectionFlag()) {
14883af6ab5fSopenharmony_ci        return OverrideErrorCode::OVERRIDDEN_WEAKER;
14893af6ab5fSopenharmony_ci    }
14903af6ab5fSopenharmony_ci
14913af6ab5fSopenharmony_ci    return OverrideErrorCode::NO_ERROR;
14923af6ab5fSopenharmony_ci}
14933af6ab5fSopenharmony_ci
14943af6ab5fSopenharmony_ciSignature *ETSChecker::AdjustForTypeParameters(Signature *source, Signature *target)
14953af6ab5fSopenharmony_ci{
14963af6ab5fSopenharmony_ci    auto &sourceTypeParams = source->GetSignatureInfo()->typeParams;
14973af6ab5fSopenharmony_ci    auto &targetTypeParams = target->GetSignatureInfo()->typeParams;
14983af6ab5fSopenharmony_ci    if (sourceTypeParams.size() != targetTypeParams.size()) {
14993af6ab5fSopenharmony_ci        return nullptr;
15003af6ab5fSopenharmony_ci    }
15013af6ab5fSopenharmony_ci    if (sourceTypeParams.empty()) {
15023af6ab5fSopenharmony_ci        return target;
15033af6ab5fSopenharmony_ci    }
15043af6ab5fSopenharmony_ci    auto *substitution = NewSubstitution();
15053af6ab5fSopenharmony_ci    for (size_t ix = 0; ix < sourceTypeParams.size(); ix++) {
15063af6ab5fSopenharmony_ci        if (!targetTypeParams[ix]->IsETSTypeParameter()) {
15073af6ab5fSopenharmony_ci            continue;
15083af6ab5fSopenharmony_ci        }
15093af6ab5fSopenharmony_ci        ETSChecker::EmplaceSubstituted(substitution, targetTypeParams[ix]->AsETSTypeParameter(), sourceTypeParams[ix]);
15103af6ab5fSopenharmony_ci    }
15113af6ab5fSopenharmony_ci    return target->Substitute(Relation(), substitution);
15123af6ab5fSopenharmony_ci}
15133af6ab5fSopenharmony_ci
15143af6ab5fSopenharmony_civoid ETSChecker::ReportOverrideError(Signature *signature, Signature *overriddenSignature,
15153af6ab5fSopenharmony_ci                                     const OverrideErrorCode &errorCode)
15163af6ab5fSopenharmony_ci{
15173af6ab5fSopenharmony_ci    const char *reason {};
15183af6ab5fSopenharmony_ci    switch (errorCode) {
15193af6ab5fSopenharmony_ci        case OverrideErrorCode::OVERRIDDEN_FINAL: {
15203af6ab5fSopenharmony_ci            reason = "overridden method is final.";
15213af6ab5fSopenharmony_ci            break;
15223af6ab5fSopenharmony_ci        }
15233af6ab5fSopenharmony_ci        case OverrideErrorCode::INCOMPATIBLE_RETURN: {
15243af6ab5fSopenharmony_ci            reason = "overriding return type is not compatible with the other return type.";
15253af6ab5fSopenharmony_ci            break;
15263af6ab5fSopenharmony_ci        }
15273af6ab5fSopenharmony_ci        case OverrideErrorCode::OVERRIDDEN_WEAKER: {
15283af6ab5fSopenharmony_ci            reason = "overridden method has weaker access privilege.";
15293af6ab5fSopenharmony_ci            break;
15303af6ab5fSopenharmony_ci        }
15313af6ab5fSopenharmony_ci        default: {
15323af6ab5fSopenharmony_ci            UNREACHABLE();
15333af6ab5fSopenharmony_ci        }
15343af6ab5fSopenharmony_ci    }
15353af6ab5fSopenharmony_ci
15363af6ab5fSopenharmony_ci    LogTypeError({signature->Function()->Id()->Name(), signature, " in ", signature->Owner(), " cannot override ",
15373af6ab5fSopenharmony_ci                  overriddenSignature->Function()->Id()->Name(), overriddenSignature, " in ",
15383af6ab5fSopenharmony_ci                  overriddenSignature->Owner(), " because ", reason},
15393af6ab5fSopenharmony_ci                 signature->Function()->Start());
15403af6ab5fSopenharmony_ci}
15413af6ab5fSopenharmony_ci
15423af6ab5fSopenharmony_cibool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site)
15433af6ab5fSopenharmony_ci{
15443af6ab5fSopenharmony_ci    auto *target = site->GetProperty(signature->Function()->Id()->Name(), PropertySearchFlags::SEARCH_METHOD);
15453af6ab5fSopenharmony_ci    bool isOverridingAnySignature = false;
15463af6ab5fSopenharmony_ci
15473af6ab5fSopenharmony_ci    if (target == nullptr) {
15483af6ab5fSopenharmony_ci        return isOverridingAnySignature;
15493af6ab5fSopenharmony_ci    }
15503af6ab5fSopenharmony_ci
15513af6ab5fSopenharmony_ci    for (auto *it : target->TsType()->AsETSFunctionType()->CallSignatures()) {
15523af6ab5fSopenharmony_ci        auto *itSubst = AdjustForTypeParameters(signature, it);
15533af6ab5fSopenharmony_ci
15543af6ab5fSopenharmony_ci        if (itSubst == nullptr) {
15553af6ab5fSopenharmony_ci            continue;
15563af6ab5fSopenharmony_ci        }
15573af6ab5fSopenharmony_ci
15583af6ab5fSopenharmony_ci        if (itSubst->HasSignatureFlag(SignatureFlags::ABSTRACT) || site->HasObjectFlag(ETSObjectFlags::INTERFACE)) {
15593af6ab5fSopenharmony_ci            if (site->HasObjectFlag(ETSObjectFlags::INTERFACE) && !CheckThrowMarkers(itSubst, signature)) {
15603af6ab5fSopenharmony_ci                return false;
15613af6ab5fSopenharmony_ci            }
15623af6ab5fSopenharmony_ci
15633af6ab5fSopenharmony_ci            if ((itSubst->Function()->IsSetter() && !signature->Function()->IsSetter()) ||
15643af6ab5fSopenharmony_ci                (itSubst->Function()->IsGetter() && !signature->Function()->IsGetter())) {
15653af6ab5fSopenharmony_ci                continue;
15663af6ab5fSopenharmony_ci            }
15673af6ab5fSopenharmony_ci        }
15683af6ab5fSopenharmony_ci
15693af6ab5fSopenharmony_ci        if (!IsMethodOverridesOther(itSubst, signature)) {
15703af6ab5fSopenharmony_ci            continue;
15713af6ab5fSopenharmony_ci        }
15723af6ab5fSopenharmony_ci
15733af6ab5fSopenharmony_ci        if (auto err = CheckOverride(signature, itSubst); err != OverrideErrorCode::NO_ERROR) {
15743af6ab5fSopenharmony_ci            ReportOverrideError(signature, it, err);
15753af6ab5fSopenharmony_ci            return false;
15763af6ab5fSopenharmony_ci        }
15773af6ab5fSopenharmony_ci
15783af6ab5fSopenharmony_ci        if (signature->Owner()->HasObjectFlag(ETSObjectFlags::INTERFACE) &&
15793af6ab5fSopenharmony_ci            Relation()->IsIdenticalTo(itSubst->Owner(), GlobalETSObjectType()) &&
15803af6ab5fSopenharmony_ci            !itSubst->HasSignatureFlag(SignatureFlags::PRIVATE)) {
15813af6ab5fSopenharmony_ci            LogTypeError("Cannot override non-private method of the class Object from an interface.",
15823af6ab5fSopenharmony_ci                         signature->Function()->Start());
15833af6ab5fSopenharmony_ci            return false;
15843af6ab5fSopenharmony_ci        }
15853af6ab5fSopenharmony_ci
15863af6ab5fSopenharmony_ci        isOverridingAnySignature = true;
15873af6ab5fSopenharmony_ci        it->AddSignatureFlag(SignatureFlags::VIRTUAL);
15883af6ab5fSopenharmony_ci    }
15893af6ab5fSopenharmony_ci
15903af6ab5fSopenharmony_ci    return isOverridingAnySignature;
15913af6ab5fSopenharmony_ci}
15923af6ab5fSopenharmony_ci
15933af6ab5fSopenharmony_civoid ETSChecker::CheckOverride(Signature *signature)
15943af6ab5fSopenharmony_ci{
15953af6ab5fSopenharmony_ci    auto *owner = signature->Owner();
15963af6ab5fSopenharmony_ci    bool isOverriding = false;
15973af6ab5fSopenharmony_ci
15983af6ab5fSopenharmony_ci    if (!owner->HasObjectFlag(ETSObjectFlags::CLASS | ETSObjectFlags::INTERFACE)) {
15993af6ab5fSopenharmony_ci        return;
16003af6ab5fSopenharmony_ci    }
16013af6ab5fSopenharmony_ci
16023af6ab5fSopenharmony_ci    for (auto *const interface : owner->Interfaces()) {
16033af6ab5fSopenharmony_ci        isOverriding |= CheckInterfaceOverride(this, interface, signature);
16043af6ab5fSopenharmony_ci    }
16053af6ab5fSopenharmony_ci
16063af6ab5fSopenharmony_ci    ETSObjectType *iter = owner->SuperType();
16073af6ab5fSopenharmony_ci    while (iter != nullptr) {
16083af6ab5fSopenharmony_ci        isOverriding |= CheckOverride(signature, iter);
16093af6ab5fSopenharmony_ci
16103af6ab5fSopenharmony_ci        for (auto *const interface : iter->Interfaces()) {
16113af6ab5fSopenharmony_ci            isOverriding |= CheckInterfaceOverride(this, interface, signature);
16123af6ab5fSopenharmony_ci        }
16133af6ab5fSopenharmony_ci
16143af6ab5fSopenharmony_ci        iter = iter->SuperType();
16153af6ab5fSopenharmony_ci    }
16163af6ab5fSopenharmony_ci
16173af6ab5fSopenharmony_ci    if (!isOverriding && signature->Function()->IsOverride()) {
16183af6ab5fSopenharmony_ci        LogTypeError({"Method ", signature->Function()->Id()->Name(), signature, " in ", signature->Owner(),
16193af6ab5fSopenharmony_ci                      " not overriding any method"},
16203af6ab5fSopenharmony_ci                     signature->Function()->Start());
16213af6ab5fSopenharmony_ci    }
16223af6ab5fSopenharmony_ci}
16233af6ab5fSopenharmony_ci
16243af6ab5fSopenharmony_ciSignature *ETSChecker::GetSignatureFromMethodDefinition(const ir::MethodDefinition *methodDef)
16253af6ab5fSopenharmony_ci{
16263af6ab5fSopenharmony_ci    if (methodDef->TsTypeOrError()->IsTypeError()) {
16273af6ab5fSopenharmony_ci        return nullptr;
16283af6ab5fSopenharmony_ci    }
16293af6ab5fSopenharmony_ci    ASSERT(methodDef->TsType() && methodDef->TsType()->IsETSFunctionType());
16303af6ab5fSopenharmony_ci    for (auto *it : methodDef->TsType()->AsETSFunctionType()->CallSignatures()) {
16313af6ab5fSopenharmony_ci        if (it->Function() == methodDef->Function()) {
16323af6ab5fSopenharmony_ci            return it;
16333af6ab5fSopenharmony_ci        }
16343af6ab5fSopenharmony_ci    }
16353af6ab5fSopenharmony_ci
16363af6ab5fSopenharmony_ci    return nullptr;
16373af6ab5fSopenharmony_ci}
16383af6ab5fSopenharmony_ci
16393af6ab5fSopenharmony_civoid ETSChecker::ValidateSignatureAccessibility(ETSObjectType *callee, const ir::CallExpression *callExpr,
16403af6ab5fSopenharmony_ci                                                Signature *signature, const lexer::SourcePosition &pos,
16413af6ab5fSopenharmony_ci                                                char const *errorMessage)
16423af6ab5fSopenharmony_ci{
16433af6ab5fSopenharmony_ci    if ((Context().Status() & CheckerStatus::IGNORE_VISIBILITY) != 0U ||
16443af6ab5fSopenharmony_ci        (!signature->HasSignatureFlag(SignatureFlags::PRIVATE) &&
16453af6ab5fSopenharmony_ci         !signature->HasSignatureFlag(SignatureFlags::PROTECTED))) {
16463af6ab5fSopenharmony_ci        return;
16473af6ab5fSopenharmony_ci    }
16483af6ab5fSopenharmony_ci    const auto *declNode = callee->GetDeclNode();
16493af6ab5fSopenharmony_ci    auto *containingClass = Context().ContainingClass();
16503af6ab5fSopenharmony_ci    bool isContainingSignatureInherited = containingClass->IsSignatureInherited(signature);
16513af6ab5fSopenharmony_ci    ASSERT(declNode && (declNode->IsClassDefinition() || declNode->IsTSInterfaceDeclaration()));
16523af6ab5fSopenharmony_ci
16533af6ab5fSopenharmony_ci    if (declNode->IsTSInterfaceDeclaration()) {
16543af6ab5fSopenharmony_ci        const auto *enclosingFunc =
16553af6ab5fSopenharmony_ci            util::Helpers::FindAncestorGivenByType(callExpr, ir::AstNodeType::SCRIPT_FUNCTION)->AsScriptFunction();
16563af6ab5fSopenharmony_ci        if (callExpr->Callee()->IsMemberExpression() &&
16573af6ab5fSopenharmony_ci            callExpr->Callee()->AsMemberExpression()->Object()->IsThisExpression() &&
16583af6ab5fSopenharmony_ci            signature->Function()->IsPrivate() && !enclosingFunc->IsPrivate()) {
16593af6ab5fSopenharmony_ci            LogTypeError({"Cannot reference 'this' in this context."}, enclosingFunc->Start());
16603af6ab5fSopenharmony_ci        }
16613af6ab5fSopenharmony_ci
16623af6ab5fSopenharmony_ci        if (containingClass == declNode->AsTSInterfaceDeclaration()->TsType() && isContainingSignatureInherited) {
16633af6ab5fSopenharmony_ci            return;
16643af6ab5fSopenharmony_ci        }
16653af6ab5fSopenharmony_ci    }
16663af6ab5fSopenharmony_ci    if (containingClass == declNode->AsClassDefinition()->TsType() && isContainingSignatureInherited) {
16673af6ab5fSopenharmony_ci        return;
16683af6ab5fSopenharmony_ci    }
16693af6ab5fSopenharmony_ci
16703af6ab5fSopenharmony_ci    bool isSignatureInherited = callee->IsSignatureInherited(signature);
16713af6ab5fSopenharmony_ci    const auto *currentOutermost = containingClass->OutermostClass();
16723af6ab5fSopenharmony_ci    if (!signature->HasSignatureFlag(SignatureFlags::PRIVATE) &&
16733af6ab5fSopenharmony_ci        ((signature->HasSignatureFlag(SignatureFlags::PROTECTED) && containingClass->IsDescendantOf(callee)) ||
16743af6ab5fSopenharmony_ci         (currentOutermost != nullptr && currentOutermost == callee->OutermostClass())) &&
16753af6ab5fSopenharmony_ci        isSignatureInherited) {
16763af6ab5fSopenharmony_ci        return;
16773af6ab5fSopenharmony_ci    }
16783af6ab5fSopenharmony_ci
16793af6ab5fSopenharmony_ci    if (errorMessage == nullptr) {
16803af6ab5fSopenharmony_ci        LogTypeError({"Signature ", signature->Function()->Id()->Name(), signature, " is not visible here."}, pos);
16813af6ab5fSopenharmony_ci        return;
16823af6ab5fSopenharmony_ci    }
16833af6ab5fSopenharmony_ci    LogTypeError(errorMessage, pos);
16843af6ab5fSopenharmony_ci}
16853af6ab5fSopenharmony_ci
16863af6ab5fSopenharmony_civoid ETSChecker::CheckCapturedVariable(ir::AstNode *const node, varbinder::Variable *const var)
16873af6ab5fSopenharmony_ci{
16883af6ab5fSopenharmony_ci    if (node->IsIdentifier()) {
16893af6ab5fSopenharmony_ci        const auto *const parent = node->Parent();
16903af6ab5fSopenharmony_ci
16913af6ab5fSopenharmony_ci        if (parent->IsUpdateExpression() ||
16923af6ab5fSopenharmony_ci            (parent->IsAssignmentExpression() && parent->AsAssignmentExpression()->Left() == node)) {
16933af6ab5fSopenharmony_ci            const auto *const identNode = node->AsIdentifier();
16943af6ab5fSopenharmony_ci
16953af6ab5fSopenharmony_ci            const auto *resolved = identNode->Variable();
16963af6ab5fSopenharmony_ci
16973af6ab5fSopenharmony_ci            if (resolved == nullptr) {
16983af6ab5fSopenharmony_ci                resolved =
16993af6ab5fSopenharmony_ci                    FindVariableInFunctionScope(identNode->Name(), varbinder::ResolveBindingOptions::ALL_NON_TYPE);
17003af6ab5fSopenharmony_ci            }
17013af6ab5fSopenharmony_ci
17023af6ab5fSopenharmony_ci            if (resolved == nullptr) {
17033af6ab5fSopenharmony_ci                resolved = FindVariableInGlobal(identNode, varbinder::ResolveBindingOptions::ALL_NON_TYPE);
17043af6ab5fSopenharmony_ci            }
17053af6ab5fSopenharmony_ci
17063af6ab5fSopenharmony_ci            if (resolved == var) {
17073af6ab5fSopenharmony_ci                // For mutable captured variable [possible] smart-cast is senseless (or even erroneous)
17083af6ab5fSopenharmony_ci                Context().RemoveSmartCast(var);
17093af6ab5fSopenharmony_ci            }
17103af6ab5fSopenharmony_ci        }
17113af6ab5fSopenharmony_ci    }
17123af6ab5fSopenharmony_ci
17133af6ab5fSopenharmony_ci    CheckCapturedVariableInSubnodes(node, var);
17143af6ab5fSopenharmony_ci}
17153af6ab5fSopenharmony_ci
17163af6ab5fSopenharmony_civoid ETSChecker::CheckCapturedVariableInSubnodes(ir::AstNode *node, varbinder::Variable *var)
17173af6ab5fSopenharmony_ci{
17183af6ab5fSopenharmony_ci    if (!node->IsClassDefinition()) {
17193af6ab5fSopenharmony_ci        node->Iterate([this, var](ir::AstNode *childNode) { CheckCapturedVariable(childNode, var); });
17203af6ab5fSopenharmony_ci    }
17213af6ab5fSopenharmony_ci}
17223af6ab5fSopenharmony_ci
17233af6ab5fSopenharmony_civoid ETSChecker::CheckCapturedVariables()
17243af6ab5fSopenharmony_ci{
17253af6ab5fSopenharmony_ci    // If we want to capture non constant local variables, we should wrap them in a generic reference class
17263af6ab5fSopenharmony_ci    for (auto [var, _] : Context().CapturedVars()) {
17273af6ab5fSopenharmony_ci        (void)_;
17283af6ab5fSopenharmony_ci        if ((var->Declaration() == nullptr) || var->Declaration()->IsConstDecl() ||
17293af6ab5fSopenharmony_ci            !var->HasFlag(varbinder::VariableFlags::LOCAL) || var->GetScope()->Node()->IsArrowFunctionExpression()) {
17303af6ab5fSopenharmony_ci            continue;
17313af6ab5fSopenharmony_ci        }
17323af6ab5fSopenharmony_ci
17333af6ab5fSopenharmony_ci        auto *searchNode = var->Declaration()->Node()->Parent();
17343af6ab5fSopenharmony_ci
17353af6ab5fSopenharmony_ci        if (searchNode->IsVariableDeclarator()) {
17363af6ab5fSopenharmony_ci            searchNode = searchNode->Parent()->Parent();
17373af6ab5fSopenharmony_ci        }
17383af6ab5fSopenharmony_ci
17393af6ab5fSopenharmony_ci        CheckCapturedVariableInSubnodes(searchNode, var);
17403af6ab5fSopenharmony_ci    }
17413af6ab5fSopenharmony_ci}
17423af6ab5fSopenharmony_ci
17433af6ab5fSopenharmony_cibool ETSChecker::AreOverrideEquivalent(Signature *const s1, Signature *const s2)
17443af6ab5fSopenharmony_ci{
17453af6ab5fSopenharmony_ci    // Two functions, methods or constructors M and N have the same signature if
17463af6ab5fSopenharmony_ci    // their names and type parameters (if any) are the same, and their formal parameter
17473af6ab5fSopenharmony_ci    // types are also the same (after the formal parameter types of N are adapted to the type parameters of M).
17483af6ab5fSopenharmony_ci    // Signatures s1 and s2 are override-equivalent only if s1 and s2 are the same.
17493af6ab5fSopenharmony_ci
17503af6ab5fSopenharmony_ci    SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::OVERRIDING_CONTEXT);
17513af6ab5fSopenharmony_ci    return s1->Function()->Id()->Name() == s2->Function()->Id()->Name() && Relation()->IsCompatibleTo(s1, s2);
17523af6ab5fSopenharmony_ci}
17533af6ab5fSopenharmony_ci
17543af6ab5fSopenharmony_cibool ETSChecker::IsReturnTypeSubstitutable(Signature *const s1, Signature *const s2)
17553af6ab5fSopenharmony_ci{
17563af6ab5fSopenharmony_ci    auto *const r1 = s1->ReturnType();
17573af6ab5fSopenharmony_ci    auto *const r2 = s2->ReturnType();
17583af6ab5fSopenharmony_ci
17593af6ab5fSopenharmony_ci    // A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return
17603af6ab5fSopenharmony_ci    // type R2 if any of the following is true:
17613af6ab5fSopenharmony_ci
17623af6ab5fSopenharmony_ci    // - If R1 is a primitive type then R2 is identical to R1.
17633af6ab5fSopenharmony_ci    if (r1->HasTypeFlag(TypeFlag::ETS_PRIMITIVE | TypeFlag::ETS_INT_ENUM | TypeFlag::ETS_STRING_ENUM |
17643af6ab5fSopenharmony_ci                        TypeFlag::ETS_VOID)) {
17653af6ab5fSopenharmony_ci        return Relation()->IsIdenticalTo(r2, r1);
17663af6ab5fSopenharmony_ci    }
17673af6ab5fSopenharmony_ci
17683af6ab5fSopenharmony_ci    // - If R1 is a reference type then R1, adapted to the type parameters of d2 (link to generic methods), is a
17693af6ab5fSopenharmony_ci    // subtype of R2.
17703af6ab5fSopenharmony_ci    ASSERT(IsReferenceType(r1));
17713af6ab5fSopenharmony_ci
17723af6ab5fSopenharmony_ci    if (Relation()->IsSupertypeOf(r2, r1)) {
17733af6ab5fSopenharmony_ci        return true;
17743af6ab5fSopenharmony_ci    }
17753af6ab5fSopenharmony_ci
17763af6ab5fSopenharmony_ci    return s2->Function()->ReturnTypeAnnotation()->IsETSTypeReference() &&
17773af6ab5fSopenharmony_ci           Relation()->IsSupertypeOf(
17783af6ab5fSopenharmony_ci               s2->Function()->ReturnTypeAnnotation()->GetType(this)->AsETSTypeParameter()->GetConstraintType(), r1);
17793af6ab5fSopenharmony_ci}
17803af6ab5fSopenharmony_ci
17813af6ab5fSopenharmony_cistd::string ETSChecker::GetAsyncImplName(const util::StringView &name)
17823af6ab5fSopenharmony_ci{
17833af6ab5fSopenharmony_ci    std::string implName(name);
17843af6ab5fSopenharmony_ci    implName += "$asyncimpl";
17853af6ab5fSopenharmony_ci    return implName;
17863af6ab5fSopenharmony_ci}
17873af6ab5fSopenharmony_ci
17883af6ab5fSopenharmony_cistd::string ETSChecker::GetAsyncImplName(ir::MethodDefinition *asyncMethod)
17893af6ab5fSopenharmony_ci{
17903af6ab5fSopenharmony_ci    ir::Identifier *asyncName = asyncMethod->Function()->Id();
17913af6ab5fSopenharmony_ci    ASSERT(asyncName != nullptr);
17923af6ab5fSopenharmony_ci    return GetAsyncImplName(asyncName->Name());
17933af6ab5fSopenharmony_ci}
17943af6ab5fSopenharmony_ci
17953af6ab5fSopenharmony_cibool ETSChecker::IsAsyncImplMethod(ir::MethodDefinition const *method)
17963af6ab5fSopenharmony_ci{
17973af6ab5fSopenharmony_ci    auto methodName = method->Key()->AsIdentifier()->Name().Utf8();
17983af6ab5fSopenharmony_ci    std::string_view asyncSuffix = "$asyncimpl";
17993af6ab5fSopenharmony_ci    if (methodName.size() < asyncSuffix.size()) {
18003af6ab5fSopenharmony_ci        return false;
18013af6ab5fSopenharmony_ci    }
18023af6ab5fSopenharmony_ci    return methodName.substr(methodName.size() - asyncSuffix.size()) == asyncSuffix;
18033af6ab5fSopenharmony_ci}
18043af6ab5fSopenharmony_ci
18053af6ab5fSopenharmony_ciir::MethodDefinition *ETSChecker::CreateAsyncImplMethod(ir::MethodDefinition *asyncMethod,
18063af6ab5fSopenharmony_ci                                                        ir::ClassDefinition *classDef)
18073af6ab5fSopenharmony_ci{
18083af6ab5fSopenharmony_ci    util::UString implName(GetAsyncImplName(asyncMethod), Allocator());
18093af6ab5fSopenharmony_ci    ir::ModifierFlags modifiers = asyncMethod->Modifiers();
18103af6ab5fSopenharmony_ci    // clear ASYNC flag for implementation
18113af6ab5fSopenharmony_ci    modifiers &= ~ir::ModifierFlags::ASYNC;
18123af6ab5fSopenharmony_ci    ir::ScriptFunction *asyncFunc = asyncMethod->Function();
18133af6ab5fSopenharmony_ci    ir::ScriptFunctionFlags flags = ir::ScriptFunctionFlags::METHOD;
18143af6ab5fSopenharmony_ci
18153af6ab5fSopenharmony_ci    if (asyncFunc->IsProxy()) {
18163af6ab5fSopenharmony_ci        flags |= ir::ScriptFunctionFlags::PROXY;
18173af6ab5fSopenharmony_ci    }
18183af6ab5fSopenharmony_ci
18193af6ab5fSopenharmony_ci    if (asyncFunc->HasReturnStatement()) {
18203af6ab5fSopenharmony_ci        flags |= ir::ScriptFunctionFlags::HAS_RETURN;
18213af6ab5fSopenharmony_ci    }
18223af6ab5fSopenharmony_ci
18233af6ab5fSopenharmony_ci    asyncMethod->AddModifier(ir::ModifierFlags::NATIVE);
18243af6ab5fSopenharmony_ci    asyncFunc->AddModifier(ir::ModifierFlags::NATIVE);
18253af6ab5fSopenharmony_ci    // Create async_impl method copied from CreateInvokeFunction
18263af6ab5fSopenharmony_ci    auto scopeCtx =
18273af6ab5fSopenharmony_ci        varbinder::LexicalScope<varbinder::ClassScope>::Enter(VarBinder(), classDef->Scope()->AsClassScope());
18283af6ab5fSopenharmony_ci    auto *body = asyncFunc->Body();
18293af6ab5fSopenharmony_ci    ArenaVector<ir::Expression *> params(Allocator()->Adapter());
18303af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
18313af6ab5fSopenharmony_ci    varbinder::FunctionParamScope *paramScope = CopyParams(asyncFunc->Params(), params);
18323af6ab5fSopenharmony_ci
18333af6ab5fSopenharmony_ci    ir::ETSTypeReference *returnTypeAnn = nullptr;
18343af6ab5fSopenharmony_ci
18353af6ab5fSopenharmony_ci    if (!asyncFunc->Signature()->HasSignatureFlag(SignatureFlags::NEED_RETURN_TYPE)) {
18363af6ab5fSopenharmony_ci        // Set impl method return type "Object" because it may return Promise as well as Promise parameter's type
18373af6ab5fSopenharmony_ci        auto *objectId = AllocNode<ir::Identifier>(compiler::Signatures::BUILTIN_OBJECT_CLASS, Allocator());
18383af6ab5fSopenharmony_ci        objectId->SetReference();
18393af6ab5fSopenharmony_ci        VarBinder()->AsETSBinder()->LookupTypeReference(objectId, false);
18403af6ab5fSopenharmony_ci        returnTypeAnn =
18413af6ab5fSopenharmony_ci            AllocNode<ir::ETSTypeReference>(AllocNode<ir::ETSTypeReferencePart>(objectId, nullptr, nullptr));
18423af6ab5fSopenharmony_ci        objectId->SetParent(returnTypeAnn->Part());
18433af6ab5fSopenharmony_ci        returnTypeAnn->Part()->SetParent(returnTypeAnn);
18443af6ab5fSopenharmony_ci        auto *asyncFuncRetTypeAnn = asyncFunc->ReturnTypeAnnotation();
18453af6ab5fSopenharmony_ci        auto *promiseType = [this](ir::TypeNode *type) {
18463af6ab5fSopenharmony_ci            if (type != nullptr) {
18473af6ab5fSopenharmony_ci                return type->GetType(this)->AsETSObjectType();
18483af6ab5fSopenharmony_ci            }
18493af6ab5fSopenharmony_ci
18503af6ab5fSopenharmony_ci            return GlobalBuiltinPromiseType()->AsETSObjectType();
18513af6ab5fSopenharmony_ci        }(asyncFuncRetTypeAnn);
18523af6ab5fSopenharmony_ci        // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
18533af6ab5fSopenharmony_ci        auto *retType = Allocator()->New<ETSAsyncFuncReturnType>(Allocator(), Relation(), promiseType);
18543af6ab5fSopenharmony_ci        returnTypeAnn->SetTsType(retType);
18553af6ab5fSopenharmony_ci    }
18563af6ab5fSopenharmony_ci
18573af6ab5fSopenharmony_ci    ir::MethodDefinition *implMethod =
18583af6ab5fSopenharmony_ci        CreateMethod(implName.View(), modifiers, flags, std::move(params), paramScope, returnTypeAnn, body);
18593af6ab5fSopenharmony_ci    asyncFunc->SetBody(nullptr);
18603af6ab5fSopenharmony_ci
18613af6ab5fSopenharmony_ci    if (returnTypeAnn != nullptr) {
18623af6ab5fSopenharmony_ci        returnTypeAnn->SetParent(implMethod->Function());
18633af6ab5fSopenharmony_ci    }
18643af6ab5fSopenharmony_ci
18653af6ab5fSopenharmony_ci    implMethod->Function()->AddFlag(ir::ScriptFunctionFlags::ASYNC_IMPL);
18663af6ab5fSopenharmony_ci    implMethod->SetParent(asyncMethod->Parent());
18673af6ab5fSopenharmony_ci    return implMethod;
18683af6ab5fSopenharmony_ci}
18693af6ab5fSopenharmony_ci
18703af6ab5fSopenharmony_cistatic void CreateFuncDecl(ETSChecker *checker, ir::MethodDefinition *func, varbinder::LocalScope *scope)
18713af6ab5fSopenharmony_ci{
18723af6ab5fSopenharmony_ci    auto *allocator = checker->Allocator();
18733af6ab5fSopenharmony_ci    auto *varBinder = checker->VarBinder();
18743af6ab5fSopenharmony_ci    // Add the function declarations to the lambda class scope
18753af6ab5fSopenharmony_ci    auto ctx = varbinder::LexicalScope<varbinder::LocalScope>::Enter(varBinder, scope);
18763af6ab5fSopenharmony_ci    varbinder::Variable *var = scope->FindLocal(func->Id()->Name(), varbinder::ResolveBindingOptions::ALL_DECLARATION);
18773af6ab5fSopenharmony_ci    if (var == nullptr) {
18783af6ab5fSopenharmony_ci        var = std::get<1>(
18793af6ab5fSopenharmony_ci            varBinder->NewVarDecl<varbinder::FunctionDecl>(func->Start(), allocator, func->Id()->Name(), func));
18803af6ab5fSopenharmony_ci    }
18813af6ab5fSopenharmony_ci    var->AddFlag(varbinder::VariableFlags::METHOD);
18823af6ab5fSopenharmony_ci    var->SetScope(ctx.GetScope());
18833af6ab5fSopenharmony_ci    func->Function()->Id()->SetVariable(var);
18843af6ab5fSopenharmony_ci}
18853af6ab5fSopenharmony_ci
18863af6ab5fSopenharmony_ciir::MethodDefinition *ETSChecker::CreateAsyncProxy(ir::MethodDefinition *asyncMethod, ir::ClassDefinition *classDef,
18873af6ab5fSopenharmony_ci                                                   bool createDecl)
18883af6ab5fSopenharmony_ci{
18893af6ab5fSopenharmony_ci    ir::ScriptFunction *asyncFunc = asyncMethod->Function();
18903af6ab5fSopenharmony_ci    if (!asyncFunc->IsExternal()) {
18913af6ab5fSopenharmony_ci        VarBinder()->AsETSBinder()->GetRecordTable()->Signatures().push_back(asyncFunc->Scope());
18923af6ab5fSopenharmony_ci    }
18933af6ab5fSopenharmony_ci
18943af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
18953af6ab5fSopenharmony_ci    ir::MethodDefinition *implMethod = CreateAsyncImplMethod(asyncMethod, classDef);
18963af6ab5fSopenharmony_ci    varbinder::FunctionScope *implFuncScope = implMethod->Function()->Scope();
18973af6ab5fSopenharmony_ci    for (auto *decl : asyncFunc->Scope()->Decls()) {
18983af6ab5fSopenharmony_ci        auto res = asyncFunc->Scope()->Bindings().find(decl->Name());
18993af6ab5fSopenharmony_ci        ASSERT(res != asyncFunc->Scope()->Bindings().end());
19003af6ab5fSopenharmony_ci        auto *const var = std::get<1>(*res);
19013af6ab5fSopenharmony_ci        var->SetScope(implFuncScope);
19023af6ab5fSopenharmony_ci        implFuncScope->Decls().push_back(decl);
19033af6ab5fSopenharmony_ci        implFuncScope->InsertBinding(decl->Name(), var);
19043af6ab5fSopenharmony_ci    }
19053af6ab5fSopenharmony_ci
19063af6ab5fSopenharmony_ci    ReplaceScope(implMethod->Function()->Body(), asyncFunc, implFuncScope);
19073af6ab5fSopenharmony_ci
19083af6ab5fSopenharmony_ci    ArenaVector<varbinder::Variable *> captured(Allocator()->Adapter());
19093af6ab5fSopenharmony_ci
19103af6ab5fSopenharmony_ci    bool isStatic = asyncMethod->IsStatic();
19113af6ab5fSopenharmony_ci    if (createDecl) {
19123af6ab5fSopenharmony_ci        if (isStatic) {
19133af6ab5fSopenharmony_ci            CreateFuncDecl(this, implMethod, classDef->Scope()->AsClassScope()->StaticMethodScope());
19143af6ab5fSopenharmony_ci        } else {
19153af6ab5fSopenharmony_ci            CreateFuncDecl(this, implMethod, classDef->Scope()->AsClassScope()->InstanceMethodScope());
19163af6ab5fSopenharmony_ci        }
19173af6ab5fSopenharmony_ci        implMethod->Id()->SetVariable(implMethod->Function()->Id()->Variable());
19183af6ab5fSopenharmony_ci    }
19193af6ab5fSopenharmony_ci    VarBinder()->AsETSBinder()->BuildProxyMethod(implMethod->Function(), classDef->InternalName(), isStatic,
19203af6ab5fSopenharmony_ci                                                 asyncFunc->IsExternal());
19213af6ab5fSopenharmony_ci    implMethod->SetParent(asyncMethod->Parent());
19223af6ab5fSopenharmony_ci
19233af6ab5fSopenharmony_ci    return implMethod;
19243af6ab5fSopenharmony_ci}
19253af6ab5fSopenharmony_ci
19263af6ab5fSopenharmony_ciir::MethodDefinition *ETSChecker::CreateMethod(const util::StringView &name, ir::ModifierFlags modifiers,
19273af6ab5fSopenharmony_ci                                               ir::ScriptFunctionFlags flags, ArenaVector<ir::Expression *> &&params,
19283af6ab5fSopenharmony_ci                                               varbinder::FunctionParamScope *paramScope, ir::TypeNode *returnType,
19293af6ab5fSopenharmony_ci                                               ir::AstNode *body)
19303af6ab5fSopenharmony_ci{
19313af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
19323af6ab5fSopenharmony_ci    auto *nameId = AllocNode<ir::Identifier>(name, Allocator());
19333af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
19343af6ab5fSopenharmony_ci    auto *scope = VarBinder()->Allocator()->New<varbinder::FunctionScope>(Allocator(), paramScope);
19353af6ab5fSopenharmony_ci    // clang-format off
19363af6ab5fSopenharmony_ci    auto *const func = AllocNode<ir::ScriptFunction>(
19373af6ab5fSopenharmony_ci        Allocator(), ir::ScriptFunction::ScriptFunctionData {
19383af6ab5fSopenharmony_ci            body, ir::FunctionSignature(nullptr, std::move(params), returnType), flags, modifiers});
19393af6ab5fSopenharmony_ci    // clang-format on
19403af6ab5fSopenharmony_ci    func->SetScope(scope);
19413af6ab5fSopenharmony_ci    func->SetIdent(nameId);
19423af6ab5fSopenharmony_ci    if (body != nullptr && body->IsBlockStatement()) {
19433af6ab5fSopenharmony_ci        body->AsBlockStatement()->SetScope(scope);
19443af6ab5fSopenharmony_ci    }
19453af6ab5fSopenharmony_ci    scope->BindNode(func);
19463af6ab5fSopenharmony_ci    paramScope->BindNode(func);
19473af6ab5fSopenharmony_ci    scope->BindParamScope(paramScope);
19483af6ab5fSopenharmony_ci    paramScope->BindFunctionScope(scope);
19493af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
19503af6ab5fSopenharmony_ci    auto *funcExpr = AllocNode<ir::FunctionExpression>(func);
19513af6ab5fSopenharmony_ci    auto *nameClone = nameId->Clone(Allocator(), nullptr);
19523af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
19533af6ab5fSopenharmony_ci    auto *method = AllocNode<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD, nameClone, funcExpr, modifiers,
19543af6ab5fSopenharmony_ci                                                   Allocator(), false);
19553af6ab5fSopenharmony_ci    return method;
19563af6ab5fSopenharmony_ci}
19573af6ab5fSopenharmony_ci
19583af6ab5fSopenharmony_civarbinder::FunctionParamScope *ETSChecker::CopyParams(const ArenaVector<ir::Expression *> &params,
19593af6ab5fSopenharmony_ci                                                      ArenaVector<ir::Expression *> &outParams)
19603af6ab5fSopenharmony_ci{
19613af6ab5fSopenharmony_ci    auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder());
19623af6ab5fSopenharmony_ci
19633af6ab5fSopenharmony_ci    for (auto *const it : params) {
19643af6ab5fSopenharmony_ci        auto *const paramOld = it->AsETSParameterExpression();
19653af6ab5fSopenharmony_ci        // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
19663af6ab5fSopenharmony_ci        auto *const paramNew = paramOld->Clone(Allocator(), paramOld->Parent())->AsETSParameterExpression();
19673af6ab5fSopenharmony_ci
19683af6ab5fSopenharmony_ci        auto *const var = std::get<1>(VarBinder()->AddParamDecl(paramNew));
19693af6ab5fSopenharmony_ci
19703af6ab5fSopenharmony_ci        var->SetTsType(paramOld->Ident()->Variable()->TsType());
19713af6ab5fSopenharmony_ci        var->SetScope(paramCtx.GetScope());
19723af6ab5fSopenharmony_ci        paramNew->SetVariable(var);
19733af6ab5fSopenharmony_ci
19743af6ab5fSopenharmony_ci        paramNew->SetTsType(paramOld->Ident()->Variable()->TsType());
19753af6ab5fSopenharmony_ci
19763af6ab5fSopenharmony_ci        outParams.emplace_back(paramNew);
19773af6ab5fSopenharmony_ci    }
19783af6ab5fSopenharmony_ci
19793af6ab5fSopenharmony_ci    return paramCtx.GetScope();
19803af6ab5fSopenharmony_ci}
19813af6ab5fSopenharmony_ci
19823af6ab5fSopenharmony_civoid ETSChecker::ReplaceScope(ir::AstNode *root, ir::AstNode *oldNode, varbinder::Scope *newScope)
19833af6ab5fSopenharmony_ci{
19843af6ab5fSopenharmony_ci    if (root == nullptr) {
19853af6ab5fSopenharmony_ci        return;
19863af6ab5fSopenharmony_ci    }
19873af6ab5fSopenharmony_ci
19883af6ab5fSopenharmony_ci    root->Iterate([this, oldNode, newScope](ir::AstNode *child) {
19893af6ab5fSopenharmony_ci        auto *scope = NodeScope(child);
19903af6ab5fSopenharmony_ci        if (scope != nullptr) {
19913af6ab5fSopenharmony_ci            while (scope->Parent() != nullptr && scope->Parent()->Node() != oldNode) {
19923af6ab5fSopenharmony_ci                scope = scope->Parent();
19933af6ab5fSopenharmony_ci            }
19943af6ab5fSopenharmony_ci            scope->SetParent(newScope);
19953af6ab5fSopenharmony_ci        } else {
19963af6ab5fSopenharmony_ci            ReplaceScope(child, oldNode, newScope);
19973af6ab5fSopenharmony_ci        }
19983af6ab5fSopenharmony_ci    });
19993af6ab5fSopenharmony_ci}
20003af6ab5fSopenharmony_ci
20013af6ab5fSopenharmony_civoid ETSChecker::MoveTrailingBlockToEnclosingBlockStatement(ir::CallExpression *callExpr)
20023af6ab5fSopenharmony_ci{
20033af6ab5fSopenharmony_ci    if (callExpr == nullptr) {
20043af6ab5fSopenharmony_ci        return;
20053af6ab5fSopenharmony_ci    }
20063af6ab5fSopenharmony_ci
20073af6ab5fSopenharmony_ci    ir::AstNode *parent = callExpr->Parent();
20083af6ab5fSopenharmony_ci    ir::AstNode *current = callExpr;
20093af6ab5fSopenharmony_ci    while (parent != nullptr) {
20103af6ab5fSopenharmony_ci        if (!parent->IsBlockStatement()) {
20113af6ab5fSopenharmony_ci            current = parent;
20123af6ab5fSopenharmony_ci            parent = parent->Parent();
20133af6ab5fSopenharmony_ci        } else {
20143af6ab5fSopenharmony_ci            // Collect trailing block, insert it only when block statements traversal ends to avoid order mismatch.
20153af6ab5fSopenharmony_ci            parent->AsBlockStatement()->AddTrailingBlock(current, callExpr->TrailingBlock());
20163af6ab5fSopenharmony_ci            callExpr->TrailingBlock()->SetParent(parent);
20173af6ab5fSopenharmony_ci            callExpr->SetTrailingBlock(nullptr);
20183af6ab5fSopenharmony_ci            break;
20193af6ab5fSopenharmony_ci        }
20203af6ab5fSopenharmony_ci    }
20213af6ab5fSopenharmony_ci}
20223af6ab5fSopenharmony_ci
20233af6ab5fSopenharmony_civoid ETSChecker::TransformTraillingLambda(ir::CallExpression *callExpr)
20243af6ab5fSopenharmony_ci{
20253af6ab5fSopenharmony_ci    auto *trailingBlock = callExpr->TrailingBlock();
20263af6ab5fSopenharmony_ci    ASSERT(trailingBlock != nullptr);
20273af6ab5fSopenharmony_ci
20283af6ab5fSopenharmony_ci    auto *funcParamScope = varbinder::LexicalScope<varbinder::FunctionParamScope>(VarBinder()).GetScope();
20293af6ab5fSopenharmony_ci    auto paramCtx = varbinder::LexicalScope<varbinder::FunctionParamScope>::Enter(VarBinder(), funcParamScope, false);
20303af6ab5fSopenharmony_ci
20313af6ab5fSopenharmony_ci    auto funcCtx = varbinder::LexicalScope<varbinder::FunctionScope>(VarBinder());
20323af6ab5fSopenharmony_ci    auto *funcScope = funcCtx.GetScope();
20333af6ab5fSopenharmony_ci    funcScope->BindParamScope(funcParamScope);
20343af6ab5fSopenharmony_ci    funcParamScope->BindFunctionScope(funcScope);
20353af6ab5fSopenharmony_ci    funcParamScope->SetParent(trailingBlock->Scope()->Parent());
20363af6ab5fSopenharmony_ci
20373af6ab5fSopenharmony_ci    for (auto [_, var] : trailingBlock->Scope()->Bindings()) {
20383af6ab5fSopenharmony_ci        (void)_;
20393af6ab5fSopenharmony_ci        if (var->GetScope() == trailingBlock->Scope()) {
20403af6ab5fSopenharmony_ci            var->SetScope(funcScope);
20413af6ab5fSopenharmony_ci            funcScope->InsertBinding(var->Name(), var);
20423af6ab5fSopenharmony_ci        }
20433af6ab5fSopenharmony_ci    }
20443af6ab5fSopenharmony_ci
20453af6ab5fSopenharmony_ci    ArenaVector<ir::Expression *> params(Allocator()->Adapter());
20463af6ab5fSopenharmony_ci    auto *funcNode = AllocNode<ir::ScriptFunction>(
20473af6ab5fSopenharmony_ci        Allocator(), ir::ScriptFunction::ScriptFunctionData {trailingBlock,
20483af6ab5fSopenharmony_ci                                                             ir::FunctionSignature(nullptr, std::move(params), nullptr),
20493af6ab5fSopenharmony_ci                                                             ir::ScriptFunctionFlags::ARROW});
20503af6ab5fSopenharmony_ci    funcNode->SetScope(funcScope);
20513af6ab5fSopenharmony_ci    funcScope->BindNode(funcNode);
20523af6ab5fSopenharmony_ci    funcParamScope->BindNode(funcNode);
20533af6ab5fSopenharmony_ci
20543af6ab5fSopenharmony_ci    trailingBlock->SetScope(funcScope);
20553af6ab5fSopenharmony_ci    ReplaceScope(funcNode->Body(), trailingBlock, funcScope);
20563af6ab5fSopenharmony_ci    callExpr->SetTrailingBlock(nullptr);
20573af6ab5fSopenharmony_ci
20583af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
20593af6ab5fSopenharmony_ci    auto *arrowFuncNode = AllocNode<ir::ArrowFunctionExpression>(funcNode);
20603af6ab5fSopenharmony_ci    arrowFuncNode->SetRange(trailingBlock->Range());
20613af6ab5fSopenharmony_ci    arrowFuncNode->SetParent(callExpr);
20623af6ab5fSopenharmony_ci
20633af6ab5fSopenharmony_ci    callExpr->Arguments().push_back(arrowFuncNode);
20643af6ab5fSopenharmony_ci}
20653af6ab5fSopenharmony_ci
20663af6ab5fSopenharmony_ciArenaVector<ir::Expression *> ETSChecker::ExtendArgumentsWithFakeLamda(ir::CallExpression *callExpr)
20673af6ab5fSopenharmony_ci{
20683af6ab5fSopenharmony_ci    auto funcCtx = varbinder::LexicalScope<varbinder::FunctionScope>(VarBinder());
20693af6ab5fSopenharmony_ci    auto *funcScope = funcCtx.GetScope();
20703af6ab5fSopenharmony_ci    ArenaVector<ir::Expression *> params(Allocator()->Adapter());
20713af6ab5fSopenharmony_ci
20723af6ab5fSopenharmony_ci    ArenaVector<ir::Statement *> statements(Allocator()->Adapter());
20733af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
20743af6ab5fSopenharmony_ci    auto *body = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
20753af6ab5fSopenharmony_ci    body->SetScope(funcScope);
20763af6ab5fSopenharmony_ci
20773af6ab5fSopenharmony_ci    auto *funcNode = AllocNode<ir::ScriptFunction>(
20783af6ab5fSopenharmony_ci        Allocator(),
20793af6ab5fSopenharmony_ci        ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), nullptr),
20803af6ab5fSopenharmony_ci                                                ir::ScriptFunctionFlags::ARROW});
20813af6ab5fSopenharmony_ci    funcNode->SetScope(funcScope);
20823af6ab5fSopenharmony_ci    funcScope->BindNode(funcNode);
20833af6ab5fSopenharmony_ci    auto *arrowFuncNode = AllocNode<ir::ArrowFunctionExpression>(funcNode);
20843af6ab5fSopenharmony_ci    arrowFuncNode->SetParent(callExpr);
20853af6ab5fSopenharmony_ci
20863af6ab5fSopenharmony_ci    ArenaVector<ir::Expression *> fakeArguments = callExpr->Arguments();
20873af6ab5fSopenharmony_ci    fakeArguments.push_back(arrowFuncNode);
20883af6ab5fSopenharmony_ci    return fakeArguments;
20893af6ab5fSopenharmony_ci}
20903af6ab5fSopenharmony_ci
20913af6ab5fSopenharmony_civoid ETSChecker::EnsureValidCurlyBrace(ir::CallExpression *callExpr)
20923af6ab5fSopenharmony_ci{
20933af6ab5fSopenharmony_ci    if (callExpr->TrailingBlock() == nullptr) {
20943af6ab5fSopenharmony_ci        return;
20953af6ab5fSopenharmony_ci    }
20963af6ab5fSopenharmony_ci
20973af6ab5fSopenharmony_ci    if (callExpr->IsTrailingBlockInNewLine()) {
20983af6ab5fSopenharmony_ci        MoveTrailingBlockToEnclosingBlockStatement(callExpr);
20993af6ab5fSopenharmony_ci        return;
21003af6ab5fSopenharmony_ci    }
21013af6ab5fSopenharmony_ci
21023af6ab5fSopenharmony_ci    LogTypeError({"No matching call signature with trailing lambda"}, callExpr->Start());
21033af6ab5fSopenharmony_ci}
21043af6ab5fSopenharmony_ci
21053af6ab5fSopenharmony_ciETSObjectType *ETSChecker::GetCachedFunctionalInterface(ir::ETSFunctionType *type)
21063af6ab5fSopenharmony_ci{
21073af6ab5fSopenharmony_ci    auto hash = GetHashFromFunctionType(type);
21083af6ab5fSopenharmony_ci    auto it = functionalInterfaceCache_.find(hash);
21093af6ab5fSopenharmony_ci    if (it == functionalInterfaceCache_.cend()) {
21103af6ab5fSopenharmony_ci        return nullptr;
21113af6ab5fSopenharmony_ci    }
21123af6ab5fSopenharmony_ci    return it->second;
21133af6ab5fSopenharmony_ci}
21143af6ab5fSopenharmony_ci
21153af6ab5fSopenharmony_civoid ETSChecker::CacheFunctionalInterface(ir::ETSFunctionType *type, ETSObjectType *ifaceType)
21163af6ab5fSopenharmony_ci{
21173af6ab5fSopenharmony_ci    auto hash = GetHashFromFunctionType(type);
21183af6ab5fSopenharmony_ci    ASSERT(functionalInterfaceCache_.find(hash) == functionalInterfaceCache_.cend());
21193af6ab5fSopenharmony_ci    functionalInterfaceCache_.emplace(hash, ifaceType);
21203af6ab5fSopenharmony_ci}
21213af6ab5fSopenharmony_ci
21223af6ab5fSopenharmony_civoid ETSChecker::CollectReturnStatements(ir::AstNode *parent)
21233af6ab5fSopenharmony_ci{
21243af6ab5fSopenharmony_ci    parent->Iterate([this](ir::AstNode *childNode) -> void {
21253af6ab5fSopenharmony_ci        if (childNode->IsScriptFunction()) {
21263af6ab5fSopenharmony_ci            return;
21273af6ab5fSopenharmony_ci        }
21283af6ab5fSopenharmony_ci
21293af6ab5fSopenharmony_ci        if (childNode->IsReturnStatement()) {
21303af6ab5fSopenharmony_ci            ir::ReturnStatement *returnStmt = childNode->AsReturnStatement();
21313af6ab5fSopenharmony_ci            returnStmt->Check(this);
21323af6ab5fSopenharmony_ci        }
21333af6ab5fSopenharmony_ci
21343af6ab5fSopenharmony_ci        CollectReturnStatements(childNode);
21353af6ab5fSopenharmony_ci    });
21363af6ab5fSopenharmony_ci}
21373af6ab5fSopenharmony_ci
21383af6ab5fSopenharmony_ciArenaVector<ConstraintCheckRecord> &ETSChecker::PendingConstraintCheckRecords()
21393af6ab5fSopenharmony_ci{
21403af6ab5fSopenharmony_ci    return pendingConstraintCheckRecords_;
21413af6ab5fSopenharmony_ci}
21423af6ab5fSopenharmony_ci
21433af6ab5fSopenharmony_cisize_t &ETSChecker::ConstraintCheckScopesCount()
21443af6ab5fSopenharmony_ci{
21453af6ab5fSopenharmony_ci    return constraintCheckScopesCount_;
21463af6ab5fSopenharmony_ci}
21473af6ab5fSopenharmony_ci
21483af6ab5fSopenharmony_cibool ETSChecker::CmpAssemblerTypesWithRank(Signature const *const sig1, Signature const *const sig2) noexcept
21493af6ab5fSopenharmony_ci{
21503af6ab5fSopenharmony_ci    for (size_t ix = 0; ix < sig1->MinArgCount(); ix++) {
21513af6ab5fSopenharmony_ci        std::stringstream s1;
21523af6ab5fSopenharmony_ci        std::stringstream s2;
21533af6ab5fSopenharmony_ci        sig1->Params()[ix]->TsType()->ToAssemblerTypeWithRank(s1);
21543af6ab5fSopenharmony_ci        sig2->Params()[ix]->TsType()->ToAssemblerTypeWithRank(s2);
21553af6ab5fSopenharmony_ci        if (s1.str() != s2.str()) {
21563af6ab5fSopenharmony_ci            return false;
21573af6ab5fSopenharmony_ci            break;
21583af6ab5fSopenharmony_ci        }
21593af6ab5fSopenharmony_ci    }
21603af6ab5fSopenharmony_ci    return true;
21613af6ab5fSopenharmony_ci}
21623af6ab5fSopenharmony_ci
21633af6ab5fSopenharmony_cibool ETSChecker::HasSameAssemblySignature(Signature const *const sig1, Signature const *const sig2) noexcept
21643af6ab5fSopenharmony_ci{
21653af6ab5fSopenharmony_ci    if (sig1->MinArgCount() != sig2->MinArgCount()) {
21663af6ab5fSopenharmony_ci        return false;
21673af6ab5fSopenharmony_ci    }
21683af6ab5fSopenharmony_ci
21693af6ab5fSopenharmony_ci    if (!CmpAssemblerTypesWithRank(sig1, sig2)) {
21703af6ab5fSopenharmony_ci        return false;
21713af6ab5fSopenharmony_ci    }
21723af6ab5fSopenharmony_ci    auto *rv1 = sig1->RestVar();
21733af6ab5fSopenharmony_ci    auto *rv2 = sig2->RestVar();
21743af6ab5fSopenharmony_ci    if (rv1 == nullptr && rv2 == nullptr) {
21753af6ab5fSopenharmony_ci        return true;
21763af6ab5fSopenharmony_ci    }
21773af6ab5fSopenharmony_ci    if (rv1 == nullptr || rv2 == nullptr) {  // exactly one of them is null
21783af6ab5fSopenharmony_ci        return false;
21793af6ab5fSopenharmony_ci    }
21803af6ab5fSopenharmony_ci    std::stringstream s1;
21813af6ab5fSopenharmony_ci    std::stringstream s2;
21823af6ab5fSopenharmony_ci    rv1->TsType()->ToAssemblerTypeWithRank(s1);
21833af6ab5fSopenharmony_ci    rv2->TsType()->ToAssemblerTypeWithRank(s2);
21843af6ab5fSopenharmony_ci    return s1.str() == s2.str();
21853af6ab5fSopenharmony_ci}
21863af6ab5fSopenharmony_ci
21873af6ab5fSopenharmony_cibool ETSChecker::HasSameAssemblySignatures(ETSFunctionType const *const func1,
21883af6ab5fSopenharmony_ci                                           ETSFunctionType const *const func2) noexcept
21893af6ab5fSopenharmony_ci{
21903af6ab5fSopenharmony_ci    for (auto const *sig1 : func1->CallSignatures()) {
21913af6ab5fSopenharmony_ci        for (auto const *sig2 : func2->CallSignatures()) {
21923af6ab5fSopenharmony_ci            if (HasSameAssemblySignature(sig1, sig2)) {
21933af6ab5fSopenharmony_ci                return true;
21943af6ab5fSopenharmony_ci            }
21953af6ab5fSopenharmony_ci        }
21963af6ab5fSopenharmony_ci    }
21973af6ab5fSopenharmony_ci    return false;
21983af6ab5fSopenharmony_ci}
21993af6ab5fSopenharmony_ci}  // namespace ark::es2panda::checker
2200