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 "ir/typeNode.h"
173af6ab5fSopenharmony_ci#include "ir/expressions/literals/stringLiteral.h"
183af6ab5fSopenharmony_ci#include "ir/expressions/literals/bigIntLiteral.h"
193af6ab5fSopenharmony_ci#include "ir/expressions/literals/numberLiteral.h"
203af6ab5fSopenharmony_ci#include "ir/expressions/arrayExpression.h"
213af6ab5fSopenharmony_ci#include "ir/expressions/assignmentExpression.h"
223af6ab5fSopenharmony_ci#include "ir/expressions/callExpression.h"
233af6ab5fSopenharmony_ci#include "ir/expressions/objectExpression.h"
243af6ab5fSopenharmony_ci#include "ir/expressions/identifier.h"
253af6ab5fSopenharmony_ci#include "ir/base/scriptFunction.h"
263af6ab5fSopenharmony_ci#include "ir/base/property.h"
273af6ab5fSopenharmony_ci#include "ir/base/spreadElement.h"
283af6ab5fSopenharmony_ci#include "ir/statements/blockStatement.h"
293af6ab5fSopenharmony_ci#include "ir/statements/returnStatement.h"
303af6ab5fSopenharmony_ci#include "ir/statements/functionDeclaration.h"
313af6ab5fSopenharmony_ci#include "util/helpers.h"
323af6ab5fSopenharmony_ci#include "varbinder/variable.h"
333af6ab5fSopenharmony_ci#include "varbinder/scope.h"
343af6ab5fSopenharmony_ci#include "varbinder/declaration.h"
353af6ab5fSopenharmony_ci
363af6ab5fSopenharmony_ci#include "checker/TSchecker.h"
373af6ab5fSopenharmony_ci#include "checker/ts/destructuringContext.h"
383af6ab5fSopenharmony_ci#include "checker/types/ts/objectDescriptor.h"
393af6ab5fSopenharmony_ci#include "checker/types/ts/objectType.h"
403af6ab5fSopenharmony_ci
413af6ab5fSopenharmony_ci#include <cstddef>
423af6ab5fSopenharmony_ci#include <cstdint>
433af6ab5fSopenharmony_ci#include <memory>
443af6ab5fSopenharmony_ci#include <utility>
453af6ab5fSopenharmony_ci#include <vector>
463af6ab5fSopenharmony_ci
473af6ab5fSopenharmony_cinamespace ark::es2panda::checker {
483af6ab5fSopenharmony_ciType *TSChecker::HandleFunctionReturn(ir::ScriptFunction *func)
493af6ab5fSopenharmony_ci{
503af6ab5fSopenharmony_ci    if (func->ReturnTypeAnnotation() != nullptr) {
513af6ab5fSopenharmony_ci        func->ReturnTypeAnnotation()->Check(this);
523af6ab5fSopenharmony_ci        Type *returnType = func->ReturnTypeAnnotation()->GetType(this);
533af6ab5fSopenharmony_ci
543af6ab5fSopenharmony_ci        if (func->IsArrow() && func->Body()->IsExpression()) {
553af6ab5fSopenharmony_ci            ElaborateElementwise(returnType, func->Body()->AsExpression(), func->Body()->Start());
563af6ab5fSopenharmony_ci        }
573af6ab5fSopenharmony_ci
583af6ab5fSopenharmony_ci        if (returnType->IsNeverType()) {
593af6ab5fSopenharmony_ci            ThrowTypeError("A function returning 'never' cannot have a reachable end point.",
603af6ab5fSopenharmony_ci                           func->ReturnTypeAnnotation()->Start());
613af6ab5fSopenharmony_ci        }
623af6ab5fSopenharmony_ci
633af6ab5fSopenharmony_ci        if (!MaybeTypeOfKind(returnType, TypeFlag::ANY_OR_VOID)) {
643af6ab5fSopenharmony_ci            CheckAllCodePathsInNonVoidFunctionReturnOrThrow(
653af6ab5fSopenharmony_ci                func, func->ReturnTypeAnnotation()->Start(),
663af6ab5fSopenharmony_ci                "A function whose declared type is neither 'void' nor 'any' must return a value.");
673af6ab5fSopenharmony_ci        }
683af6ab5fSopenharmony_ci
693af6ab5fSopenharmony_ci        return returnType;
703af6ab5fSopenharmony_ci    }
713af6ab5fSopenharmony_ci
723af6ab5fSopenharmony_ci    if (func->Declare()) {
733af6ab5fSopenharmony_ci        return GlobalAnyType();
743af6ab5fSopenharmony_ci    }
753af6ab5fSopenharmony_ci
763af6ab5fSopenharmony_ci    if (func->IsArrow() && func->Body()->IsExpression()) {
773af6ab5fSopenharmony_ci        return func->Body()->Check(this);
783af6ab5fSopenharmony_ci    }
793af6ab5fSopenharmony_ci
803af6ab5fSopenharmony_ci    ArenaVector<Type *> returnTypes(Allocator()->Adapter());
813af6ab5fSopenharmony_ci    CollectTypesFromReturnStatements(func->Body(), &returnTypes);
823af6ab5fSopenharmony_ci
833af6ab5fSopenharmony_ci    if (returnTypes.empty()) {
843af6ab5fSopenharmony_ci        return GlobalVoidType();
853af6ab5fSopenharmony_ci    }
863af6ab5fSopenharmony_ci
873af6ab5fSopenharmony_ci    if (returnTypes.size() == 1 && returnTypes[0] == GlobalResolvingReturnType()) {
883af6ab5fSopenharmony_ci        ThrowReturnTypeCircularityError(func);
893af6ab5fSopenharmony_ci    }
903af6ab5fSopenharmony_ci
913af6ab5fSopenharmony_ci    for (auto *it : returnTypes) {
923af6ab5fSopenharmony_ci        if (it == GlobalResolvingReturnType()) {
933af6ab5fSopenharmony_ci            ThrowReturnTypeCircularityError(func);
943af6ab5fSopenharmony_ci        }
953af6ab5fSopenharmony_ci    }
963af6ab5fSopenharmony_ci
973af6ab5fSopenharmony_ci    return CreateUnionType(std::move(returnTypes));
983af6ab5fSopenharmony_ci}
993af6ab5fSopenharmony_ci
1003af6ab5fSopenharmony_civoid TSChecker::ThrowReturnTypeCircularityError(ir::ScriptFunction *func)
1013af6ab5fSopenharmony_ci{
1023af6ab5fSopenharmony_ci    if (func->ReturnTypeAnnotation() != nullptr) {
1033af6ab5fSopenharmony_ci        ThrowTypeError("Return type annotation circularly reference itself", func->ReturnTypeAnnotation()->Start());
1043af6ab5fSopenharmony_ci    }
1053af6ab5fSopenharmony_ci
1063af6ab5fSopenharmony_ci    if (func->Id() != nullptr) {
1073af6ab5fSopenharmony_ci        ThrowTypeError({func->Id()->AsIdentifier()->Name(),
1083af6ab5fSopenharmony_ci                        " implicitly has return type 'any' because it does not have a return type annotation and is "
1093af6ab5fSopenharmony_ci                        "referenced directly or indirectly in one of its return expressions."},
1103af6ab5fSopenharmony_ci                       func->Id()->Start());
1113af6ab5fSopenharmony_ci    }
1123af6ab5fSopenharmony_ci
1133af6ab5fSopenharmony_ci    ThrowTypeError(
1143af6ab5fSopenharmony_ci        "Function implicitly has return type 'any' because it does not have a return type annotation and is "
1153af6ab5fSopenharmony_ci        "referenced directly or indirectly in one of its return expressions.",
1163af6ab5fSopenharmony_ci        func->Start());
1173af6ab5fSopenharmony_ci}
1183af6ab5fSopenharmony_ci
1193af6ab5fSopenharmony_cistd::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> TSChecker::CheckFunctionIdentifierParameter(
1203af6ab5fSopenharmony_ci    ir::Identifier *param)
1213af6ab5fSopenharmony_ci{
1223af6ab5fSopenharmony_ci    ASSERT(param->Variable());
1233af6ab5fSopenharmony_ci    varbinder::Variable *paramVar = param->Variable();
1243af6ab5fSopenharmony_ci    bool isOptional = param->IsOptional();
1253af6ab5fSopenharmony_ci
1263af6ab5fSopenharmony_ci    if (param->TypeAnnotation() == nullptr) {
1273af6ab5fSopenharmony_ci        ThrowTypeError({"Parameter ", param->Name(), " implicitly has any type."}, param->Start());
1283af6ab5fSopenharmony_ci    }
1293af6ab5fSopenharmony_ci
1303af6ab5fSopenharmony_ci    if (isOptional) {
1313af6ab5fSopenharmony_ci        paramVar->AddFlag(varbinder::VariableFlags::OPTIONAL);
1323af6ab5fSopenharmony_ci    }
1333af6ab5fSopenharmony_ci
1343af6ab5fSopenharmony_ci    param->TypeAnnotation()->Check(this);
1353af6ab5fSopenharmony_ci    paramVar->SetTsType(param->TypeAnnotation()->GetType(this));
1363af6ab5fSopenharmony_ci    return {paramVar->AsLocalVariable(), nullptr, isOptional};
1373af6ab5fSopenharmony_ci}
1383af6ab5fSopenharmony_ci
1393af6ab5fSopenharmony_ciType *TSChecker::CreateParameterTypeForArrayAssignmentPattern(ir::ArrayExpression *arrayPattern, Type *inferredType)
1403af6ab5fSopenharmony_ci{
1413af6ab5fSopenharmony_ci    if (!inferredType->IsObjectType()) {
1423af6ab5fSopenharmony_ci        return inferredType;
1433af6ab5fSopenharmony_ci    }
1443af6ab5fSopenharmony_ci
1453af6ab5fSopenharmony_ci    ASSERT(inferredType->AsObjectType()->IsTupleType());
1463af6ab5fSopenharmony_ci    TupleType *inferredTuple = inferredType->AsObjectType()->AsTupleType();
1473af6ab5fSopenharmony_ci
1483af6ab5fSopenharmony_ci    if (inferredTuple->FixedLength() > arrayPattern->Elements().size()) {
1493af6ab5fSopenharmony_ci        return inferredType;
1503af6ab5fSopenharmony_ci    }
1513af6ab5fSopenharmony_ci
1523af6ab5fSopenharmony_ci    TupleType *newTuple =
1533af6ab5fSopenharmony_ci        inferredTuple->Instantiate(Allocator(), Relation(), GetGlobalTypesHolder())->AsObjectType()->AsTupleType();
1543af6ab5fSopenharmony_ci
1553af6ab5fSopenharmony_ci    for (uint32_t index = inferredTuple->FixedLength(); index < arrayPattern->Elements().size(); index++) {
1563af6ab5fSopenharmony_ci        util::StringView memberIndex = util::Helpers::ToStringView(Allocator(), index);
1573af6ab5fSopenharmony_ci        varbinder::LocalVariable *newMember = varbinder::Scope::CreateVar(
1583af6ab5fSopenharmony_ci            Allocator(), memberIndex, varbinder::VariableFlags::PROPERTY | varbinder::VariableFlags::OPTIONAL, nullptr);
1593af6ab5fSopenharmony_ci        newMember->SetTsType(GlobalAnyType());
1603af6ab5fSopenharmony_ci        newTuple->AddProperty(newMember);
1613af6ab5fSopenharmony_ci    }
1623af6ab5fSopenharmony_ci
1633af6ab5fSopenharmony_ci    return newTuple;
1643af6ab5fSopenharmony_ci}
1653af6ab5fSopenharmony_ci
1663af6ab5fSopenharmony_ciType *TSChecker::CreateParameterTypeForObjectAssignmentPattern(ir::ObjectExpression *objectPattern, Type *inferredType)
1673af6ab5fSopenharmony_ci{
1683af6ab5fSopenharmony_ci    if (!inferredType->IsObjectType()) {
1693af6ab5fSopenharmony_ci        return inferredType;
1703af6ab5fSopenharmony_ci    }
1713af6ab5fSopenharmony_ci
1723af6ab5fSopenharmony_ci    ObjectType *newObject = inferredType->Instantiate(Allocator(), Relation(), GetGlobalTypesHolder())->AsObjectType();
1733af6ab5fSopenharmony_ci
1743af6ab5fSopenharmony_ci    for (auto *it : objectPattern->Properties()) {
1753af6ab5fSopenharmony_ci        if (it->IsRestElement()) {
1763af6ab5fSopenharmony_ci            continue;
1773af6ab5fSopenharmony_ci        }
1783af6ab5fSopenharmony_ci
1793af6ab5fSopenharmony_ci        ir::Property *prop = it->AsProperty();
1803af6ab5fSopenharmony_ci        varbinder::LocalVariable *foundVar = newObject->GetProperty(prop->Key()->AsIdentifier()->Name(), true);
1813af6ab5fSopenharmony_ci
1823af6ab5fSopenharmony_ci        if (foundVar != nullptr) {
1833af6ab5fSopenharmony_ci            if (prop->Value()->IsAssignmentPattern()) {
1843af6ab5fSopenharmony_ci                foundVar->AddFlag(varbinder::VariableFlags::OPTIONAL);
1853af6ab5fSopenharmony_ci            }
1863af6ab5fSopenharmony_ci
1873af6ab5fSopenharmony_ci            continue;
1883af6ab5fSopenharmony_ci        }
1893af6ab5fSopenharmony_ci
1903af6ab5fSopenharmony_ci        ASSERT(prop->Value()->IsAssignmentPattern());
1913af6ab5fSopenharmony_ci        ir::AssignmentExpression *assignmentPattern = prop->Value()->AsAssignmentPattern();
1923af6ab5fSopenharmony_ci
1933af6ab5fSopenharmony_ci        varbinder::LocalVariable *newProp = varbinder::Scope::CreateVar(
1943af6ab5fSopenharmony_ci            Allocator(), prop->Key()->AsIdentifier()->Name(),
1953af6ab5fSopenharmony_ci            varbinder::VariableFlags::PROPERTY | varbinder::VariableFlags::OPTIONAL, nullptr);
1963af6ab5fSopenharmony_ci        newProp->SetTsType(GetBaseTypeOfLiteralType(CheckTypeCached(assignmentPattern->Right())));
1973af6ab5fSopenharmony_ci        newObject->AddProperty(newProp);
1983af6ab5fSopenharmony_ci    }
1993af6ab5fSopenharmony_ci
2003af6ab5fSopenharmony_ci    newObject->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS);
2013af6ab5fSopenharmony_ci    return newObject;
2023af6ab5fSopenharmony_ci}
2033af6ab5fSopenharmony_ci
2043af6ab5fSopenharmony_ciusing ReturnedVariable = std::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool>;
2053af6ab5fSopenharmony_ciReturnedVariable TSChecker::CheckFunctionAssignmentPatternParameter(ir::AssignmentExpression *param)
2063af6ab5fSopenharmony_ci{
2073af6ab5fSopenharmony_ci    if (param->Left()->IsIdentifier()) {
2083af6ab5fSopenharmony_ci        ir::Identifier *paramIdent = param->Left()->AsIdentifier();
2093af6ab5fSopenharmony_ci        varbinder::Variable *paramVar = paramIdent->Variable();
2103af6ab5fSopenharmony_ci        ASSERT(paramVar);
2113af6ab5fSopenharmony_ci
2123af6ab5fSopenharmony_ci        if (paramIdent->TypeAnnotation() != nullptr) {
2133af6ab5fSopenharmony_ci            paramIdent->TypeAnnotation()->Check(this);
2143af6ab5fSopenharmony_ci            Type *paramType = paramIdent->TypeAnnotation()->GetType(this);
2153af6ab5fSopenharmony_ci            paramVar->SetTsType(paramType);
2163af6ab5fSopenharmony_ci            ElaborateElementwise(paramType, param->Right(), paramIdent->Start());
2173af6ab5fSopenharmony_ci            return {paramVar->AsLocalVariable(), nullptr, true};
2183af6ab5fSopenharmony_ci        }
2193af6ab5fSopenharmony_ci
2203af6ab5fSopenharmony_ci        paramVar->SetTsType(GetBaseTypeOfLiteralType(param->Right()->Check(this)));
2213af6ab5fSopenharmony_ci        paramVar->AddFlag(varbinder::VariableFlags::OPTIONAL);
2223af6ab5fSopenharmony_ci        return {paramVar->AsLocalVariable(), nullptr, true};
2233af6ab5fSopenharmony_ci    }
2243af6ab5fSopenharmony_ci
2253af6ab5fSopenharmony_ci    Type *paramType = nullptr;
2263af6ab5fSopenharmony_ci    std::stringstream ss;
2273af6ab5fSopenharmony_ci
2283af6ab5fSopenharmony_ci    auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE | CheckerStatus::IN_PARAMETER);
2293af6ab5fSopenharmony_ci
2303af6ab5fSopenharmony_ci    if (param->Left()->IsArrayPattern()) {
2313af6ab5fSopenharmony_ci        ir::ArrayExpression *arrayPattern = param->Left()->AsArrayPattern();
2323af6ab5fSopenharmony_ci        auto context = ArrayDestructuringContext(
2333af6ab5fSopenharmony_ci            {this, arrayPattern, false, true, arrayPattern->TypeAnnotation(), param->Right()});
2343af6ab5fSopenharmony_ci        context.Start();
2353af6ab5fSopenharmony_ci        paramType = CreateParameterTypeForArrayAssignmentPattern(arrayPattern, context.InferredType());
2363af6ab5fSopenharmony_ci        CreatePatternParameterName(param->Left(), ss);
2373af6ab5fSopenharmony_ci    } else {
2383af6ab5fSopenharmony_ci        ir::ObjectExpression *objectPattern = param->Left()->AsObjectPattern();
2393af6ab5fSopenharmony_ci        auto context = ObjectDestructuringContext(
2403af6ab5fSopenharmony_ci            {this, objectPattern, false, true, objectPattern->TypeAnnotation(), param->Right()});
2413af6ab5fSopenharmony_ci        context.Start();
2423af6ab5fSopenharmony_ci        paramType = CreateParameterTypeForObjectAssignmentPattern(objectPattern, context.InferredType());
2433af6ab5fSopenharmony_ci        CreatePatternParameterName(param->Left(), ss);
2443af6ab5fSopenharmony_ci    }
2453af6ab5fSopenharmony_ci
2463af6ab5fSopenharmony_ci    util::UString pn(ss.str(), Allocator());
2473af6ab5fSopenharmony_ci    varbinder::LocalVariable *patternVar =
2483af6ab5fSopenharmony_ci        varbinder::Scope::CreateVar(Allocator(), pn.View(), varbinder::VariableFlags::NONE, param);
2493af6ab5fSopenharmony_ci    patternVar->SetTsType(paramType);
2503af6ab5fSopenharmony_ci    patternVar->AddFlag(varbinder::VariableFlags::OPTIONAL);
2513af6ab5fSopenharmony_ci    return {patternVar->AsLocalVariable(), nullptr, true};
2523af6ab5fSopenharmony_ci}
2533af6ab5fSopenharmony_ci
2543af6ab5fSopenharmony_cistd::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> TSChecker::CheckFunctionRestParameter(
2553af6ab5fSopenharmony_ci    ir::SpreadElement *param, SignatureInfo *signatureInfo)
2563af6ab5fSopenharmony_ci{
2573af6ab5fSopenharmony_ci    ir::TypeNode *typeAnnotation = nullptr;
2583af6ab5fSopenharmony_ci    if (param->Argument() != nullptr) {
2593af6ab5fSopenharmony_ci        typeAnnotation = param->Argument()->AsAnnotatedExpression()->TypeAnnotation();
2603af6ab5fSopenharmony_ci    }
2613af6ab5fSopenharmony_ci
2623af6ab5fSopenharmony_ci    Type *restType = Allocator()->New<ArrayType>(GlobalAnyType());
2633af6ab5fSopenharmony_ci
2643af6ab5fSopenharmony_ci    if (typeAnnotation != nullptr) {
2653af6ab5fSopenharmony_ci        typeAnnotation->Check(this);
2663af6ab5fSopenharmony_ci        restType = typeAnnotation->GetType(this);
2673af6ab5fSopenharmony_ci        if (!restType->IsArrayType()) {
2683af6ab5fSopenharmony_ci            ThrowTypeError("A rest parameter must be of an array type", param->Start());
2693af6ab5fSopenharmony_ci        }
2703af6ab5fSopenharmony_ci    }
2713af6ab5fSopenharmony_ci
2723af6ab5fSopenharmony_ci    switch (param->Argument()->Type()) {
2733af6ab5fSopenharmony_ci        case ir::AstNodeType::IDENTIFIER: {
2743af6ab5fSopenharmony_ci            ir::Identifier *restIdent = param->Argument()->AsIdentifier();
2753af6ab5fSopenharmony_ci            ASSERT(restIdent->Variable());
2763af6ab5fSopenharmony_ci            restIdent->Variable()->SetTsType(restType->AsArrayType()->ElementType());
2773af6ab5fSopenharmony_ci            return {nullptr, restIdent->Variable()->AsLocalVariable(), false};
2783af6ab5fSopenharmony_ci        }
2793af6ab5fSopenharmony_ci        case ir::AstNodeType::OBJECT_PATTERN: {
2803af6ab5fSopenharmony_ci            ASSERT(param->Argument()->IsObjectPattern());
2813af6ab5fSopenharmony_ci            auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE);
2823af6ab5fSopenharmony_ci            auto destructuringContext =
2833af6ab5fSopenharmony_ci                ObjectDestructuringContext({this, param->Argument(), false, false, nullptr, nullptr});
2843af6ab5fSopenharmony_ci            destructuringContext.SetInferredType(restType);
2853af6ab5fSopenharmony_ci            destructuringContext.SetSignatureInfo(signatureInfo);
2863af6ab5fSopenharmony_ci            destructuringContext.Start();
2873af6ab5fSopenharmony_ci            return {nullptr, nullptr, false};
2883af6ab5fSopenharmony_ci        }
2893af6ab5fSopenharmony_ci        case ir::AstNodeType::ARRAY_PATTERN: {
2903af6ab5fSopenharmony_ci            auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE);
2913af6ab5fSopenharmony_ci            auto destructuringContext =
2923af6ab5fSopenharmony_ci                ArrayDestructuringContext({this, param->Argument(), false, false, nullptr, nullptr});
2933af6ab5fSopenharmony_ci            destructuringContext.SetInferredType(restType);
2943af6ab5fSopenharmony_ci            destructuringContext.SetSignatureInfo(signatureInfo);
2953af6ab5fSopenharmony_ci            destructuringContext.Start();
2963af6ab5fSopenharmony_ci            return {nullptr, nullptr, false};
2973af6ab5fSopenharmony_ci        }
2983af6ab5fSopenharmony_ci        default: {
2993af6ab5fSopenharmony_ci            UNREACHABLE();
3003af6ab5fSopenharmony_ci        }
3013af6ab5fSopenharmony_ci    }
3023af6ab5fSopenharmony_ci}
3033af6ab5fSopenharmony_ci
3043af6ab5fSopenharmony_cistd::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> TSChecker::CheckFunctionArrayPatternParameter(
3053af6ab5fSopenharmony_ci    ir::ArrayExpression *param)
3063af6ab5fSopenharmony_ci{
3073af6ab5fSopenharmony_ci    std::stringstream ss;
3083af6ab5fSopenharmony_ci    CreatePatternParameterName(param, ss);
3093af6ab5fSopenharmony_ci    util::UString pn(ss.str(), Allocator());
3103af6ab5fSopenharmony_ci    varbinder::LocalVariable *patternVar =
3113af6ab5fSopenharmony_ci        varbinder::Scope::CreateVar(Allocator(), pn.View(), varbinder::VariableFlags::NONE, param);
3123af6ab5fSopenharmony_ci
3133af6ab5fSopenharmony_ci    if (param->TypeAnnotation() != nullptr) {
3143af6ab5fSopenharmony_ci        auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE);
3153af6ab5fSopenharmony_ci        auto destructuringContext =
3163af6ab5fSopenharmony_ci            ArrayDestructuringContext({this, param->AsArrayPattern(), false, false, param->TypeAnnotation(), nullptr});
3173af6ab5fSopenharmony_ci        destructuringContext.Start();
3183af6ab5fSopenharmony_ci        patternVar->SetTsType(destructuringContext.InferredType());
3193af6ab5fSopenharmony_ci        return {patternVar->AsLocalVariable(), nullptr, false};
3203af6ab5fSopenharmony_ci    }
3213af6ab5fSopenharmony_ci
3223af6ab5fSopenharmony_ci    patternVar->SetTsType(param->CheckPattern(this));
3233af6ab5fSopenharmony_ci    return {patternVar->AsLocalVariable(), nullptr, false};
3243af6ab5fSopenharmony_ci}
3253af6ab5fSopenharmony_ci
3263af6ab5fSopenharmony_cistd::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> TSChecker::CheckFunctionObjectPatternParameter(
3273af6ab5fSopenharmony_ci    ir::ObjectExpression *param)
3283af6ab5fSopenharmony_ci{
3293af6ab5fSopenharmony_ci    std::stringstream ss;
3303af6ab5fSopenharmony_ci    CreatePatternParameterName(param, ss);
3313af6ab5fSopenharmony_ci    util::UString pn(ss.str(), Allocator());
3323af6ab5fSopenharmony_ci    varbinder::LocalVariable *patternVar =
3333af6ab5fSopenharmony_ci        varbinder::Scope::CreateVar(Allocator(), pn.View(), varbinder::VariableFlags::NONE, param);
3343af6ab5fSopenharmony_ci
3353af6ab5fSopenharmony_ci    if (param->TypeAnnotation() != nullptr) {
3363af6ab5fSopenharmony_ci        auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE);
3373af6ab5fSopenharmony_ci        auto destructuringContext = ObjectDestructuringContext(
3383af6ab5fSopenharmony_ci            {this, param->AsObjectPattern(), false, false, param->TypeAnnotation(), nullptr});
3393af6ab5fSopenharmony_ci        destructuringContext.Start();
3403af6ab5fSopenharmony_ci        patternVar->SetTsType(destructuringContext.InferredType());
3413af6ab5fSopenharmony_ci        return {patternVar->AsLocalVariable(), nullptr, false};
3423af6ab5fSopenharmony_ci    }
3433af6ab5fSopenharmony_ci
3443af6ab5fSopenharmony_ci    patternVar->SetTsType(param->CheckPattern(this));
3453af6ab5fSopenharmony_ci    return {patternVar->AsLocalVariable(), nullptr, false};
3463af6ab5fSopenharmony_ci}
3473af6ab5fSopenharmony_ci
3483af6ab5fSopenharmony_cistd::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> TSChecker::CheckFunctionParameter(
3493af6ab5fSopenharmony_ci    ir::Expression *param, SignatureInfo *signatureInfo)
3503af6ab5fSopenharmony_ci{
3513af6ab5fSopenharmony_ci    std::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> result;
3523af6ab5fSopenharmony_ci    if (param->TsType() != nullptr) {
3533af6ab5fSopenharmony_ci        ASSERT(param->TsType()->Variable());
3543af6ab5fSopenharmony_ci        varbinder::Variable *var = param->TsType()->Variable();
3553af6ab5fSopenharmony_ci        result = {var->AsLocalVariable(), nullptr, var->HasFlag(varbinder::VariableFlags::OPTIONAL)};
3563af6ab5fSopenharmony_ci        return result;
3573af6ab5fSopenharmony_ci    }
3583af6ab5fSopenharmony_ci
3593af6ab5fSopenharmony_ci    bool cache = true;
3603af6ab5fSopenharmony_ci    switch (param->Type()) {
3613af6ab5fSopenharmony_ci        case ir::AstNodeType::IDENTIFIER: {
3623af6ab5fSopenharmony_ci            result = CheckFunctionIdentifierParameter(param->AsIdentifier());
3633af6ab5fSopenharmony_ci            break;
3643af6ab5fSopenharmony_ci        }
3653af6ab5fSopenharmony_ci        case ir::AstNodeType::ASSIGNMENT_PATTERN: {
3663af6ab5fSopenharmony_ci            result = CheckFunctionAssignmentPatternParameter(param->AsAssignmentPattern());
3673af6ab5fSopenharmony_ci            break;
3683af6ab5fSopenharmony_ci        }
3693af6ab5fSopenharmony_ci        case ir::AstNodeType::REST_ELEMENT: {
3703af6ab5fSopenharmony_ci            result = CheckFunctionRestParameter(param->AsRestElement(), signatureInfo);
3713af6ab5fSopenharmony_ci            cache = false;
3723af6ab5fSopenharmony_ci            break;
3733af6ab5fSopenharmony_ci        }
3743af6ab5fSopenharmony_ci        case ir::AstNodeType::ARRAY_PATTERN: {
3753af6ab5fSopenharmony_ci            result = CheckFunctionArrayPatternParameter(param->AsArrayPattern());
3763af6ab5fSopenharmony_ci            break;
3773af6ab5fSopenharmony_ci        }
3783af6ab5fSopenharmony_ci        case ir::AstNodeType::OBJECT_PATTERN: {
3793af6ab5fSopenharmony_ci            result = CheckFunctionObjectPatternParameter(param->AsObjectPattern());
3803af6ab5fSopenharmony_ci            break;
3813af6ab5fSopenharmony_ci        }
3823af6ab5fSopenharmony_ci        default: {
3833af6ab5fSopenharmony_ci            UNREACHABLE();
3843af6ab5fSopenharmony_ci        }
3853af6ab5fSopenharmony_ci    }
3863af6ab5fSopenharmony_ci
3873af6ab5fSopenharmony_ci    if (cache) {
3883af6ab5fSopenharmony_ci        Type *placeholder = Allocator()->New<ArrayType>(GlobalAnyType());
3893af6ab5fSopenharmony_ci        placeholder->SetVariable(std::get<0>(result));
3903af6ab5fSopenharmony_ci        param->SetTsType(placeholder);
3913af6ab5fSopenharmony_ci    }
3923af6ab5fSopenharmony_ci
3933af6ab5fSopenharmony_ci    return result;
3943af6ab5fSopenharmony_ci}
3953af6ab5fSopenharmony_ci
3963af6ab5fSopenharmony_civoid TSChecker::CheckFunctionParameterDeclarations(const ArenaVector<ir::Expression *> &params,
3973af6ab5fSopenharmony_ci                                                   SignatureInfo *signatureInfo)
3983af6ab5fSopenharmony_ci{
3993af6ab5fSopenharmony_ci    signatureInfo->restVar = nullptr;
4003af6ab5fSopenharmony_ci    signatureInfo->minArgCount = 0;
4013af6ab5fSopenharmony_ci
4023af6ab5fSopenharmony_ci    for (auto it = params.rbegin(); it != params.rend(); it++) {
4033af6ab5fSopenharmony_ci        auto [paramVar, restVar, isOptional] = CheckFunctionParameter(*it, signatureInfo);
4043af6ab5fSopenharmony_ci
4053af6ab5fSopenharmony_ci        if (restVar != nullptr) {
4063af6ab5fSopenharmony_ci            signatureInfo->restVar = restVar;
4073af6ab5fSopenharmony_ci            continue;
4083af6ab5fSopenharmony_ci        }
4093af6ab5fSopenharmony_ci
4103af6ab5fSopenharmony_ci        if (paramVar == nullptr) {
4113af6ab5fSopenharmony_ci            continue;
4123af6ab5fSopenharmony_ci        }
4133af6ab5fSopenharmony_ci
4143af6ab5fSopenharmony_ci        signatureInfo->params.insert(signatureInfo->params.begin(), paramVar);
4153af6ab5fSopenharmony_ci
4163af6ab5fSopenharmony_ci        if (!isOptional) {
4173af6ab5fSopenharmony_ci            signatureInfo->minArgCount++;
4183af6ab5fSopenharmony_ci        }
4193af6ab5fSopenharmony_ci    }
4203af6ab5fSopenharmony_ci}
4213af6ab5fSopenharmony_ci
4223af6ab5fSopenharmony_cibool ShouldCreatePropertyValueName(ir::Expression *propValue)
4233af6ab5fSopenharmony_ci{
4243af6ab5fSopenharmony_ci    return propValue->IsArrayPattern() || propValue->IsObjectPattern() ||
4253af6ab5fSopenharmony_ci           (propValue->IsAssignmentPattern() && (propValue->AsAssignmentPattern()->Left()->IsArrayPattern() ||
4263af6ab5fSopenharmony_ci                                                 propValue->AsAssignmentPattern()->Left()->IsObjectPattern()));
4273af6ab5fSopenharmony_ci}
4283af6ab5fSopenharmony_ci
4293af6ab5fSopenharmony_civoid TSChecker::HandlePropertyPatternParameterName(ir::Property *prop, std::stringstream &ss)
4303af6ab5fSopenharmony_ci{
4313af6ab5fSopenharmony_ci    util::StringView propName;
4323af6ab5fSopenharmony_ci    if (prop->Key()->IsIdentifier()) {
4333af6ab5fSopenharmony_ci        propName = prop->Key()->AsIdentifier()->Name();
4343af6ab5fSopenharmony_ci    } else {
4353af6ab5fSopenharmony_ci        switch (prop->Key()->Type()) {
4363af6ab5fSopenharmony_ci            case ir::AstNodeType::NUMBER_LITERAL: {
4373af6ab5fSopenharmony_ci                propName =
4383af6ab5fSopenharmony_ci                    util::Helpers::ToStringView(Allocator(), prop->Key()->AsNumberLiteral()->Number().GetDouble());
4393af6ab5fSopenharmony_ci                break;
4403af6ab5fSopenharmony_ci            }
4413af6ab5fSopenharmony_ci            case ir::AstNodeType::BIGINT_LITERAL: {
4423af6ab5fSopenharmony_ci                propName = prop->Key()->AsBigIntLiteral()->Str();
4433af6ab5fSopenharmony_ci                break;
4443af6ab5fSopenharmony_ci            }
4453af6ab5fSopenharmony_ci            case ir::AstNodeType::STRING_LITERAL: {
4463af6ab5fSopenharmony_ci                propName = prop->Key()->AsStringLiteral()->Str();
4473af6ab5fSopenharmony_ci                break;
4483af6ab5fSopenharmony_ci            }
4493af6ab5fSopenharmony_ci            default: {
4503af6ab5fSopenharmony_ci                UNREACHABLE();
4513af6ab5fSopenharmony_ci                break;
4523af6ab5fSopenharmony_ci            }
4533af6ab5fSopenharmony_ci        }
4543af6ab5fSopenharmony_ci    }
4553af6ab5fSopenharmony_ci
4563af6ab5fSopenharmony_ci    ss << propName;
4573af6ab5fSopenharmony_ci
4583af6ab5fSopenharmony_ci    if (ShouldCreatePropertyValueName(prop->Value())) {
4593af6ab5fSopenharmony_ci        ss << ": ";
4603af6ab5fSopenharmony_ci        TSChecker::CreatePatternParameterName(prop->Value(), ss);
4613af6ab5fSopenharmony_ci    }
4623af6ab5fSopenharmony_ci}
4633af6ab5fSopenharmony_ci
4643af6ab5fSopenharmony_civoid TSChecker::CreatePatternParameterName(ir::AstNode *node, std::stringstream &ss)
4653af6ab5fSopenharmony_ci{
4663af6ab5fSopenharmony_ci    switch (node->Type()) {
4673af6ab5fSopenharmony_ci        case ir::AstNodeType::IDENTIFIER: {
4683af6ab5fSopenharmony_ci            ss << node->AsIdentifier()->Name();
4693af6ab5fSopenharmony_ci            break;
4703af6ab5fSopenharmony_ci        }
4713af6ab5fSopenharmony_ci        case ir::AstNodeType::ARRAY_PATTERN: {
4723af6ab5fSopenharmony_ci            ss << "[";
4733af6ab5fSopenharmony_ci
4743af6ab5fSopenharmony_ci            const auto &elements = node->AsArrayPattern()->Elements();
4753af6ab5fSopenharmony_ci            for (auto it = elements.begin(); it != elements.end(); it++) {
4763af6ab5fSopenharmony_ci                CreatePatternParameterName(*it, ss);
4773af6ab5fSopenharmony_ci                if (std::next(it) != elements.end()) {
4783af6ab5fSopenharmony_ci                    ss << ", ";
4793af6ab5fSopenharmony_ci                }
4803af6ab5fSopenharmony_ci            }
4813af6ab5fSopenharmony_ci
4823af6ab5fSopenharmony_ci            ss << "]";
4833af6ab5fSopenharmony_ci            break;
4843af6ab5fSopenharmony_ci        }
4853af6ab5fSopenharmony_ci        case ir::AstNodeType::OBJECT_PATTERN: {
4863af6ab5fSopenharmony_ci            ss << "{ ";
4873af6ab5fSopenharmony_ci
4883af6ab5fSopenharmony_ci            const auto &properties = node->AsObjectPattern()->Properties();
4893af6ab5fSopenharmony_ci            for (auto it = properties.begin(); it != properties.end(); it++) {
4903af6ab5fSopenharmony_ci                CreatePatternParameterName(*it, ss);
4913af6ab5fSopenharmony_ci                if (std::next(it) != properties.end()) {
4923af6ab5fSopenharmony_ci                    ss << ", ";
4933af6ab5fSopenharmony_ci                }
4943af6ab5fSopenharmony_ci            }
4953af6ab5fSopenharmony_ci
4963af6ab5fSopenharmony_ci            ss << " }";
4973af6ab5fSopenharmony_ci            break;
4983af6ab5fSopenharmony_ci        }
4993af6ab5fSopenharmony_ci        case ir::AstNodeType::ASSIGNMENT_PATTERN: {
5003af6ab5fSopenharmony_ci            CreatePatternParameterName(node->AsAssignmentPattern()->Left(), ss);
5013af6ab5fSopenharmony_ci            break;
5023af6ab5fSopenharmony_ci        }
5033af6ab5fSopenharmony_ci        case ir::AstNodeType::PROPERTY: {
5043af6ab5fSopenharmony_ci            HandlePropertyPatternParameterName(node->AsProperty(), ss);
5053af6ab5fSopenharmony_ci            break;
5063af6ab5fSopenharmony_ci        }
5073af6ab5fSopenharmony_ci        case ir::AstNodeType::REST_ELEMENT: {
5083af6ab5fSopenharmony_ci            ss << "...";
5093af6ab5fSopenharmony_ci            TSChecker::CreatePatternParameterName(node->AsRestElement()->Argument(), ss);
5103af6ab5fSopenharmony_ci            break;
5113af6ab5fSopenharmony_ci        }
5123af6ab5fSopenharmony_ci        default:
5133af6ab5fSopenharmony_ci            break;
5143af6ab5fSopenharmony_ci    }
5153af6ab5fSopenharmony_ci}
5163af6ab5fSopenharmony_ci
5173af6ab5fSopenharmony_ciir::Statement *FindSubsequentFunctionNode(ir::BlockStatement *block, ir::ScriptFunction *node)
5183af6ab5fSopenharmony_ci{
5193af6ab5fSopenharmony_ci    for (auto it = block->Statements().begin(); it != block->Statements().end(); it++) {
5203af6ab5fSopenharmony_ci        if ((*it)->IsFunctionDeclaration() && (*it)->AsFunctionDeclaration()->Function() == node) {
5213af6ab5fSopenharmony_ci            return *(++it);
5223af6ab5fSopenharmony_ci        }
5233af6ab5fSopenharmony_ci    }
5243af6ab5fSopenharmony_ci
5253af6ab5fSopenharmony_ci    UNREACHABLE();
5263af6ab5fSopenharmony_ci    return nullptr;
5273af6ab5fSopenharmony_ci}
5283af6ab5fSopenharmony_ci
5293af6ab5fSopenharmony_civoid TSChecker::ValidateSubsequentNode(const ir::Statement *const subsequentNode, const ir::ScriptFunction *const func)
5303af6ab5fSopenharmony_ci{
5313af6ab5fSopenharmony_ci    if (!subsequentNode->IsFunctionDeclaration()) {
5323af6ab5fSopenharmony_ci        ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
5333af6ab5fSopenharmony_ci                       func->Id()->Start());
5343af6ab5fSopenharmony_ci    }
5353af6ab5fSopenharmony_ci
5363af6ab5fSopenharmony_ci    const ir::ScriptFunction *const subsequentFunc = subsequentNode->AsFunctionDeclaration()->Function();
5373af6ab5fSopenharmony_ci    if (subsequentFunc->Id()->Name() != func->Id()->Name()) {
5383af6ab5fSopenharmony_ci        ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
5393af6ab5fSopenharmony_ci                       func->Id()->Start());
5403af6ab5fSopenharmony_ci    }
5413af6ab5fSopenharmony_ci
5423af6ab5fSopenharmony_ci    if (subsequentFunc->Declare() != func->Declare()) {
5433af6ab5fSopenharmony_ci        ThrowTypeError("Overload signatures must all be ambient or non-ambient.", func->Id()->Start());
5443af6ab5fSopenharmony_ci    }
5453af6ab5fSopenharmony_ci}
5463af6ab5fSopenharmony_ci
5473af6ab5fSopenharmony_civoid TSChecker::CheckOverloadSignatureCompatibility(Signature *bodyCallSignature, Signature *signature)
5483af6ab5fSopenharmony_ci{
5493af6ab5fSopenharmony_ci    if (bodyCallSignature->ReturnType()->IsVoidType() ||
5503af6ab5fSopenharmony_ci        IsTypeAssignableTo(bodyCallSignature->ReturnType(), signature->ReturnType()) ||
5513af6ab5fSopenharmony_ci        IsTypeAssignableTo(signature->ReturnType(), bodyCallSignature->ReturnType())) {
5523af6ab5fSopenharmony_ci        bodyCallSignature->AssignmentTarget(Relation(), signature);
5533af6ab5fSopenharmony_ci
5543af6ab5fSopenharmony_ci        if (Relation()->IsTrue()) {
5553af6ab5fSopenharmony_ci            return;
5563af6ab5fSopenharmony_ci        }
5573af6ab5fSopenharmony_ci    }
5583af6ab5fSopenharmony_ci
5593af6ab5fSopenharmony_ci    ASSERT(signature->Function());
5603af6ab5fSopenharmony_ci    ThrowTypeError("This overload signature is not compatible with its implementation signature",
5613af6ab5fSopenharmony_ci                   signature->Function()->Id()->Start());
5623af6ab5fSopenharmony_ci}
5633af6ab5fSopenharmony_ci
5643af6ab5fSopenharmony_civoid TSChecker::InferFunctionDeclarationType(const varbinder::FunctionDecl *decl, varbinder::Variable *funcVar)
5653af6ab5fSopenharmony_ci{
5663af6ab5fSopenharmony_ci    ir::ScriptFunction *bodyDeclaration = decl->Decls().back();
5673af6ab5fSopenharmony_ci    if (bodyDeclaration->IsOverload()) {
5683af6ab5fSopenharmony_ci        ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
5693af6ab5fSopenharmony_ci                       bodyDeclaration->Id()->Start());
5703af6ab5fSopenharmony_ci    }
5713af6ab5fSopenharmony_ci
5723af6ab5fSopenharmony_ci    ObjectDescriptor *descWithOverload = Allocator()->New<ObjectDescriptor>(Allocator());
5733af6ab5fSopenharmony_ci    for (auto it = decl->Decls().begin(); it != decl->Decls().end() - 1; it++) {
5743af6ab5fSopenharmony_ci        ir::ScriptFunction *func = *it;
5753af6ab5fSopenharmony_ci        ASSERT(func->IsOverload() && (*it)->Parent()->Parent()->IsBlockStatement());
5763af6ab5fSopenharmony_ci        ir::Statement *subsequentNode = FindSubsequentFunctionNode((*it)->Parent()->Parent()->AsBlockStatement(), func);
5773af6ab5fSopenharmony_ci        ASSERT(subsequentNode);
5783af6ab5fSopenharmony_ci        ValidateSubsequentNode(subsequentNode, func);
5793af6ab5fSopenharmony_ci
5803af6ab5fSopenharmony_ci        ScopeContext scopeCtx(this, func->Scope());
5813af6ab5fSopenharmony_ci
5823af6ab5fSopenharmony_ci        auto *overloadSignatureInfo = Allocator()->New<checker::SignatureInfo>(Allocator());
5833af6ab5fSopenharmony_ci        CheckFunctionParameterDeclarations(func->Params(), overloadSignatureInfo);
5843af6ab5fSopenharmony_ci
5853af6ab5fSopenharmony_ci        Type *returnType = GlobalAnyType();
5863af6ab5fSopenharmony_ci
5873af6ab5fSopenharmony_ci        if (func->ReturnTypeAnnotation() != nullptr) {
5883af6ab5fSopenharmony_ci            func->ReturnTypeAnnotation()->Check(this);
5893af6ab5fSopenharmony_ci            returnType = func->ReturnTypeAnnotation()->GetType(this);
5903af6ab5fSopenharmony_ci        }
5913af6ab5fSopenharmony_ci
5923af6ab5fSopenharmony_ci        Signature *overloadSignature = Allocator()->New<checker::Signature>(overloadSignatureInfo, returnType, func);
5933af6ab5fSopenharmony_ci        descWithOverload->callSignatures.push_back(overloadSignature);
5943af6ab5fSopenharmony_ci    }
5953af6ab5fSopenharmony_ci
5963af6ab5fSopenharmony_ci    ScopeContext scopeCtx(this, bodyDeclaration->Scope());
5973af6ab5fSopenharmony_ci
5983af6ab5fSopenharmony_ci    auto *signatureInfo = Allocator()->New<checker::SignatureInfo>(Allocator());
5993af6ab5fSopenharmony_ci    CheckFunctionParameterDeclarations(bodyDeclaration->Params(), signatureInfo);
6003af6ab5fSopenharmony_ci    auto *bodyCallSignature = Allocator()->New<checker::Signature>(signatureInfo, GlobalResolvingReturnType());
6013af6ab5fSopenharmony_ci
6023af6ab5fSopenharmony_ci    if (descWithOverload->callSignatures.empty()) {
6033af6ab5fSopenharmony_ci        Type *funcType = CreateFunctionTypeWithSignature(bodyCallSignature);
6043af6ab5fSopenharmony_ci        funcType->SetVariable(funcVar);
6053af6ab5fSopenharmony_ci        funcVar->SetTsType(funcType);
6063af6ab5fSopenharmony_ci    }
6073af6ab5fSopenharmony_ci
6083af6ab5fSopenharmony_ci    bodyCallSignature->SetReturnType(HandleFunctionReturn(bodyDeclaration));
6093af6ab5fSopenharmony_ci
6103af6ab5fSopenharmony_ci    if (!descWithOverload->callSignatures.empty()) {
6113af6ab5fSopenharmony_ci        Type *funcType = Allocator()->New<FunctionType>(descWithOverload);
6123af6ab5fSopenharmony_ci        funcType->SetVariable(funcVar);
6133af6ab5fSopenharmony_ci        funcVar->SetTsType(funcType);
6143af6ab5fSopenharmony_ci
6153af6ab5fSopenharmony_ci        for (auto *iter : descWithOverload->callSignatures) {
6163af6ab5fSopenharmony_ci            CheckOverloadSignatureCompatibility(bodyCallSignature, iter);
6173af6ab5fSopenharmony_ci        }
6183af6ab5fSopenharmony_ci    }
6193af6ab5fSopenharmony_ci}
6203af6ab5fSopenharmony_ci
6213af6ab5fSopenharmony_civoid TSChecker::CollectTypesFromReturnStatements(ir::AstNode *parent, ArenaVector<Type *> *returnTypes)
6223af6ab5fSopenharmony_ci{
6233af6ab5fSopenharmony_ci    parent->Iterate([this, returnTypes](ir::AstNode *childNode) -> void {
6243af6ab5fSopenharmony_ci        if (childNode->IsScriptFunction()) {
6253af6ab5fSopenharmony_ci            return;
6263af6ab5fSopenharmony_ci        }
6273af6ab5fSopenharmony_ci
6283af6ab5fSopenharmony_ci        if (childNode->IsReturnStatement()) {
6293af6ab5fSopenharmony_ci            ir::ReturnStatement *returnStmt = childNode->AsReturnStatement();
6303af6ab5fSopenharmony_ci
6313af6ab5fSopenharmony_ci            if (returnStmt->Argument() == nullptr) {
6323af6ab5fSopenharmony_ci                return;
6333af6ab5fSopenharmony_ci            }
6343af6ab5fSopenharmony_ci
6353af6ab5fSopenharmony_ci            returnTypes->push_back(
6363af6ab5fSopenharmony_ci                GetBaseTypeOfLiteralType(CheckTypeCached(childNode->AsReturnStatement()->Argument())));
6373af6ab5fSopenharmony_ci        }
6383af6ab5fSopenharmony_ci
6393af6ab5fSopenharmony_ci        CollectTypesFromReturnStatements(childNode, returnTypes);
6403af6ab5fSopenharmony_ci    });
6413af6ab5fSopenharmony_ci}
6423af6ab5fSopenharmony_ci
6433af6ab5fSopenharmony_cistatic bool SearchForReturnOrThrow(ir::AstNode *parent)
6443af6ab5fSopenharmony_ci{
6453af6ab5fSopenharmony_ci    bool found = false;
6463af6ab5fSopenharmony_ci
6473af6ab5fSopenharmony_ci    parent->Iterate([&found](ir::AstNode *childNode) -> void {
6483af6ab5fSopenharmony_ci        if (childNode->IsThrowStatement() || childNode->IsReturnStatement()) {
6493af6ab5fSopenharmony_ci            found = true;
6503af6ab5fSopenharmony_ci            return;
6513af6ab5fSopenharmony_ci        }
6523af6ab5fSopenharmony_ci
6533af6ab5fSopenharmony_ci        if (childNode->IsScriptFunction()) {
6543af6ab5fSopenharmony_ci            return;
6553af6ab5fSopenharmony_ci        }
6563af6ab5fSopenharmony_ci
6573af6ab5fSopenharmony_ci        SearchForReturnOrThrow(childNode);
6583af6ab5fSopenharmony_ci    });
6593af6ab5fSopenharmony_ci
6603af6ab5fSopenharmony_ci    return found;
6613af6ab5fSopenharmony_ci}
6623af6ab5fSopenharmony_ci
6633af6ab5fSopenharmony_civoid TSChecker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(ir::ScriptFunction *func,
6643af6ab5fSopenharmony_ci                                                                lexer::SourcePosition lineInfo, const char *errMsg)
6653af6ab5fSopenharmony_ci{
6663af6ab5fSopenharmony_ci    if (!SearchForReturnOrThrow(func->Body())) {
6673af6ab5fSopenharmony_ci        ThrowTypeError(errMsg, lineInfo);
6683af6ab5fSopenharmony_ci    }
6693af6ab5fSopenharmony_ci    // NOTE: aszilagyi. this function is not fully implement the TSC one, in the future if we will have a
6703af6ab5fSopenharmony_ci    // noImplicitReturn compiler option for TypeScript we should update this function
6713af6ab5fSopenharmony_ci}
6723af6ab5fSopenharmony_ci
6733af6ab5fSopenharmony_ciArgRange TSChecker::GetArgRange(const ArenaVector<Signature *> &signatures,
6743af6ab5fSopenharmony_ci                                ArenaVector<Signature *> *potentialSignatures, uint32_t callArgsSize,
6753af6ab5fSopenharmony_ci                                bool *haveSignatureWithRest)
6763af6ab5fSopenharmony_ci{
6773af6ab5fSopenharmony_ci    uint32_t minArg = UINT32_MAX;
6783af6ab5fSopenharmony_ci    uint32_t maxArg = 0;
6793af6ab5fSopenharmony_ci
6803af6ab5fSopenharmony_ci    for (auto *it : signatures) {
6813af6ab5fSopenharmony_ci        if (it->RestVar() != nullptr) {
6823af6ab5fSopenharmony_ci            *haveSignatureWithRest = true;
6833af6ab5fSopenharmony_ci        }
6843af6ab5fSopenharmony_ci
6853af6ab5fSopenharmony_ci        if (it->MinArgCount() < minArg) {
6863af6ab5fSopenharmony_ci            minArg = it->MinArgCount();
6873af6ab5fSopenharmony_ci        }
6883af6ab5fSopenharmony_ci
6893af6ab5fSopenharmony_ci        if (it->Params().size() > maxArg) {
6903af6ab5fSopenharmony_ci            maxArg = it->Params().size();
6913af6ab5fSopenharmony_ci        }
6923af6ab5fSopenharmony_ci
6933af6ab5fSopenharmony_ci        if (callArgsSize >= it->MinArgCount() && (callArgsSize <= it->Params().size() || it->RestVar() != nullptr)) {
6943af6ab5fSopenharmony_ci            potentialSignatures->push_back(it);
6953af6ab5fSopenharmony_ci        }
6963af6ab5fSopenharmony_ci    }
6973af6ab5fSopenharmony_ci
6983af6ab5fSopenharmony_ci    return {minArg, maxArg};
6993af6ab5fSopenharmony_ci}
7003af6ab5fSopenharmony_ci
7013af6ab5fSopenharmony_cibool TSChecker::CallMatchesSignature(const ArenaVector<ir::Expression *> &args, Signature *signature, bool throwError)
7023af6ab5fSopenharmony_ci{
7033af6ab5fSopenharmony_ci    for (size_t index = 0; index < args.size(); index++) {
7043af6ab5fSopenharmony_ci        checker::Type *sigArgType = nullptr;
7053af6ab5fSopenharmony_ci        bool validateRestArg = false;
7063af6ab5fSopenharmony_ci
7073af6ab5fSopenharmony_ci        if (index >= signature->Params().size()) {
7083af6ab5fSopenharmony_ci            ASSERT(signature->RestVar());
7093af6ab5fSopenharmony_ci            validateRestArg = true;
7103af6ab5fSopenharmony_ci            sigArgType = signature->RestVar()->TsType();
7113af6ab5fSopenharmony_ci        } else {
7123af6ab5fSopenharmony_ci            sigArgType = signature->Params()[index]->TsType();
7133af6ab5fSopenharmony_ci        }
7143af6ab5fSopenharmony_ci
7153af6ab5fSopenharmony_ci        if (validateRestArg || !throwError) {
7163af6ab5fSopenharmony_ci            checker::Type *callArgType = GetBaseTypeOfLiteralType(args[index]->Check(this));
7173af6ab5fSopenharmony_ci            if (IsTypeAssignableTo(callArgType, sigArgType)) {
7183af6ab5fSopenharmony_ci                continue;
7193af6ab5fSopenharmony_ci            }
7203af6ab5fSopenharmony_ci
7213af6ab5fSopenharmony_ci            if (throwError) {
7223af6ab5fSopenharmony_ci                ThrowTypeError(
7233af6ab5fSopenharmony_ci                    {"Argument of type '", callArgType, "' is not assignable to parameter of type '", sigArgType, "'."},
7243af6ab5fSopenharmony_ci                    args[index]->Start());
7253af6ab5fSopenharmony_ci            }
7263af6ab5fSopenharmony_ci            return false;
7273af6ab5fSopenharmony_ci        }
7283af6ab5fSopenharmony_ci
7293af6ab5fSopenharmony_ci        ElaborateElementwise(sigArgType, args[index], args[index]->Start());
7303af6ab5fSopenharmony_ci    }
7313af6ab5fSopenharmony_ci
7323af6ab5fSopenharmony_ci    return true;
7333af6ab5fSopenharmony_ci}
7343af6ab5fSopenharmony_ci
7353af6ab5fSopenharmony_ciType *TSChecker::ResolveCallOrNewExpression(const ArenaVector<Signature *> &signatures,
7363af6ab5fSopenharmony_ci                                            ArenaVector<ir::Expression *> arguments,
7373af6ab5fSopenharmony_ci                                            const lexer::SourcePosition &errPos)
7383af6ab5fSopenharmony_ci{
7393af6ab5fSopenharmony_ci    if (signatures.empty()) {
7403af6ab5fSopenharmony_ci        ThrowTypeError("This expression is not callable.", errPos);
7413af6ab5fSopenharmony_ci    }
7423af6ab5fSopenharmony_ci
7433af6ab5fSopenharmony_ci    ArenaVector<checker::Signature *> potentialSignatures(Allocator()->Adapter());
7443af6ab5fSopenharmony_ci    bool haveSignatureWithRest = false;
7453af6ab5fSopenharmony_ci
7463af6ab5fSopenharmony_ci    auto argRange = GetArgRange(signatures, &potentialSignatures, arguments.size(), &haveSignatureWithRest);
7473af6ab5fSopenharmony_ci
7483af6ab5fSopenharmony_ci    if (potentialSignatures.empty()) {
7493af6ab5fSopenharmony_ci        if (haveSignatureWithRest) {
7503af6ab5fSopenharmony_ci            ThrowTypeError({"Expected at least ", argRange.first, " arguments, but got ", arguments.size(), "."},
7513af6ab5fSopenharmony_ci                           errPos);
7523af6ab5fSopenharmony_ci        }
7533af6ab5fSopenharmony_ci
7543af6ab5fSopenharmony_ci        if (signatures.size() == 1 && argRange.first == argRange.second) {
7553af6ab5fSopenharmony_ci            lexer::SourcePosition loc =
7563af6ab5fSopenharmony_ci                (argRange.first > arguments.size()) ? errPos : arguments[argRange.second]->Start();
7573af6ab5fSopenharmony_ci            ThrowTypeError({"Expected ", argRange.first, " arguments, but got ", arguments.size(), "."}, loc);
7583af6ab5fSopenharmony_ci        }
7593af6ab5fSopenharmony_ci
7603af6ab5fSopenharmony_ci        ThrowTypeError({"Expected ", argRange.first, "-", argRange.second, " arguments, but got ", arguments.size()},
7613af6ab5fSopenharmony_ci                       errPos);
7623af6ab5fSopenharmony_ci    }
7633af6ab5fSopenharmony_ci
7643af6ab5fSopenharmony_ci    checker::Type *returnType = nullptr;
7653af6ab5fSopenharmony_ci    for (auto *it : potentialSignatures) {
7663af6ab5fSopenharmony_ci        if (CallMatchesSignature(arguments, it, potentialSignatures.size() == 1)) {
7673af6ab5fSopenharmony_ci            returnType = it->ReturnType();
7683af6ab5fSopenharmony_ci            break;
7693af6ab5fSopenharmony_ci        }
7703af6ab5fSopenharmony_ci    }
7713af6ab5fSopenharmony_ci
7723af6ab5fSopenharmony_ci    if (returnType == nullptr) {
7733af6ab5fSopenharmony_ci        ThrowTypeError("No overload matches this call.", errPos);
7743af6ab5fSopenharmony_ci    }
7753af6ab5fSopenharmony_ci
7763af6ab5fSopenharmony_ci    return returnType;
7773af6ab5fSopenharmony_ci}
7783af6ab5fSopenharmony_ci}  // namespace ark::es2panda::checker
779