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 "TSAnalyzer.h"
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_ci#include "checker/TSchecker.h"
193af6ab5fSopenharmony_ci#include "checker/ts/destructuringContext.h"
203af6ab5fSopenharmony_ci
213af6ab5fSopenharmony_cinamespace ark::es2panda::checker {
223af6ab5fSopenharmony_ci
233af6ab5fSopenharmony_ciTSChecker *TSAnalyzer::GetTSChecker() const
243af6ab5fSopenharmony_ci{
253af6ab5fSopenharmony_ci    return static_cast<TSChecker *>(GetChecker());
263af6ab5fSopenharmony_ci}
273af6ab5fSopenharmony_ci
283af6ab5fSopenharmony_ci// from base folder
293af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::CatchClause *st) const
303af6ab5fSopenharmony_ci{
313af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
323af6ab5fSopenharmony_ci    ir::Expression *typeAnnotation = st->Param()->AsAnnotatedExpression()->TypeAnnotation();
333af6ab5fSopenharmony_ci
343af6ab5fSopenharmony_ci    if (typeAnnotation != nullptr) {
353af6ab5fSopenharmony_ci        checker::Type *catchParamType = typeAnnotation->Check(checker);
363af6ab5fSopenharmony_ci
373af6ab5fSopenharmony_ci        if (!catchParamType->HasTypeFlag(checker::TypeFlag::ANY_OR_UNKNOWN)) {
383af6ab5fSopenharmony_ci            checker->ThrowTypeError("Catch clause variable type annotation must be 'any' or 'unknown' if specified",
393af6ab5fSopenharmony_ci                                    st->Start());
403af6ab5fSopenharmony_ci        }
413af6ab5fSopenharmony_ci    }
423af6ab5fSopenharmony_ci
433af6ab5fSopenharmony_ci    st->Body()->Check(checker);
443af6ab5fSopenharmony_ci
453af6ab5fSopenharmony_ci    return nullptr;
463af6ab5fSopenharmony_ci}
473af6ab5fSopenharmony_ci
483af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ClassDefinition *node) const
493af6ab5fSopenharmony_ci{
503af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
513af6ab5fSopenharmony_ci    // NOTE: aszilagyi.
523af6ab5fSopenharmony_ci    return checker->GlobalAnyType();
533af6ab5fSopenharmony_ci}
543af6ab5fSopenharmony_ci
553af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::MetaProperty *expr) const
563af6ab5fSopenharmony_ci{
573af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
583af6ab5fSopenharmony_ci    // NOTE: aszilagyi.
593af6ab5fSopenharmony_ci    return checker->GlobalAnyType();
603af6ab5fSopenharmony_ci}
613af6ab5fSopenharmony_ci
623af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSIndexSignature *node) const
633af6ab5fSopenharmony_ci{
643af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
653af6ab5fSopenharmony_ci    if (node->TsType() != nullptr) {
663af6ab5fSopenharmony_ci        return node->TsType();
673af6ab5fSopenharmony_ci    }
683af6ab5fSopenharmony_ci
693af6ab5fSopenharmony_ci    const util::StringView &paramName = node->Param()->AsIdentifier()->Name();
703af6ab5fSopenharmony_ci    node->typeAnnotation_->Check(checker);
713af6ab5fSopenharmony_ci    checker::Type *indexType = node->typeAnnotation_->GetType(checker);
723af6ab5fSopenharmony_ci    checker::IndexInfo *info =
733af6ab5fSopenharmony_ci        checker->Allocator()->New<checker::IndexInfo>(indexType, paramName, node->Readonly(), node->Start());
743af6ab5fSopenharmony_ci    checker::ObjectDescriptor *desc = checker->Allocator()->New<checker::ObjectDescriptor>(checker->Allocator());
753af6ab5fSopenharmony_ci    checker::ObjectType *placeholder = checker->Allocator()->New<checker::ObjectLiteralType>(desc);
763af6ab5fSopenharmony_ci
773af6ab5fSopenharmony_ci    if (node->Kind() == ir::TSIndexSignature::TSIndexSignatureKind::NUMBER) {
783af6ab5fSopenharmony_ci        placeholder->Desc()->numberIndexInfo = info;
793af6ab5fSopenharmony_ci    } else {
803af6ab5fSopenharmony_ci        placeholder->Desc()->stringIndexInfo = info;
813af6ab5fSopenharmony_ci    }
823af6ab5fSopenharmony_ci
833af6ab5fSopenharmony_ci    node->SetTsType(placeholder);
843af6ab5fSopenharmony_ci    return placeholder;
853af6ab5fSopenharmony_ci}
863af6ab5fSopenharmony_ci
873af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSMethodSignature *node) const
883af6ab5fSopenharmony_ci{
893af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
903af6ab5fSopenharmony_ci    if (node->Computed()) {
913af6ab5fSopenharmony_ci        checker->CheckComputedPropertyName(node->Key());
923af6ab5fSopenharmony_ci    }
933af6ab5fSopenharmony_ci
943af6ab5fSopenharmony_ci    checker::ScopeContext scopeCtx(checker, node->Scope());
953af6ab5fSopenharmony_ci
963af6ab5fSopenharmony_ci    auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
973af6ab5fSopenharmony_ci    checker->CheckFunctionParameterDeclarations(node->Params(), signatureInfo);
983af6ab5fSopenharmony_ci
993af6ab5fSopenharmony_ci    auto *callSignature = checker->Allocator()->New<checker::Signature>(signatureInfo, checker->GlobalAnyType());
1003af6ab5fSopenharmony_ci    node->Variable()->SetTsType(checker->CreateFunctionTypeWithSignature(callSignature));
1013af6ab5fSopenharmony_ci
1023af6ab5fSopenharmony_ci    auto returnType = node->ReturnTypeAnnotation();
1033af6ab5fSopenharmony_ci    if (returnType == nullptr) {
1043af6ab5fSopenharmony_ci        checker->ThrowTypeError(
1053af6ab5fSopenharmony_ci            "Method signature, which lacks return-type annotation, implicitly has an 'any' return type.",
1063af6ab5fSopenharmony_ci            node->Start());
1073af6ab5fSopenharmony_ci    }
1083af6ab5fSopenharmony_ci
1093af6ab5fSopenharmony_ci    returnType->Check(checker);
1103af6ab5fSopenharmony_ci    callSignature->SetReturnType(returnType->GetType(checker));
1113af6ab5fSopenharmony_ci
1123af6ab5fSopenharmony_ci    return nullptr;
1133af6ab5fSopenharmony_ci}
1143af6ab5fSopenharmony_ci
1153af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSPropertySignature *node) const
1163af6ab5fSopenharmony_ci{
1173af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
1183af6ab5fSopenharmony_ci    if (node->TypeAnnotation() != nullptr) {
1193af6ab5fSopenharmony_ci        node->TypeAnnotation()->Check(checker);
1203af6ab5fSopenharmony_ci    }
1213af6ab5fSopenharmony_ci
1223af6ab5fSopenharmony_ci    if (node->Computed()) {
1233af6ab5fSopenharmony_ci        checker->CheckComputedPropertyName(node->Key());
1243af6ab5fSopenharmony_ci    }
1253af6ab5fSopenharmony_ci
1263af6ab5fSopenharmony_ci    if (node->TypeAnnotation() != nullptr) {
1273af6ab5fSopenharmony_ci        node->Variable()->SetTsType(node->TypeAnnotation()->GetType(checker));
1283af6ab5fSopenharmony_ci        return nullptr;
1293af6ab5fSopenharmony_ci    }
1303af6ab5fSopenharmony_ci
1313af6ab5fSopenharmony_ci    checker->ThrowTypeError("Property implicitly has an 'any' type.", node->Start());
1323af6ab5fSopenharmony_ci    return nullptr;
1333af6ab5fSopenharmony_ci}
1343af6ab5fSopenharmony_ci
1353af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSSignatureDeclaration *node) const
1363af6ab5fSopenharmony_ci{
1373af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
1383af6ab5fSopenharmony_ci    if (node->TsType() != nullptr) {
1393af6ab5fSopenharmony_ci        return node->TsType();
1403af6ab5fSopenharmony_ci    }
1413af6ab5fSopenharmony_ci
1423af6ab5fSopenharmony_ci    checker::ScopeContext scopeCtx(checker, node->Scope());
1433af6ab5fSopenharmony_ci
1443af6ab5fSopenharmony_ci    auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
1453af6ab5fSopenharmony_ci    checker->CheckFunctionParameterDeclarations(node->Params(), signatureInfo);
1463af6ab5fSopenharmony_ci
1473af6ab5fSopenharmony_ci    bool isCallSignature = (node->Kind() == ir::TSSignatureDeclaration::TSSignatureDeclarationKind::CALL_SIGNATURE);
1483af6ab5fSopenharmony_ci
1493af6ab5fSopenharmony_ci    if (node->ReturnTypeAnnotation() == nullptr) {
1503af6ab5fSopenharmony_ci        if (isCallSignature) {
1513af6ab5fSopenharmony_ci            checker->ThrowTypeError(
1523af6ab5fSopenharmony_ci                "Call signature, which lacks return-type annotation, implicitly has an 'any' return type.",
1533af6ab5fSopenharmony_ci                node->Start());
1543af6ab5fSopenharmony_ci        }
1553af6ab5fSopenharmony_ci
1563af6ab5fSopenharmony_ci        checker->ThrowTypeError(
1573af6ab5fSopenharmony_ci            "Construct signature, which lacks return-type annotation, implicitly has an 'any' return type.",
1583af6ab5fSopenharmony_ci            node->Start());
1593af6ab5fSopenharmony_ci    }
1603af6ab5fSopenharmony_ci
1613af6ab5fSopenharmony_ci    node->ReturnTypeAnnotation()->Check(checker);
1623af6ab5fSopenharmony_ci    checker::Type *returnType = node->ReturnTypeAnnotation()->GetType(checker);
1633af6ab5fSopenharmony_ci
1643af6ab5fSopenharmony_ci    auto *signature = checker->Allocator()->New<checker::Signature>(signatureInfo, returnType);
1653af6ab5fSopenharmony_ci
1663af6ab5fSopenharmony_ci    checker::Type *placeholderObj = nullptr;
1673af6ab5fSopenharmony_ci
1683af6ab5fSopenharmony_ci    if (isCallSignature) {
1693af6ab5fSopenharmony_ci        placeholderObj = checker->CreateObjectTypeWithCallSignature(signature);
1703af6ab5fSopenharmony_ci    } else {
1713af6ab5fSopenharmony_ci        placeholderObj = checker->CreateObjectTypeWithConstructSignature(signature);
1723af6ab5fSopenharmony_ci    }
1733af6ab5fSopenharmony_ci
1743af6ab5fSopenharmony_ci    node->SetTsType(placeholderObj);
1753af6ab5fSopenharmony_ci    return placeholderObj;
1763af6ab5fSopenharmony_ci}
1773af6ab5fSopenharmony_ci
1783af6ab5fSopenharmony_cistatic void GetSpreadElementType(checker::TSChecker *checker, checker::Type *spreadType,
1793af6ab5fSopenharmony_ci                                 ArenaVector<checker::Type *> &elementTypes, const lexer::SourcePosition &loc)
1803af6ab5fSopenharmony_ci{
1813af6ab5fSopenharmony_ci    bool inConstContext = checker->HasStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
1823af6ab5fSopenharmony_ci
1833af6ab5fSopenharmony_ci    if (spreadType->IsObjectType() && spreadType->AsObjectType()->IsTupleType()) {
1843af6ab5fSopenharmony_ci        ArenaVector<checker::Type *> tupleElementTypes(checker->Allocator()->Adapter());
1853af6ab5fSopenharmony_ci        checker::TupleType *spreadTuple = spreadType->AsObjectType()->AsTupleType();
1863af6ab5fSopenharmony_ci
1873af6ab5fSopenharmony_ci        for (auto *it : spreadTuple->Properties()) {
1883af6ab5fSopenharmony_ci            if (inConstContext) {
1893af6ab5fSopenharmony_ci                elementTypes.push_back(it->TsType());
1903af6ab5fSopenharmony_ci                continue;
1913af6ab5fSopenharmony_ci            }
1923af6ab5fSopenharmony_ci
1933af6ab5fSopenharmony_ci            tupleElementTypes.push_back(it->TsType());
1943af6ab5fSopenharmony_ci        }
1953af6ab5fSopenharmony_ci
1963af6ab5fSopenharmony_ci        if (inConstContext) {
1973af6ab5fSopenharmony_ci            return;
1983af6ab5fSopenharmony_ci        }
1993af6ab5fSopenharmony_ci
2003af6ab5fSopenharmony_ci        elementTypes.push_back(checker->CreateUnionType(std::move(tupleElementTypes)));
2013af6ab5fSopenharmony_ci        return;
2023af6ab5fSopenharmony_ci    }
2033af6ab5fSopenharmony_ci
2043af6ab5fSopenharmony_ci    if (!spreadType->IsUnionType()) {
2053af6ab5fSopenharmony_ci        checker->ThrowTypeError(
2063af6ab5fSopenharmony_ci            {"Type '", spreadType, "' must have a '[Symbol.iterator]()' method that returns an iterator."}, loc);
2073af6ab5fSopenharmony_ci        return;
2083af6ab5fSopenharmony_ci    }
2093af6ab5fSopenharmony_ci
2103af6ab5fSopenharmony_ci    ArenaVector<checker::Type *> spreadTypes(checker->Allocator()->Adapter());
2113af6ab5fSopenharmony_ci    bool throwError = false;
2123af6ab5fSopenharmony_ci
2133af6ab5fSopenharmony_ci    for (auto *type : spreadType->AsUnionType()->ConstituentTypes()) {
2143af6ab5fSopenharmony_ci        if (type->IsArrayType()) {
2153af6ab5fSopenharmony_ci            spreadTypes.push_back(type->AsArrayType()->ElementType());
2163af6ab5fSopenharmony_ci            continue;
2173af6ab5fSopenharmony_ci        }
2183af6ab5fSopenharmony_ci
2193af6ab5fSopenharmony_ci        if (type->IsObjectType() && type->AsObjectType()->IsTupleType()) {
2203af6ab5fSopenharmony_ci            checker::TupleType *tuple = type->AsObjectType()->AsTupleType();
2213af6ab5fSopenharmony_ci
2223af6ab5fSopenharmony_ci            for (auto *it : tuple->Properties()) {
2233af6ab5fSopenharmony_ci                spreadTypes.push_back(it->TsType());
2243af6ab5fSopenharmony_ci            }
2253af6ab5fSopenharmony_ci
2263af6ab5fSopenharmony_ci            continue;
2273af6ab5fSopenharmony_ci        }
2283af6ab5fSopenharmony_ci
2293af6ab5fSopenharmony_ci        throwError = true;
2303af6ab5fSopenharmony_ci        break;
2313af6ab5fSopenharmony_ci    }
2323af6ab5fSopenharmony_ci
2333af6ab5fSopenharmony_ci    if (!throwError) {
2343af6ab5fSopenharmony_ci        elementTypes.push_back(checker->CreateUnionType(std::move(spreadTypes)));
2353af6ab5fSopenharmony_ci        return;
2363af6ab5fSopenharmony_ci    }
2373af6ab5fSopenharmony_ci
2383af6ab5fSopenharmony_ci    checker->ThrowTypeError(
2393af6ab5fSopenharmony_ci        {"Type '", spreadType, "' must have a '[Symbol.iterator]()' method that returns an iterator."}, loc);
2403af6ab5fSopenharmony_ci}
2413af6ab5fSopenharmony_ci
2423af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::ArrayExpression *expr) const
2433af6ab5fSopenharmony_ci{
2443af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
2453af6ab5fSopenharmony_ci    ArenaVector<checker::Type *> elementTypes(checker->Allocator()->Adapter());
2463af6ab5fSopenharmony_ci    ArenaVector<checker::ElementFlags> elementFlags(checker->Allocator()->Adapter());
2473af6ab5fSopenharmony_ci    bool inConstContext = checker->HasStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
2483af6ab5fSopenharmony_ci    bool createTuple = checker->HasStatus(checker::CheckerStatus::FORCE_TUPLE);
2493af6ab5fSopenharmony_ci
2503af6ab5fSopenharmony_ci    for (auto *it : expr->Elements()) {
2513af6ab5fSopenharmony_ci        if (it->IsSpreadElement()) {
2523af6ab5fSopenharmony_ci            checker::Type *spreadType = it->AsSpreadElement()->Argument()->Check(checker);
2533af6ab5fSopenharmony_ci
2543af6ab5fSopenharmony_ci            if (spreadType->IsArrayType()) {
2553af6ab5fSopenharmony_ci                elementTypes.push_back(inConstContext ? spreadType : spreadType->AsArrayType()->ElementType());
2563af6ab5fSopenharmony_ci                elementFlags.push_back(checker::ElementFlags::VARIADIC);
2573af6ab5fSopenharmony_ci                continue;
2583af6ab5fSopenharmony_ci            }
2593af6ab5fSopenharmony_ci
2603af6ab5fSopenharmony_ci            GetSpreadElementType(checker, spreadType, elementTypes, it->Start());
2613af6ab5fSopenharmony_ci            elementFlags.push_back(checker::ElementFlags::REST);
2623af6ab5fSopenharmony_ci            continue;
2633af6ab5fSopenharmony_ci        }
2643af6ab5fSopenharmony_ci
2653af6ab5fSopenharmony_ci        checker::Type *elementType = it->Check(checker);
2663af6ab5fSopenharmony_ci
2673af6ab5fSopenharmony_ci        if (!inConstContext) {
2683af6ab5fSopenharmony_ci            elementType = checker->GetBaseTypeOfLiteralType(elementType);
2693af6ab5fSopenharmony_ci        }
2703af6ab5fSopenharmony_ci
2713af6ab5fSopenharmony_ci        elementFlags.push_back(checker::ElementFlags::REQUIRED);
2723af6ab5fSopenharmony_ci        elementTypes.push_back(elementType);
2733af6ab5fSopenharmony_ci    }
2743af6ab5fSopenharmony_ci
2753af6ab5fSopenharmony_ci    if (inConstContext || createTuple) {
2763af6ab5fSopenharmony_ci        checker::ObjectDescriptor *desc = checker->Allocator()->New<checker::ObjectDescriptor>(checker->Allocator());
2773af6ab5fSopenharmony_ci        uint32_t index = 0;
2783af6ab5fSopenharmony_ci
2793af6ab5fSopenharmony_ci        for (auto it = elementTypes.begin(); it != elementTypes.end(); it++, index++) {
2803af6ab5fSopenharmony_ci            util::StringView memberIndex = util::Helpers::ToStringView(checker->Allocator(), index);
2813af6ab5fSopenharmony_ci            varbinder::LocalVariable *tupleMember = varbinder::Scope::CreateVar(
2823af6ab5fSopenharmony_ci                checker->Allocator(), memberIndex, varbinder::VariableFlags::PROPERTY, nullptr);
2833af6ab5fSopenharmony_ci
2843af6ab5fSopenharmony_ci            if (inConstContext) {
2853af6ab5fSopenharmony_ci                tupleMember->AddFlag(varbinder::VariableFlags::READONLY);
2863af6ab5fSopenharmony_ci            }
2873af6ab5fSopenharmony_ci
2883af6ab5fSopenharmony_ci            tupleMember->SetTsType(*it);
2893af6ab5fSopenharmony_ci            desc->properties.push_back(tupleMember);
2903af6ab5fSopenharmony_ci        }
2913af6ab5fSopenharmony_ci
2923af6ab5fSopenharmony_ci        const checker::TupleTypeInfo tupleTypeInfo = {ElementFlags::REQUIRED, index, index, inConstContext};
2933af6ab5fSopenharmony_ci        return checker->CreateTupleType(desc, std::move(elementFlags), tupleTypeInfo);
2943af6ab5fSopenharmony_ci    }
2953af6ab5fSopenharmony_ci
2963af6ab5fSopenharmony_ci    checker::Type *arrayElementType = nullptr;
2973af6ab5fSopenharmony_ci    if (elementTypes.empty()) {
2983af6ab5fSopenharmony_ci        arrayElementType = checker->GlobalAnyType();
2993af6ab5fSopenharmony_ci    } else {
3003af6ab5fSopenharmony_ci        arrayElementType = checker->CreateUnionType(std::move(elementTypes));
3013af6ab5fSopenharmony_ci    }
3023af6ab5fSopenharmony_ci
3033af6ab5fSopenharmony_ci    return checker->Allocator()->New<checker::ArrayType>(arrayElementType);
3043af6ab5fSopenharmony_ci}
3053af6ab5fSopenharmony_ci
3063af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::ArrowFunctionExpression *expr) const
3073af6ab5fSopenharmony_ci{
3083af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
3093af6ab5fSopenharmony_ci    varbinder::Variable *funcVar = nullptr;
3103af6ab5fSopenharmony_ci
3113af6ab5fSopenharmony_ci    if (expr->Function()->Parent()->Parent() != nullptr &&
3123af6ab5fSopenharmony_ci        expr->Function()->Parent()->Parent()->IsVariableDeclarator() &&
3133af6ab5fSopenharmony_ci        expr->Function()->Parent()->Parent()->AsVariableDeclarator()->Id()->IsIdentifier()) {
3143af6ab5fSopenharmony_ci        funcVar = expr->Function()->Parent()->Parent()->AsVariableDeclarator()->Id()->AsIdentifier()->Variable();
3153af6ab5fSopenharmony_ci    }
3163af6ab5fSopenharmony_ci
3173af6ab5fSopenharmony_ci    checker::ScopeContext scopeCtx(checker, expr->Function()->Scope());
3183af6ab5fSopenharmony_ci
3193af6ab5fSopenharmony_ci    auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
3203af6ab5fSopenharmony_ci    checker->CheckFunctionParameterDeclarations(expr->Function()->Params(), signatureInfo);
3213af6ab5fSopenharmony_ci
3223af6ab5fSopenharmony_ci    auto *signature = checker->Allocator()->New<checker::Signature>(signatureInfo, checker->GlobalResolvingReturnType(),
3233af6ab5fSopenharmony_ci                                                                    expr->Function());
3243af6ab5fSopenharmony_ci    checker::Type *funcType = checker->CreateFunctionTypeWithSignature(signature);
3253af6ab5fSopenharmony_ci
3263af6ab5fSopenharmony_ci    if (funcVar != nullptr && funcVar->TsType() == nullptr) {
3273af6ab5fSopenharmony_ci        funcVar->SetTsType(funcType);
3283af6ab5fSopenharmony_ci    }
3293af6ab5fSopenharmony_ci
3303af6ab5fSopenharmony_ci    signature->SetReturnType(checker->HandleFunctionReturn(expr->Function()));
3313af6ab5fSopenharmony_ci
3323af6ab5fSopenharmony_ci    if (!expr->Function()->Body()->IsExpression()) {
3333af6ab5fSopenharmony_ci        expr->Function()->Body()->Check(checker);
3343af6ab5fSopenharmony_ci    }
3353af6ab5fSopenharmony_ci
3363af6ab5fSopenharmony_ci    return funcType;
3373af6ab5fSopenharmony_ci}
3383af6ab5fSopenharmony_ci
3393af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::CheckAssignmentExprOperatorType(ir::AssignmentExpression *expr, checker::Type *leftType,
3403af6ab5fSopenharmony_ci                                                           checker::Type *rightType) const
3413af6ab5fSopenharmony_ci{
3423af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
3433af6ab5fSopenharmony_ci    ExpressionTypeInfo leftRightType {};
3443af6ab5fSopenharmony_ci    leftRightType.leftType = leftType;
3453af6ab5fSopenharmony_ci    leftRightType.rightType = rightType;
3463af6ab5fSopenharmony_ci    switch (expr->OperatorType()) {
3473af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL:
3483af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL:
3493af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL:
3503af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MOD_EQUAL:
3513af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL:
3523af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL:
3533af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL:
3543af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL:
3553af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL:
3563af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL:
3573af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: {
3583af6ab5fSopenharmony_ci            return checker->CheckBinaryOperator(&leftRightType, expr->Left(), expr->Right(), expr,
3593af6ab5fSopenharmony_ci                                                expr->OperatorType());
3603af6ab5fSopenharmony_ci        }
3613af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
3623af6ab5fSopenharmony_ci            return checker->CheckPlusOperator(&leftRightType, expr->Left(), expr->Right(), expr, expr->OperatorType());
3633af6ab5fSopenharmony_ci        }
3643af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
3653af6ab5fSopenharmony_ci            checker->CheckAssignmentOperator(expr->OperatorType(), expr->Left(), leftType, rightType);
3663af6ab5fSopenharmony_ci            return rightType;
3673af6ab5fSopenharmony_ci        }
3683af6ab5fSopenharmony_ci        default: {
3693af6ab5fSopenharmony_ci            UNREACHABLE();
3703af6ab5fSopenharmony_ci            break;
3713af6ab5fSopenharmony_ci        }
3723af6ab5fSopenharmony_ci    }
3733af6ab5fSopenharmony_ci
3743af6ab5fSopenharmony_ci    return nullptr;
3753af6ab5fSopenharmony_ci}
3763af6ab5fSopenharmony_ci
3773af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::AssignmentExpression *expr) const
3783af6ab5fSopenharmony_ci{
3793af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
3803af6ab5fSopenharmony_ci    if (expr->Left()->IsArrayPattern()) {
3813af6ab5fSopenharmony_ci        auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
3823af6ab5fSopenharmony_ci        auto destructuringContext =
3833af6ab5fSopenharmony_ci            checker::ArrayDestructuringContext({checker, expr->Left(), true, true, nullptr, expr->Right()});
3843af6ab5fSopenharmony_ci        destructuringContext.Start();
3853af6ab5fSopenharmony_ci        return destructuringContext.InferredType();
3863af6ab5fSopenharmony_ci    }
3873af6ab5fSopenharmony_ci
3883af6ab5fSopenharmony_ci    if (expr->Left()->IsObjectPattern()) {
3893af6ab5fSopenharmony_ci        auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
3903af6ab5fSopenharmony_ci        auto destructuringContext =
3913af6ab5fSopenharmony_ci            checker::ObjectDestructuringContext({checker, expr->Left(), true, true, nullptr, expr->Right()});
3923af6ab5fSopenharmony_ci        destructuringContext.Start();
3933af6ab5fSopenharmony_ci        return destructuringContext.InferredType();
3943af6ab5fSopenharmony_ci    }
3953af6ab5fSopenharmony_ci
3963af6ab5fSopenharmony_ci    if (expr->Left()->IsIdentifier() && expr->Left()->AsIdentifier()->Variable() != nullptr &&
3973af6ab5fSopenharmony_ci        expr->Left()->AsIdentifier()->Variable()->Declaration()->IsConstDecl()) {
3983af6ab5fSopenharmony_ci        checker->ThrowTypeError(
3993af6ab5fSopenharmony_ci            {"Cannot assign to ", expr->Left()->AsIdentifier()->Name(), " because it is a constant."},
4003af6ab5fSopenharmony_ci            expr->Left()->Start());
4013af6ab5fSopenharmony_ci    }
4023af6ab5fSopenharmony_ci
4033af6ab5fSopenharmony_ci    auto *leftType = expr->Left()->Check(checker);
4043af6ab5fSopenharmony_ci
4053af6ab5fSopenharmony_ci    if (leftType->HasTypeFlag(checker::TypeFlag::READONLY)) {
4063af6ab5fSopenharmony_ci        checker->ThrowTypeError("Cannot assign to this property because it is readonly.", expr->Left()->Start());
4073af6ab5fSopenharmony_ci    }
4083af6ab5fSopenharmony_ci
4093af6ab5fSopenharmony_ci    if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
4103af6ab5fSopenharmony_ci        checker->ElaborateElementwise(leftType, expr->Right(), expr->Left()->Start());
4113af6ab5fSopenharmony_ci        return checker->CheckTypeCached(expr->Right());
4123af6ab5fSopenharmony_ci    }
4133af6ab5fSopenharmony_ci
4143af6ab5fSopenharmony_ci    auto *rightType = expr->Right()->Check(checker);
4153af6ab5fSopenharmony_ci
4163af6ab5fSopenharmony_ci    return CheckAssignmentExprOperatorType(expr, leftType, rightType);
4173af6ab5fSopenharmony_ci}
4183af6ab5fSopenharmony_ci
4193af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::AwaitExpression *expr) const
4203af6ab5fSopenharmony_ci{
4213af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
4223af6ab5fSopenharmony_ci    // NOTE(aszilagyi)
4233af6ab5fSopenharmony_ci    return checker->GlobalAnyType();
4243af6ab5fSopenharmony_ci}
4253af6ab5fSopenharmony_ci
4263af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::CheckBinaryExprArithmLogical(ir::BinaryExpression *expr, ExpressionTypeInfo *leftRightType,
4273af6ab5fSopenharmony_ci                                                        TSChecker *checker) const
4283af6ab5fSopenharmony_ci{
4293af6ab5fSopenharmony_ci    switch (expr->OperatorType()) {
4303af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MULTIPLY:
4313af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_EXPONENTIATION:
4323af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_DIVIDE:
4333af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MOD:
4343af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MINUS:
4353af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
4363af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT:
4373af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT:
4383af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_AND:
4393af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_XOR:
4403af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_OR: {
4413af6ab5fSopenharmony_ci            return checker->CheckBinaryOperator(leftRightType, expr->Left(), expr->Right(), expr, expr->OperatorType());
4423af6ab5fSopenharmony_ci        }
4433af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_PLUS: {
4443af6ab5fSopenharmony_ci            return checker->CheckPlusOperator(leftRightType, expr->Left(), expr->Right(), expr, expr->OperatorType());
4453af6ab5fSopenharmony_ci        }
4463af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
4473af6ab5fSopenharmony_ci            return checker->CheckAndOperator(leftRightType->leftType, leftRightType->rightType, expr->Left());
4483af6ab5fSopenharmony_ci        }
4493af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
4503af6ab5fSopenharmony_ci            return checker->CheckOrOperator(leftRightType->leftType, leftRightType->rightType, expr->Left());
4513af6ab5fSopenharmony_ci        }
4523af6ab5fSopenharmony_ci        default: {
4533af6ab5fSopenharmony_ci            return nullptr;
4543af6ab5fSopenharmony_ci        }
4553af6ab5fSopenharmony_ci    }
4563af6ab5fSopenharmony_ci}
4573af6ab5fSopenharmony_ci
4583af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::BinaryExpression *expr) const
4593af6ab5fSopenharmony_ci{
4603af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
4613af6ab5fSopenharmony_ci    ExpressionTypeInfo leftRightType {};
4623af6ab5fSopenharmony_ci    leftRightType.leftType = expr->Left()->Check(checker);
4633af6ab5fSopenharmony_ci    leftRightType.rightType = expr->Right()->Check(checker);
4643af6ab5fSopenharmony_ci
4653af6ab5fSopenharmony_ci    auto *checkBinaryExprPunctuator = CheckBinaryExprArithmLogical(expr, &leftRightType, checker);
4663af6ab5fSopenharmony_ci    if (checkBinaryExprPunctuator != nullptr) {
4673af6ab5fSopenharmony_ci        return checkBinaryExprPunctuator;
4683af6ab5fSopenharmony_ci    }
4693af6ab5fSopenharmony_ci
4703af6ab5fSopenharmony_ci    switch (expr->OperatorType()) {
4713af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LESS_THAN:
4723af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_GREATER_THAN: {
4733af6ab5fSopenharmony_ci            return checker->CheckCompareOperator(&leftRightType, expr->Left(), expr->Right(), expr,
4743af6ab5fSopenharmony_ci                                                 expr->OperatorType());
4753af6ab5fSopenharmony_ci        }
4763af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_EQUAL:
4773af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_NOT_EQUAL:
4783af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
4793af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: {
4803af6ab5fSopenharmony_ci            if (checker->IsTypeEqualityComparableTo(leftRightType.leftType, leftRightType.rightType) ||
4813af6ab5fSopenharmony_ci                checker->IsTypeEqualityComparableTo(leftRightType.rightType, leftRightType.leftType)) {
4823af6ab5fSopenharmony_ci                return checker->GlobalBooleanType();
4833af6ab5fSopenharmony_ci            }
4843af6ab5fSopenharmony_ci
4853af6ab5fSopenharmony_ci            checker->ThrowBinaryLikeError(expr->OperatorType(), leftRightType.leftType, leftRightType.rightType,
4863af6ab5fSopenharmony_ci                                          expr->Start());
4873af6ab5fSopenharmony_ci        }
4883af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: {
4893af6ab5fSopenharmony_ci            // NOTE: Csaba Repasi. Implement checker for nullish coalescing
4903af6ab5fSopenharmony_ci            return checker->GlobalAnyType();
4913af6ab5fSopenharmony_ci        }
4923af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
4933af6ab5fSopenharmony_ci            checker->CheckAssignmentOperator(expr->OperatorType(), expr->Left(), leftRightType.leftType,
4943af6ab5fSopenharmony_ci                                             leftRightType.rightType);
4953af6ab5fSopenharmony_ci            return leftRightType.rightType;
4963af6ab5fSopenharmony_ci        }
4973af6ab5fSopenharmony_ci        case lexer::TokenType::KEYW_INSTANCEOF: {
4983af6ab5fSopenharmony_ci            return checker->CheckInstanceofExpression(leftRightType.leftType, leftRightType.rightType, expr->Right(),
4993af6ab5fSopenharmony_ci                                                      expr);
5003af6ab5fSopenharmony_ci        }
5013af6ab5fSopenharmony_ci        case lexer::TokenType::KEYW_IN: {
5023af6ab5fSopenharmony_ci            return checker->CheckInExpression(leftRightType.leftType, leftRightType.rightType, expr->Left(),
5033af6ab5fSopenharmony_ci                                              expr->Right(), expr);
5043af6ab5fSopenharmony_ci        }
5053af6ab5fSopenharmony_ci        default: {
5063af6ab5fSopenharmony_ci            UNREACHABLE();
5073af6ab5fSopenharmony_ci            break;
5083af6ab5fSopenharmony_ci        }
5093af6ab5fSopenharmony_ci    }
5103af6ab5fSopenharmony_ci
5113af6ab5fSopenharmony_ci    return nullptr;
5123af6ab5fSopenharmony_ci}
5133af6ab5fSopenharmony_ci
5143af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::CallExpression *expr) const
5153af6ab5fSopenharmony_ci{
5163af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
5173af6ab5fSopenharmony_ci    checker::Type *calleeType = expr->callee_->Check(checker);
5183af6ab5fSopenharmony_ci
5193af6ab5fSopenharmony_ci    // NOTE: aszilagyi. handle optional chain
5203af6ab5fSopenharmony_ci    if (calleeType->IsObjectType()) {
5213af6ab5fSopenharmony_ci        checker::ObjectType *calleeObj = calleeType->AsObjectType();
5223af6ab5fSopenharmony_ci        return checker->ResolveCallOrNewExpression(calleeObj->CallSignatures(), expr->Arguments(), expr->Start());
5233af6ab5fSopenharmony_ci    }
5243af6ab5fSopenharmony_ci
5253af6ab5fSopenharmony_ci    checker->ThrowTypeError("This expression is not callable.", expr->Start());
5263af6ab5fSopenharmony_ci    return nullptr;
5273af6ab5fSopenharmony_ci}
5283af6ab5fSopenharmony_ci
5293af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::ChainExpression *expr) const
5303af6ab5fSopenharmony_ci{
5313af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
5323af6ab5fSopenharmony_ci    return expr->expression_->Check(checker);
5333af6ab5fSopenharmony_ci}
5343af6ab5fSopenharmony_ci
5353af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::ConditionalExpression *expr) const
5363af6ab5fSopenharmony_ci{
5373af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
5383af6ab5fSopenharmony_ci    checker::Type *testType = expr->Test()->Check(checker);
5393af6ab5fSopenharmony_ci
5403af6ab5fSopenharmony_ci    checker->CheckTruthinessOfType(testType, expr->Test()->Start());
5413af6ab5fSopenharmony_ci    checker->CheckTestingKnownTruthyCallableOrAwaitableType(expr->Test(), testType, expr->Consequent());
5423af6ab5fSopenharmony_ci
5433af6ab5fSopenharmony_ci    checker::Type *consequentType = expr->Consequent()->Check(checker);
5443af6ab5fSopenharmony_ci    checker::Type *alternateType = expr->Alternate()->Check(checker);
5453af6ab5fSopenharmony_ci
5463af6ab5fSopenharmony_ci    return checker->CreateUnionType({consequentType, alternateType});
5473af6ab5fSopenharmony_ci}
5483af6ab5fSopenharmony_ci
5493af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::FunctionExpression *expr) const
5503af6ab5fSopenharmony_ci{
5513af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
5523af6ab5fSopenharmony_ci    varbinder::Variable *funcVar = nullptr;
5533af6ab5fSopenharmony_ci
5543af6ab5fSopenharmony_ci    if (expr->Function()->Parent()->Parent() != nullptr &&
5553af6ab5fSopenharmony_ci        expr->Function()->Parent()->Parent()->IsVariableDeclarator() &&
5563af6ab5fSopenharmony_ci        expr->Function()->Parent()->Parent()->AsVariableDeclarator()->Id()->IsIdentifier()) {
5573af6ab5fSopenharmony_ci        funcVar = expr->Function()->Parent()->Parent()->AsVariableDeclarator()->Id()->AsIdentifier()->Variable();
5583af6ab5fSopenharmony_ci    }
5593af6ab5fSopenharmony_ci
5603af6ab5fSopenharmony_ci    checker::ScopeContext scopeCtx(checker, expr->Function()->Scope());
5613af6ab5fSopenharmony_ci
5623af6ab5fSopenharmony_ci    auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
5633af6ab5fSopenharmony_ci    checker->CheckFunctionParameterDeclarations(expr->Function()->Params(), signatureInfo);
5643af6ab5fSopenharmony_ci
5653af6ab5fSopenharmony_ci    auto *signature = checker->Allocator()->New<checker::Signature>(signatureInfo, checker->GlobalResolvingReturnType(),
5663af6ab5fSopenharmony_ci                                                                    expr->Function());
5673af6ab5fSopenharmony_ci    checker::Type *funcType = checker->CreateFunctionTypeWithSignature(signature);
5683af6ab5fSopenharmony_ci
5693af6ab5fSopenharmony_ci    if (funcVar != nullptr && funcVar->TsType() == nullptr) {
5703af6ab5fSopenharmony_ci        funcVar->SetTsType(funcType);
5713af6ab5fSopenharmony_ci    }
5723af6ab5fSopenharmony_ci
5733af6ab5fSopenharmony_ci    signature->SetReturnType(checker->HandleFunctionReturn(expr->Function()));
5743af6ab5fSopenharmony_ci
5753af6ab5fSopenharmony_ci    expr->Function()->Body()->Check(checker);
5763af6ab5fSopenharmony_ci
5773af6ab5fSopenharmony_ci    return funcType;
5783af6ab5fSopenharmony_ci}
5793af6ab5fSopenharmony_ci
5803af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::Identifier *expr) const
5813af6ab5fSopenharmony_ci{
5823af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
5833af6ab5fSopenharmony_ci    if (expr->Variable() == nullptr) {
5843af6ab5fSopenharmony_ci        if (expr->Name().Is("undefined")) {
5853af6ab5fSopenharmony_ci            return checker->GlobalUndefinedType();
5863af6ab5fSopenharmony_ci        }
5873af6ab5fSopenharmony_ci
5883af6ab5fSopenharmony_ci        checker->ThrowTypeError({"Cannot find name ", expr->Name()}, expr->Start());
5893af6ab5fSopenharmony_ci    }
5903af6ab5fSopenharmony_ci
5913af6ab5fSopenharmony_ci    const varbinder::Decl *decl = expr->Variable()->Declaration();
5923af6ab5fSopenharmony_ci
5933af6ab5fSopenharmony_ci    if (decl->IsTypeAliasDecl() || decl->IsInterfaceDecl()) {
5943af6ab5fSopenharmony_ci        checker->ThrowTypeError({expr->Name(), " only refers to a type, but is being used as a value here."},
5953af6ab5fSopenharmony_ci                                expr->Start());
5963af6ab5fSopenharmony_ci    }
5973af6ab5fSopenharmony_ci
5983af6ab5fSopenharmony_ci    expr->SetTsType(checker->GetTypeOfVariable(expr->Variable()));
5993af6ab5fSopenharmony_ci    return expr->TsType();
6003af6ab5fSopenharmony_ci}
6013af6ab5fSopenharmony_ci
6023af6ab5fSopenharmony_civoid TSAnalyzer::CheckComputed(ir::MemberExpression *expr, checker::Type *indexType) const
6033af6ab5fSopenharmony_ci{
6043af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
6053af6ab5fSopenharmony_ci    if (!indexType->HasTypeFlag(checker::TypeFlag::STRING_LIKE | checker::TypeFlag::NUMBER_LIKE)) {
6063af6ab5fSopenharmony_ci        checker->ThrowTypeError({"Type ", indexType, " cannot be used as index type"}, expr->Property()->Start());
6073af6ab5fSopenharmony_ci    }
6083af6ab5fSopenharmony_ci
6093af6ab5fSopenharmony_ci    if (indexType->IsNumberType()) {
6103af6ab5fSopenharmony_ci        checker->ThrowTypeError("No index signature with a parameter of type 'string' was found on type this type",
6113af6ab5fSopenharmony_ci                                expr->Start());
6123af6ab5fSopenharmony_ci    }
6133af6ab5fSopenharmony_ci
6143af6ab5fSopenharmony_ci    if (indexType->IsStringType()) {
6153af6ab5fSopenharmony_ci        checker->ThrowTypeError("No index signature with a parameter of type 'number' was found on type this type",
6163af6ab5fSopenharmony_ci                                expr->Start());
6173af6ab5fSopenharmony_ci    }
6183af6ab5fSopenharmony_ci
6193af6ab5fSopenharmony_ci    switch (expr->Property()->Type()) {
6203af6ab5fSopenharmony_ci        case ir::AstNodeType::IDENTIFIER: {
6213af6ab5fSopenharmony_ci            checker->ThrowTypeError(
6223af6ab5fSopenharmony_ci                {"Property ", expr->Property()->AsIdentifier()->Name(), " does not exist on this type."},
6233af6ab5fSopenharmony_ci                expr->Property()->Start());
6243af6ab5fSopenharmony_ci        }
6253af6ab5fSopenharmony_ci        case ir::AstNodeType::NUMBER_LITERAL: {
6263af6ab5fSopenharmony_ci            checker->ThrowTypeError(
6273af6ab5fSopenharmony_ci                {"Property ", expr->Property()->AsNumberLiteral()->Str(), " does not exist on this type."},
6283af6ab5fSopenharmony_ci                expr->Property()->Start());
6293af6ab5fSopenharmony_ci        }
6303af6ab5fSopenharmony_ci        case ir::AstNodeType::STRING_LITERAL: {
6313af6ab5fSopenharmony_ci            checker->ThrowTypeError(
6323af6ab5fSopenharmony_ci                {"Property ", expr->Property()->AsStringLiteral()->Str(), " does not exist on this type."},
6333af6ab5fSopenharmony_ci                expr->Property()->Start());
6343af6ab5fSopenharmony_ci        }
6353af6ab5fSopenharmony_ci        default: {
6363af6ab5fSopenharmony_ci            UNREACHABLE();
6373af6ab5fSopenharmony_ci        }
6383af6ab5fSopenharmony_ci    }
6393af6ab5fSopenharmony_ci}
6403af6ab5fSopenharmony_ci
6413af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::MemberExpression *expr) const
6423af6ab5fSopenharmony_ci{
6433af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
6443af6ab5fSopenharmony_ci    checker::Type *baseType = checker->CheckNonNullType(expr->Object()->Check(checker), expr->Object()->Start());
6453af6ab5fSopenharmony_ci
6463af6ab5fSopenharmony_ci    if (expr->IsComputed()) {
6473af6ab5fSopenharmony_ci        checker::Type *indexType = expr->Property()->Check(checker);
6483af6ab5fSopenharmony_ci        checker::Type *indexedAccessType = checker->GetPropertyTypeForIndexType(baseType, indexType);
6493af6ab5fSopenharmony_ci
6503af6ab5fSopenharmony_ci        if (indexedAccessType != nullptr) {
6513af6ab5fSopenharmony_ci            return indexedAccessType;
6523af6ab5fSopenharmony_ci        }
6533af6ab5fSopenharmony_ci        CheckComputed(expr, indexType);
6543af6ab5fSopenharmony_ci    }
6553af6ab5fSopenharmony_ci
6563af6ab5fSopenharmony_ci    varbinder::Variable *prop = checker->GetPropertyOfType(baseType, expr->Property()->AsIdentifier()->Name());
6573af6ab5fSopenharmony_ci
6583af6ab5fSopenharmony_ci    if (prop != nullptr) {
6593af6ab5fSopenharmony_ci        checker::Type *propType = checker->GetTypeOfVariable(prop);
6603af6ab5fSopenharmony_ci        if (prop->HasFlag(varbinder::VariableFlags::READONLY)) {
6613af6ab5fSopenharmony_ci            propType->AddTypeFlag(checker::TypeFlag::READONLY);
6623af6ab5fSopenharmony_ci        }
6633af6ab5fSopenharmony_ci
6643af6ab5fSopenharmony_ci        return propType;
6653af6ab5fSopenharmony_ci    }
6663af6ab5fSopenharmony_ci
6673af6ab5fSopenharmony_ci    if (baseType->IsObjectType()) {
6683af6ab5fSopenharmony_ci        checker::ObjectType *objType = baseType->AsObjectType();
6693af6ab5fSopenharmony_ci
6703af6ab5fSopenharmony_ci        if (objType->StringIndexInfo() != nullptr) {
6713af6ab5fSopenharmony_ci            checker::Type *indexType = objType->StringIndexInfo()->GetType();
6723af6ab5fSopenharmony_ci            if (objType->StringIndexInfo()->Readonly()) {
6733af6ab5fSopenharmony_ci                indexType->AddTypeFlag(checker::TypeFlag::READONLY);
6743af6ab5fSopenharmony_ci            }
6753af6ab5fSopenharmony_ci
6763af6ab5fSopenharmony_ci            return indexType;
6773af6ab5fSopenharmony_ci        }
6783af6ab5fSopenharmony_ci    }
6793af6ab5fSopenharmony_ci
6803af6ab5fSopenharmony_ci    checker->ThrowTypeError({"Property ", expr->Property()->AsIdentifier()->Name(), " does not exist on this type."},
6813af6ab5fSopenharmony_ci                            expr->Property()->Start());
6823af6ab5fSopenharmony_ci    return nullptr;
6833af6ab5fSopenharmony_ci}
6843af6ab5fSopenharmony_ci
6853af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::NewExpression *expr) const
6863af6ab5fSopenharmony_ci{
6873af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
6883af6ab5fSopenharmony_ci    checker::Type *calleeType = expr->callee_->Check(checker);
6893af6ab5fSopenharmony_ci
6903af6ab5fSopenharmony_ci    if (calleeType->IsObjectType()) {
6913af6ab5fSopenharmony_ci        checker::ObjectType *calleeObj = calleeType->AsObjectType();
6923af6ab5fSopenharmony_ci        return checker->ResolveCallOrNewExpression(calleeObj->ConstructSignatures(), expr->Arguments(), expr->Start());
6933af6ab5fSopenharmony_ci    }
6943af6ab5fSopenharmony_ci
6953af6ab5fSopenharmony_ci    checker->ThrowTypeError("This expression is not callable.", expr->Start());
6963af6ab5fSopenharmony_ci    return nullptr;
6973af6ab5fSopenharmony_ci}
6983af6ab5fSopenharmony_cistatic const util::StringView &GetPropertyName(const ir::Expression *key)
6993af6ab5fSopenharmony_ci{
7003af6ab5fSopenharmony_ci    if (key->IsIdentifier()) {
7013af6ab5fSopenharmony_ci        return key->AsIdentifier()->Name();
7023af6ab5fSopenharmony_ci    }
7033af6ab5fSopenharmony_ci
7043af6ab5fSopenharmony_ci    if (key->IsStringLiteral()) {
7053af6ab5fSopenharmony_ci        return key->AsStringLiteral()->Str();
7063af6ab5fSopenharmony_ci    }
7073af6ab5fSopenharmony_ci
7083af6ab5fSopenharmony_ci    ASSERT(key->IsNumberLiteral());
7093af6ab5fSopenharmony_ci    return key->AsNumberLiteral()->Str();
7103af6ab5fSopenharmony_ci}
7113af6ab5fSopenharmony_ci
7123af6ab5fSopenharmony_cistatic varbinder::VariableFlags GetFlagsForProperty(const ir::Property *prop)
7133af6ab5fSopenharmony_ci{
7143af6ab5fSopenharmony_ci    if (!prop->IsMethod()) {
7153af6ab5fSopenharmony_ci        return varbinder::VariableFlags::PROPERTY;
7163af6ab5fSopenharmony_ci    }
7173af6ab5fSopenharmony_ci
7183af6ab5fSopenharmony_ci    varbinder::VariableFlags propFlags = varbinder::VariableFlags::METHOD;
7193af6ab5fSopenharmony_ci
7203af6ab5fSopenharmony_ci    if (prop->IsAccessor() && prop->Kind() == ir::PropertyKind::GET) {
7213af6ab5fSopenharmony_ci        propFlags |= varbinder::VariableFlags::READONLY;
7223af6ab5fSopenharmony_ci    }
7233af6ab5fSopenharmony_ci
7243af6ab5fSopenharmony_ci    return propFlags;
7253af6ab5fSopenharmony_ci}
7263af6ab5fSopenharmony_ci
7273af6ab5fSopenharmony_cistatic checker::Type *GetTypeForProperty(ir::Property *prop, checker::TSChecker *checker)
7283af6ab5fSopenharmony_ci{
7293af6ab5fSopenharmony_ci    if (prop->IsAccessor()) {
7303af6ab5fSopenharmony_ci        checker::Type *funcType = prop->Value()->Check(checker);
7313af6ab5fSopenharmony_ci
7323af6ab5fSopenharmony_ci        if (prop->Kind() == ir::PropertyKind::SET) {
7333af6ab5fSopenharmony_ci            return checker->GlobalAnyType();
7343af6ab5fSopenharmony_ci        }
7353af6ab5fSopenharmony_ci
7363af6ab5fSopenharmony_ci        ASSERT(funcType->IsObjectType() && funcType->AsObjectType()->IsFunctionType());
7373af6ab5fSopenharmony_ci        return funcType->AsObjectType()->CallSignatures()[0]->ReturnType();
7383af6ab5fSopenharmony_ci    }
7393af6ab5fSopenharmony_ci
7403af6ab5fSopenharmony_ci    if (prop->IsShorthand()) {
7413af6ab5fSopenharmony_ci        return prop->Key()->Check(checker);
7423af6ab5fSopenharmony_ci    }
7433af6ab5fSopenharmony_ci
7443af6ab5fSopenharmony_ci    return prop->Value()->Check(checker);
7453af6ab5fSopenharmony_ci}
7463af6ab5fSopenharmony_ci
7473af6ab5fSopenharmony_civoid TSAnalyzer::CheckSpread(std::unordered_map<util::StringView, lexer::SourcePosition> &allPropertiesMap,
7483af6ab5fSopenharmony_ci                             checker::ObjectDescriptor *desc, ir::Expression *it) const
7493af6ab5fSopenharmony_ci{
7503af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
7513af6ab5fSopenharmony_ci    ASSERT(it->IsSpreadElement());
7523af6ab5fSopenharmony_ci
7533af6ab5fSopenharmony_ci    checker::Type *const spreadType = it->AsSpreadElement()->Argument()->Check(checker);
7543af6ab5fSopenharmony_ci
7553af6ab5fSopenharmony_ci    // NOTE: aszilagyi. handle union of object types
7563af6ab5fSopenharmony_ci    if (!spreadType->IsObjectType()) {
7573af6ab5fSopenharmony_ci        checker->ThrowTypeError("Spread types may only be created from object types.", it->Start());
7583af6ab5fSopenharmony_ci    }
7593af6ab5fSopenharmony_ci
7603af6ab5fSopenharmony_ci    for (auto *spreadProp : spreadType->AsObjectType()->Properties()) {
7613af6ab5fSopenharmony_ci        auto found = allPropertiesMap.find(spreadProp->Name());
7623af6ab5fSopenharmony_ci        if (found != allPropertiesMap.end()) {
7633af6ab5fSopenharmony_ci            checker->ThrowTypeError({found->first, " is specified more than once, so this usage will be overwritten."},
7643af6ab5fSopenharmony_ci                                    found->second);
7653af6ab5fSopenharmony_ci        }
7663af6ab5fSopenharmony_ci
7673af6ab5fSopenharmony_ci        varbinder::LocalVariable *foundMember = desc->FindProperty(spreadProp->Name());
7683af6ab5fSopenharmony_ci
7693af6ab5fSopenharmony_ci        if (foundMember != nullptr) {
7703af6ab5fSopenharmony_ci            foundMember->SetTsType(spreadProp->TsType());
7713af6ab5fSopenharmony_ci            continue;
7723af6ab5fSopenharmony_ci        }
7733af6ab5fSopenharmony_ci
7743af6ab5fSopenharmony_ci        desc->properties.push_back(spreadProp);
7753af6ab5fSopenharmony_ci    }
7763af6ab5fSopenharmony_ci}
7773af6ab5fSopenharmony_ci
7783af6ab5fSopenharmony_civoid TSAnalyzer::CheckNonComputed(checker::ObjectDescriptor *desc, ir::Expression *it,
7793af6ab5fSopenharmony_ci                                  std::unordered_map<util::StringView, lexer::SourcePosition> &allPropertiesMap,
7803af6ab5fSopenharmony_ci                                  bool inConstContext) const
7813af6ab5fSopenharmony_ci{
7823af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
7833af6ab5fSopenharmony_ci    auto *prop = it->AsProperty();
7843af6ab5fSopenharmony_ci    checker::Type *propType = GetTypeForProperty(prop, checker);
7853af6ab5fSopenharmony_ci    varbinder::VariableFlags flags = GetFlagsForProperty(prop);
7863af6ab5fSopenharmony_ci    const util::StringView &propName = GetPropertyName(prop->Key());
7873af6ab5fSopenharmony_ci
7883af6ab5fSopenharmony_ci    auto *memberVar = varbinder::Scope::CreateVar(checker->Allocator(), propName, flags, it);
7893af6ab5fSopenharmony_ci
7903af6ab5fSopenharmony_ci    if (inConstContext) {
7913af6ab5fSopenharmony_ci        memberVar->AddFlag(varbinder::VariableFlags::READONLY);
7923af6ab5fSopenharmony_ci    } else {
7933af6ab5fSopenharmony_ci        propType = checker->GetBaseTypeOfLiteralType(propType);
7943af6ab5fSopenharmony_ci    }
7953af6ab5fSopenharmony_ci
7963af6ab5fSopenharmony_ci    memberVar->SetTsType(propType);
7973af6ab5fSopenharmony_ci
7983af6ab5fSopenharmony_ci    if (prop->Key()->IsNumberLiteral()) {
7993af6ab5fSopenharmony_ci        memberVar->AddFlag(varbinder::VariableFlags::NUMERIC_NAME);
8003af6ab5fSopenharmony_ci    }
8013af6ab5fSopenharmony_ci
8023af6ab5fSopenharmony_ci    varbinder::LocalVariable *foundMember = desc->FindProperty(propName);
8033af6ab5fSopenharmony_ci    allPropertiesMap.insert({propName, it->Start()});
8043af6ab5fSopenharmony_ci
8053af6ab5fSopenharmony_ci    if (foundMember != nullptr) {
8063af6ab5fSopenharmony_ci        foundMember->SetTsType(propType);
8073af6ab5fSopenharmony_ci        return;
8083af6ab5fSopenharmony_ci    }
8093af6ab5fSopenharmony_ci
8103af6ab5fSopenharmony_ci    desc->properties.push_back(memberVar);
8113af6ab5fSopenharmony_ci}
8123af6ab5fSopenharmony_ci
8133af6ab5fSopenharmony_cichecker::IndexInfo *TSAnalyzer::CreateUnionTypeHelper(ArenaVector<checker::Type *> &computedPropTypes,
8143af6ab5fSopenharmony_ci                                                      bool inConstContext) const
8153af6ab5fSopenharmony_ci{
8163af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
8173af6ab5fSopenharmony_ci
8183af6ab5fSopenharmony_ci    return checker->Allocator()->New<checker::IndexInfo>(checker->CreateUnionType(std::move(computedPropTypes)), "x",
8193af6ab5fSopenharmony_ci                                                         inConstContext);
8203af6ab5fSopenharmony_ci}
8213af6ab5fSopenharmony_ci
8223af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::ObjectExpression *expr) const
8233af6ab5fSopenharmony_ci{
8243af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
8253af6ab5fSopenharmony_ci
8263af6ab5fSopenharmony_ci    checker::ObjectDescriptor *desc = checker->Allocator()->New<checker::ObjectDescriptor>(checker->Allocator());
8273af6ab5fSopenharmony_ci    std::unordered_map<util::StringView, lexer::SourcePosition> allPropertiesMap;
8283af6ab5fSopenharmony_ci    bool inConstContext = checker->HasStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
8293af6ab5fSopenharmony_ci    ArenaVector<checker::Type *> computedNumberPropTypes(checker->Allocator()->Adapter());
8303af6ab5fSopenharmony_ci    ArenaVector<checker::Type *> computedStringPropTypes(checker->Allocator()->Adapter());
8313af6ab5fSopenharmony_ci    bool hasComputedNumberProperty = false;
8323af6ab5fSopenharmony_ci    bool hasComputedStringProperty = false;
8333af6ab5fSopenharmony_ci    bool seenSpread = false;
8343af6ab5fSopenharmony_ci
8353af6ab5fSopenharmony_ci    for (auto *it : expr->Properties()) {
8363af6ab5fSopenharmony_ci        if (it->IsProperty()) {
8373af6ab5fSopenharmony_ci            auto *prop = it->AsProperty();
8383af6ab5fSopenharmony_ci
8393af6ab5fSopenharmony_ci            if (prop->IsComputed() && checker->CheckComputedPropertyName(prop->Key())->IsNumberType()) {
8403af6ab5fSopenharmony_ci                hasComputedNumberProperty = true;
8413af6ab5fSopenharmony_ci                computedNumberPropTypes.push_back(prop->Value()->Check(checker));
8423af6ab5fSopenharmony_ci                continue;
8433af6ab5fSopenharmony_ci            }
8443af6ab5fSopenharmony_ci
8453af6ab5fSopenharmony_ci            if (prop->IsComputed() && checker->CheckComputedPropertyName(prop->Key())->IsStringType()) {
8463af6ab5fSopenharmony_ci                hasComputedStringProperty = true;
8473af6ab5fSopenharmony_ci                computedStringPropTypes.push_back(prop->Value()->Check(checker));
8483af6ab5fSopenharmony_ci                continue;
8493af6ab5fSopenharmony_ci            }
8503af6ab5fSopenharmony_ci
8513af6ab5fSopenharmony_ci            CheckNonComputed(desc, it, allPropertiesMap, inConstContext);
8523af6ab5fSopenharmony_ci        }
8533af6ab5fSopenharmony_ci
8543af6ab5fSopenharmony_ci        if (it->IsSpreadElement()) {
8553af6ab5fSopenharmony_ci            CheckSpread(allPropertiesMap, desc, it);
8563af6ab5fSopenharmony_ci            seenSpread = true;
8573af6ab5fSopenharmony_ci        }
8583af6ab5fSopenharmony_ci    }
8593af6ab5fSopenharmony_ci
8603af6ab5fSopenharmony_ci    if (!seenSpread && (hasComputedNumberProperty || hasComputedStringProperty)) {
8613af6ab5fSopenharmony_ci        for (auto *it : desc->properties) {
8623af6ab5fSopenharmony_ci            computedStringPropTypes.push_back(it->TsType());
8633af6ab5fSopenharmony_ci
8643af6ab5fSopenharmony_ci            if (hasComputedNumberProperty && it->HasFlag(varbinder::VariableFlags::NUMERIC_NAME)) {
8653af6ab5fSopenharmony_ci                computedNumberPropTypes.push_back(it->TsType());
8663af6ab5fSopenharmony_ci            }
8673af6ab5fSopenharmony_ci        }
8683af6ab5fSopenharmony_ci
8693af6ab5fSopenharmony_ci        if (hasComputedNumberProperty) {
8703af6ab5fSopenharmony_ci            desc->numberIndexInfo = CreateUnionTypeHelper(computedNumberPropTypes, inConstContext);
8713af6ab5fSopenharmony_ci        }
8723af6ab5fSopenharmony_ci
8733af6ab5fSopenharmony_ci        if (hasComputedStringProperty) {
8743af6ab5fSopenharmony_ci            desc->stringIndexInfo = CreateUnionTypeHelper(computedStringPropTypes, inConstContext);
8753af6ab5fSopenharmony_ci        }
8763af6ab5fSopenharmony_ci    }
8773af6ab5fSopenharmony_ci
8783af6ab5fSopenharmony_ci    checker::Type *returnType = checker->Allocator()->New<checker::ObjectLiteralType>(desc);
8793af6ab5fSopenharmony_ci    returnType->AsObjectType()->AddObjectFlag(checker::ObjectFlags::RESOLVED_MEMBERS |
8803af6ab5fSopenharmony_ci                                              checker::ObjectFlags::CHECK_EXCESS_PROPS);
8813af6ab5fSopenharmony_ci    return returnType;
8823af6ab5fSopenharmony_ci}
8833af6ab5fSopenharmony_ci
8843af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::OmittedExpression *expr) const
8853af6ab5fSopenharmony_ci{
8863af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
8873af6ab5fSopenharmony_ci    return checker->GlobalUndefinedType();
8883af6ab5fSopenharmony_ci}
8893af6ab5fSopenharmony_ci
8903af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::OpaqueTypeNode *expr) const
8913af6ab5fSopenharmony_ci{
8923af6ab5fSopenharmony_ci    return expr->TsType();
8933af6ab5fSopenharmony_ci}
8943af6ab5fSopenharmony_ci
8953af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::SequenceExpression *expr) const
8963af6ab5fSopenharmony_ci{
8973af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
8983af6ab5fSopenharmony_ci    // NOTE: aszilagyi.
8993af6ab5fSopenharmony_ci    return checker->GlobalAnyType();
9003af6ab5fSopenharmony_ci}
9013af6ab5fSopenharmony_ci
9023af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::SuperExpression *expr) const
9033af6ab5fSopenharmony_ci{
9043af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
9053af6ab5fSopenharmony_ci    // NOTE: aszilagyi.
9063af6ab5fSopenharmony_ci    return checker->GlobalAnyType();
9073af6ab5fSopenharmony_ci}
9083af6ab5fSopenharmony_ci
9093af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TaggedTemplateExpression *expr) const
9103af6ab5fSopenharmony_ci{
9113af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
9123af6ab5fSopenharmony_ci    // NOTE: aszilagyi.
9133af6ab5fSopenharmony_ci    return checker->GlobalAnyType();
9143af6ab5fSopenharmony_ci}
9153af6ab5fSopenharmony_ci
9163af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TemplateLiteral *expr) const
9173af6ab5fSopenharmony_ci{
9183af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
9193af6ab5fSopenharmony_ci    // NOTE(aszilagyi)
9203af6ab5fSopenharmony_ci    return checker->GlobalAnyType();
9213af6ab5fSopenharmony_ci}
9223af6ab5fSopenharmony_ci
9233af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ThisExpression *expr) const
9243af6ab5fSopenharmony_ci{
9253af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
9263af6ab5fSopenharmony_ci    // NOTE: aszilagyi
9273af6ab5fSopenharmony_ci    return checker->GlobalAnyType();
9283af6ab5fSopenharmony_ci}
9293af6ab5fSopenharmony_ci
9303af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TypeofExpression *expr) const
9313af6ab5fSopenharmony_ci{
9323af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
9333af6ab5fSopenharmony_ci    return checker->GlobalStringType();
9343af6ab5fSopenharmony_ci}
9353af6ab5fSopenharmony_ci
9363af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::CheckDeleteKeyword([[maybe_unused]] checker::TSChecker *checker,
9373af6ab5fSopenharmony_ci                                              ir::UnaryExpression *expr) const
9383af6ab5fSopenharmony_ci{
9393af6ab5fSopenharmony_ci    checker::Type *propType = expr->argument_->Check(checker);
9403af6ab5fSopenharmony_ci    if (!expr->Argument()->IsMemberExpression()) {
9413af6ab5fSopenharmony_ci        checker->ThrowTypeError("The operand of a delete operator must be a property reference.",
9423af6ab5fSopenharmony_ci                                expr->Argument()->Start());
9433af6ab5fSopenharmony_ci    }
9443af6ab5fSopenharmony_ci    if (propType->Variable()->HasFlag(varbinder::VariableFlags::READONLY)) {
9453af6ab5fSopenharmony_ci        checker->ThrowTypeError("The operand of a delete operator cannot be a readonly property.",
9463af6ab5fSopenharmony_ci                                expr->Argument()->Start());
9473af6ab5fSopenharmony_ci    }
9483af6ab5fSopenharmony_ci    if (!propType->Variable()->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
9493af6ab5fSopenharmony_ci        checker->ThrowTypeError("The operand of a delete operator must be a optional.", expr->Argument()->Start());
9503af6ab5fSopenharmony_ci    }
9513af6ab5fSopenharmony_ci    return checker->GlobalBooleanType();
9523af6ab5fSopenharmony_ci}
9533af6ab5fSopenharmony_ci
9543af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::CheckLiteral([[maybe_unused]] checker::TSChecker *checker, ir::UnaryExpression *expr) const
9553af6ab5fSopenharmony_ci{
9563af6ab5fSopenharmony_ci    if (!expr->Argument()->IsLiteral()) {
9573af6ab5fSopenharmony_ci        return nullptr;
9583af6ab5fSopenharmony_ci    }
9593af6ab5fSopenharmony_ci
9603af6ab5fSopenharmony_ci    const ir::Literal *lit = expr->Argument()->AsLiteral();
9613af6ab5fSopenharmony_ci    if (lit->IsNumberLiteral()) {
9623af6ab5fSopenharmony_ci        auto numberValue = lit->AsNumberLiteral()->Number().GetDouble();
9633af6ab5fSopenharmony_ci        if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS) {
9643af6ab5fSopenharmony_ci            return checker->CreateNumberLiteralType(numberValue);
9653af6ab5fSopenharmony_ci        }
9663af6ab5fSopenharmony_ci        if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_MINUS) {
9673af6ab5fSopenharmony_ci            return checker->CreateNumberLiteralType(-numberValue);
9683af6ab5fSopenharmony_ci        }
9693af6ab5fSopenharmony_ci    } else if (lit->IsBigIntLiteral() && expr->OperatorType() == lexer::TokenType::PUNCTUATOR_MINUS) {
9703af6ab5fSopenharmony_ci        return checker->CreateBigintLiteralType(lit->AsBigIntLiteral()->Str(), true);
9713af6ab5fSopenharmony_ci    }
9723af6ab5fSopenharmony_ci
9733af6ab5fSopenharmony_ci    return nullptr;
9743af6ab5fSopenharmony_ci}
9753af6ab5fSopenharmony_ci
9763af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::UnaryExpression *expr) const
9773af6ab5fSopenharmony_ci{
9783af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
9793af6ab5fSopenharmony_ci    checker::Type *operandType = expr->argument_->Check(checker);
9803af6ab5fSopenharmony_ci
9813af6ab5fSopenharmony_ci    if (expr->operator_ == lexer::TokenType::KEYW_TYPEOF) {
9823af6ab5fSopenharmony_ci        return operandType;
9833af6ab5fSopenharmony_ci    }
9843af6ab5fSopenharmony_ci
9853af6ab5fSopenharmony_ci    if (expr->operator_ == lexer::TokenType::KEYW_DELETE) {
9863af6ab5fSopenharmony_ci        return CheckDeleteKeyword(checker, expr);
9873af6ab5fSopenharmony_ci    }
9883af6ab5fSopenharmony_ci
9893af6ab5fSopenharmony_ci    auto *res = CheckLiteral(checker, expr);
9903af6ab5fSopenharmony_ci    if (res != nullptr) {
9913af6ab5fSopenharmony_ci        return res;
9923af6ab5fSopenharmony_ci    }
9933af6ab5fSopenharmony_ci
9943af6ab5fSopenharmony_ci    switch (expr->operator_) {
9953af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_PLUS:
9963af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MINUS:
9973af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_TILDE: {
9983af6ab5fSopenharmony_ci            checker->CheckNonNullType(operandType, expr->Start());
9993af6ab5fSopenharmony_ci            // NOTE: aszilagyi. check Symbol like types
10003af6ab5fSopenharmony_ci
10013af6ab5fSopenharmony_ci            if (expr->operator_ == lexer::TokenType::PUNCTUATOR_PLUS) {
10023af6ab5fSopenharmony_ci                if (checker::TSChecker::MaybeTypeOfKind(operandType, checker::TypeFlag::BIGINT_LIKE)) {
10033af6ab5fSopenharmony_ci                    checker->ThrowTypeError({"Operator '+' cannot be applied to type '", operandType, "'"},
10043af6ab5fSopenharmony_ci                                            expr->Start());
10053af6ab5fSopenharmony_ci                }
10063af6ab5fSopenharmony_ci
10073af6ab5fSopenharmony_ci                return checker->GlobalNumberType();
10083af6ab5fSopenharmony_ci            }
10093af6ab5fSopenharmony_ci
10103af6ab5fSopenharmony_ci            return checker->GetUnaryResultType(operandType);
10113af6ab5fSopenharmony_ci        }
10123af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: {
10133af6ab5fSopenharmony_ci            checker->CheckTruthinessOfType(operandType, expr->Start());
10143af6ab5fSopenharmony_ci            auto facts = operandType->GetTypeFacts();
10153af6ab5fSopenharmony_ci            if ((facts & checker::TypeFacts::TRUTHY) != 0) {
10163af6ab5fSopenharmony_ci                return checker->GlobalFalseType();
10173af6ab5fSopenharmony_ci            }
10183af6ab5fSopenharmony_ci
10193af6ab5fSopenharmony_ci            if ((facts & checker::TypeFacts::FALSY) != 0) {
10203af6ab5fSopenharmony_ci                return checker->GlobalTrueType();
10213af6ab5fSopenharmony_ci            }
10223af6ab5fSopenharmony_ci
10233af6ab5fSopenharmony_ci            return checker->GlobalBooleanType();
10243af6ab5fSopenharmony_ci        }
10253af6ab5fSopenharmony_ci        default: {
10263af6ab5fSopenharmony_ci            UNREACHABLE();
10273af6ab5fSopenharmony_ci        }
10283af6ab5fSopenharmony_ci    }
10293af6ab5fSopenharmony_ci
10303af6ab5fSopenharmony_ci    return nullptr;
10313af6ab5fSopenharmony_ci}
10323af6ab5fSopenharmony_ci
10333af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::UpdateExpression *expr) const
10343af6ab5fSopenharmony_ci{
10353af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
10363af6ab5fSopenharmony_ci    checker::Type *operandType = expr->argument_->Check(checker);
10373af6ab5fSopenharmony_ci    checker->CheckNonNullType(operandType, expr->Start());
10383af6ab5fSopenharmony_ci
10393af6ab5fSopenharmony_ci    if (!operandType->HasTypeFlag(checker::TypeFlag::VALID_ARITHMETIC_TYPE)) {
10403af6ab5fSopenharmony_ci        checker->ThrowTypeError("An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type.",
10413af6ab5fSopenharmony_ci                                expr->Start());
10423af6ab5fSopenharmony_ci    }
10433af6ab5fSopenharmony_ci
10443af6ab5fSopenharmony_ci    checker->CheckReferenceExpression(
10453af6ab5fSopenharmony_ci        expr->argument_, "The operand of an increment or decrement operator must be a variable or a property access",
10463af6ab5fSopenharmony_ci        "The operand of an increment or decrement operator may not be an optional property access");
10473af6ab5fSopenharmony_ci
10483af6ab5fSopenharmony_ci    return checker->GetUnaryResultType(operandType);
10493af6ab5fSopenharmony_ci}
10503af6ab5fSopenharmony_ci
10513af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::YieldExpression *expr) const
10523af6ab5fSopenharmony_ci{
10533af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
10543af6ab5fSopenharmony_ci    // NOTE: aszilagyi.
10553af6ab5fSopenharmony_ci    return checker->GlobalAnyType();
10563af6ab5fSopenharmony_ci}
10573af6ab5fSopenharmony_ci// compile methods for LITERAL EXPRESSIONS in alphabetical order
10583af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::BigIntLiteral *expr) const
10593af6ab5fSopenharmony_ci{
10603af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
10613af6ab5fSopenharmony_ci    auto search = checker->BigintLiteralMap().find(expr->Str());
10623af6ab5fSopenharmony_ci    if (search != checker->BigintLiteralMap().end()) {
10633af6ab5fSopenharmony_ci        return search->second;
10643af6ab5fSopenharmony_ci    }
10653af6ab5fSopenharmony_ci
10663af6ab5fSopenharmony_ci    auto *newBigintLiteralType = checker->Allocator()->New<checker::BigintLiteralType>(expr->Str(), false);
10673af6ab5fSopenharmony_ci    checker->BigintLiteralMap().insert({expr->Str(), newBigintLiteralType});
10683af6ab5fSopenharmony_ci    return newBigintLiteralType;
10693af6ab5fSopenharmony_ci}
10703af6ab5fSopenharmony_ci
10713af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::BooleanLiteral *expr) const
10723af6ab5fSopenharmony_ci{
10733af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
10743af6ab5fSopenharmony_ci    return expr->Value() ? checker->GlobalTrueType() : checker->GlobalFalseType();
10753af6ab5fSopenharmony_ci}
10763af6ab5fSopenharmony_ci
10773af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::NullLiteral *expr) const
10783af6ab5fSopenharmony_ci{
10793af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
10803af6ab5fSopenharmony_ci    return checker->GlobalNullType();
10813af6ab5fSopenharmony_ci}
10823af6ab5fSopenharmony_ci
10833af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::NumberLiteral *expr) const
10843af6ab5fSopenharmony_ci{
10853af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
10863af6ab5fSopenharmony_ci    auto search = checker->NumberLiteralMap().find(expr->Number().GetDouble());
10873af6ab5fSopenharmony_ci    if (search != checker->NumberLiteralMap().end()) {
10883af6ab5fSopenharmony_ci        return search->second;
10893af6ab5fSopenharmony_ci    }
10903af6ab5fSopenharmony_ci
10913af6ab5fSopenharmony_ci    auto *newNumLiteralType = checker->Allocator()->New<checker::NumberLiteralType>(expr->Number().GetDouble());
10923af6ab5fSopenharmony_ci    checker->NumberLiteralMap().insert({expr->Number().GetDouble(), newNumLiteralType});
10933af6ab5fSopenharmony_ci    return newNumLiteralType;
10943af6ab5fSopenharmony_ci}
10953af6ab5fSopenharmony_ci
10963af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::RegExpLiteral *expr) const
10973af6ab5fSopenharmony_ci{
10983af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
10993af6ab5fSopenharmony_ci    // NOTE: aszilagyi
11003af6ab5fSopenharmony_ci    return checker->GlobalAnyType();
11013af6ab5fSopenharmony_ci}
11023af6ab5fSopenharmony_ci
11033af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::StringLiteral *expr) const
11043af6ab5fSopenharmony_ci{
11053af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
11063af6ab5fSopenharmony_ci    auto search = checker->StringLiteralMap().find(expr->Str());
11073af6ab5fSopenharmony_ci    if (search != checker->StringLiteralMap().end()) {
11083af6ab5fSopenharmony_ci        return search->second;
11093af6ab5fSopenharmony_ci    }
11103af6ab5fSopenharmony_ci
11113af6ab5fSopenharmony_ci    auto *newStrLiteralType = checker->Allocator()->New<checker::StringLiteralType>(expr->Str());
11123af6ab5fSopenharmony_ci    checker->StringLiteralMap().insert({expr->Str(), newStrLiteralType});
11133af6ab5fSopenharmony_ci
11143af6ab5fSopenharmony_ci    return newStrLiteralType;
11153af6ab5fSopenharmony_ci}
11163af6ab5fSopenharmony_ci
11173af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::BlockStatement *st) const
11183af6ab5fSopenharmony_ci{
11193af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
11203af6ab5fSopenharmony_ci    checker::ScopeContext scopeCtx(checker, st->Scope());
11213af6ab5fSopenharmony_ci
11223af6ab5fSopenharmony_ci    for (auto *it : st->Statements()) {
11233af6ab5fSopenharmony_ci        it->Check(checker);
11243af6ab5fSopenharmony_ci    }
11253af6ab5fSopenharmony_ci
11263af6ab5fSopenharmony_ci    return nullptr;
11273af6ab5fSopenharmony_ci}
11283af6ab5fSopenharmony_ci
11293af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::BreakStatement *st) const
11303af6ab5fSopenharmony_ci{
11313af6ab5fSopenharmony_ci    return nullptr;
11323af6ab5fSopenharmony_ci}
11333af6ab5fSopenharmony_ci
11343af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::DoWhileStatement *st) const
11353af6ab5fSopenharmony_ci{
11363af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
11373af6ab5fSopenharmony_ci    checker::ScopeContext scopeCtx(checker, st->Scope());
11383af6ab5fSopenharmony_ci
11393af6ab5fSopenharmony_ci    checker::Type *testType = st->Test()->Check(checker);
11403af6ab5fSopenharmony_ci    checker->CheckTruthinessOfType(testType, st->Test()->Start());
11413af6ab5fSopenharmony_ci    st->Body()->Check(checker);
11423af6ab5fSopenharmony_ci
11433af6ab5fSopenharmony_ci    return nullptr;
11443af6ab5fSopenharmony_ci}
11453af6ab5fSopenharmony_ci
11463af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::EmptyStatement *st) const
11473af6ab5fSopenharmony_ci{
11483af6ab5fSopenharmony_ci    return nullptr;
11493af6ab5fSopenharmony_ci}
11503af6ab5fSopenharmony_ci
11513af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::ExpressionStatement *st) const
11523af6ab5fSopenharmony_ci{
11533af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
11543af6ab5fSopenharmony_ci    return st->GetExpression()->Check(checker);
11553af6ab5fSopenharmony_ci}
11563af6ab5fSopenharmony_ci
11573af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::ForUpdateStatement *st) const
11583af6ab5fSopenharmony_ci{
11593af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
11603af6ab5fSopenharmony_ci    checker::ScopeContext scopeCtx(checker, st->Scope());
11613af6ab5fSopenharmony_ci
11623af6ab5fSopenharmony_ci    if (st->Init() != nullptr) {
11633af6ab5fSopenharmony_ci        st->Init()->Check(checker);
11643af6ab5fSopenharmony_ci    }
11653af6ab5fSopenharmony_ci
11663af6ab5fSopenharmony_ci    if (st->Test() != nullptr) {
11673af6ab5fSopenharmony_ci        checker::Type *testType = st->Test()->Check(checker);
11683af6ab5fSopenharmony_ci        checker->CheckTruthinessOfType(testType, st->Start());
11693af6ab5fSopenharmony_ci    }
11703af6ab5fSopenharmony_ci
11713af6ab5fSopenharmony_ci    if (st->Update() != nullptr) {
11723af6ab5fSopenharmony_ci        st->Update()->Check(checker);
11733af6ab5fSopenharmony_ci    }
11743af6ab5fSopenharmony_ci
11753af6ab5fSopenharmony_ci    st->Body()->Check(checker);
11763af6ab5fSopenharmony_ci
11773af6ab5fSopenharmony_ci    return nullptr;
11783af6ab5fSopenharmony_ci}
11793af6ab5fSopenharmony_ci
11803af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::FunctionDeclaration *st) const
11813af6ab5fSopenharmony_ci{
11823af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
11833af6ab5fSopenharmony_ci    if (st->Function()->IsOverload()) {
11843af6ab5fSopenharmony_ci        return nullptr;
11853af6ab5fSopenharmony_ci    }
11863af6ab5fSopenharmony_ci
11873af6ab5fSopenharmony_ci    const util::StringView &funcName = st->Function()->Id()->Name();
11883af6ab5fSopenharmony_ci    auto result = checker->Scope()->Find(funcName);
11893af6ab5fSopenharmony_ci    ASSERT(result.variable);
11903af6ab5fSopenharmony_ci
11913af6ab5fSopenharmony_ci    checker::ScopeContext scopeCtx(checker, st->Function()->Scope());
11923af6ab5fSopenharmony_ci
11933af6ab5fSopenharmony_ci    if (result.variable->TsType() == nullptr) {
11943af6ab5fSopenharmony_ci        checker->InferFunctionDeclarationType(result.variable->Declaration()->AsFunctionDecl(), result.variable);
11953af6ab5fSopenharmony_ci    }
11963af6ab5fSopenharmony_ci
11973af6ab5fSopenharmony_ci    st->Function()->Body()->Check(checker);
11983af6ab5fSopenharmony_ci
11993af6ab5fSopenharmony_ci    return nullptr;
12003af6ab5fSopenharmony_ci}
12013af6ab5fSopenharmony_ci
12023af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::IfStatement *st) const
12033af6ab5fSopenharmony_ci{
12043af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
12053af6ab5fSopenharmony_ci    checker::Type *testType = st->Test()->Check(checker);
12063af6ab5fSopenharmony_ci    checker->CheckTruthinessOfType(testType, st->Start());
12073af6ab5fSopenharmony_ci    checker->CheckTestingKnownTruthyCallableOrAwaitableType(st->Test(), testType, st->Consequent());
12083af6ab5fSopenharmony_ci
12093af6ab5fSopenharmony_ci    st->Consequent()->Check(checker);
12103af6ab5fSopenharmony_ci
12113af6ab5fSopenharmony_ci    if (st->Alternate() != nullptr) {
12123af6ab5fSopenharmony_ci        st->Alternate()->Check(checker);
12133af6ab5fSopenharmony_ci    }
12143af6ab5fSopenharmony_ci
12153af6ab5fSopenharmony_ci    return nullptr;
12163af6ab5fSopenharmony_ci}
12173af6ab5fSopenharmony_ci
12183af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::ReturnStatement *st) const
12193af6ab5fSopenharmony_ci{
12203af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
12213af6ab5fSopenharmony_ci    ir::AstNode *ancestor = util::Helpers::FindAncestorGivenByType(st, ir::AstNodeType::SCRIPT_FUNCTION);
12223af6ab5fSopenharmony_ci    ASSERT(ancestor && ancestor->IsScriptFunction());
12233af6ab5fSopenharmony_ci    auto *containingFunc = ancestor->AsScriptFunction();
12243af6ab5fSopenharmony_ci
12253af6ab5fSopenharmony_ci    if (containingFunc->Parent()->Parent()->IsMethodDefinition()) {
12263af6ab5fSopenharmony_ci        const ir::MethodDefinition *containingClassMethod = containingFunc->Parent()->Parent()->AsMethodDefinition();
12273af6ab5fSopenharmony_ci        if (containingClassMethod->Kind() == ir::MethodDefinitionKind::SET) {
12283af6ab5fSopenharmony_ci            checker->ThrowTypeError("Setters cannot return a value", st->Start());
12293af6ab5fSopenharmony_ci        }
12303af6ab5fSopenharmony_ci    }
12313af6ab5fSopenharmony_ci
12323af6ab5fSopenharmony_ci    if (containingFunc->ReturnTypeAnnotation() != nullptr) {
12333af6ab5fSopenharmony_ci        checker::Type *returnType = checker->GlobalUndefinedType();
12343af6ab5fSopenharmony_ci        checker::Type *funcReturnType = containingFunc->ReturnTypeAnnotation()->GetType(checker);
12353af6ab5fSopenharmony_ci
12363af6ab5fSopenharmony_ci        if (st->Argument() != nullptr) {
12373af6ab5fSopenharmony_ci            checker->ElaborateElementwise(funcReturnType, st->Argument(), st->Start());
12383af6ab5fSopenharmony_ci            returnType = checker->CheckTypeCached(st->Argument());
12393af6ab5fSopenharmony_ci        }
12403af6ab5fSopenharmony_ci
12413af6ab5fSopenharmony_ci        checker->IsTypeAssignableTo(returnType, funcReturnType,
12423af6ab5fSopenharmony_ci                                    {"Type '", returnType, "' is not assignable to type '", funcReturnType, "'."},
12433af6ab5fSopenharmony_ci                                    st->Start());
12443af6ab5fSopenharmony_ci    }
12453af6ab5fSopenharmony_ci
12463af6ab5fSopenharmony_ci    return nullptr;
12473af6ab5fSopenharmony_ci}
12483af6ab5fSopenharmony_ci
12493af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::SwitchStatement *st) const
12503af6ab5fSopenharmony_ci{
12513af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
12523af6ab5fSopenharmony_ci    checker::ScopeContext scopeCtx(checker, st->Scope());
12533af6ab5fSopenharmony_ci
12543af6ab5fSopenharmony_ci    checker::Type *exprType = st->Discriminant()->Check(checker);
12553af6ab5fSopenharmony_ci    bool exprIsLiteral = checker::TSChecker::IsLiteralType(exprType);
12563af6ab5fSopenharmony_ci
12573af6ab5fSopenharmony_ci    for (auto *it : st->Cases()) {
12583af6ab5fSopenharmony_ci        if (it->Test() != nullptr) {
12593af6ab5fSopenharmony_ci            checker::Type *caseType = it->Test()->Check(checker);
12603af6ab5fSopenharmony_ci            bool caseIsLiteral = checker::TSChecker::IsLiteralType(caseType);
12613af6ab5fSopenharmony_ci            checker::Type *comparedExprType = exprType;
12623af6ab5fSopenharmony_ci
12633af6ab5fSopenharmony_ci            if (!caseIsLiteral || !exprIsLiteral) {
12643af6ab5fSopenharmony_ci                caseType = caseIsLiteral ? checker->GetBaseTypeOfLiteralType(caseType) : caseType;
12653af6ab5fSopenharmony_ci                comparedExprType = checker->GetBaseTypeOfLiteralType(exprType);
12663af6ab5fSopenharmony_ci            }
12673af6ab5fSopenharmony_ci
12683af6ab5fSopenharmony_ci            if (!checker->IsTypeEqualityComparableTo(comparedExprType, caseType) &&
12693af6ab5fSopenharmony_ci                !checker->IsTypeComparableTo(caseType, comparedExprType)) {
12703af6ab5fSopenharmony_ci                checker->ThrowTypeError({"Type ", caseType, " is not comparable to type ", comparedExprType},
12713af6ab5fSopenharmony_ci                                        it->Test()->Start());
12723af6ab5fSopenharmony_ci            }
12733af6ab5fSopenharmony_ci        }
12743af6ab5fSopenharmony_ci
12753af6ab5fSopenharmony_ci        for (auto *caseStmt : it->Consequent()) {
12763af6ab5fSopenharmony_ci            caseStmt->Check(checker);
12773af6ab5fSopenharmony_ci        }
12783af6ab5fSopenharmony_ci    }
12793af6ab5fSopenharmony_ci
12803af6ab5fSopenharmony_ci    return nullptr;
12813af6ab5fSopenharmony_ci}
12823af6ab5fSopenharmony_ci
12833af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TryStatement *st) const
12843af6ab5fSopenharmony_ci{
12853af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
12863af6ab5fSopenharmony_ci    st->Block()->Check(checker);
12873af6ab5fSopenharmony_ci
12883af6ab5fSopenharmony_ci    for (auto *catchClause : st->CatchClauses()) {
12893af6ab5fSopenharmony_ci        if (catchClause != nullptr) {
12903af6ab5fSopenharmony_ci            catchClause->Check(checker);
12913af6ab5fSopenharmony_ci        }
12923af6ab5fSopenharmony_ci    }
12933af6ab5fSopenharmony_ci
12943af6ab5fSopenharmony_ci    if (st->HasFinalizer()) {
12953af6ab5fSopenharmony_ci        st->finalizer_->Check(checker);
12963af6ab5fSopenharmony_ci    }
12973af6ab5fSopenharmony_ci
12983af6ab5fSopenharmony_ci    return nullptr;
12993af6ab5fSopenharmony_ci}
13003af6ab5fSopenharmony_ci
13013af6ab5fSopenharmony_cistatic void CheckSimpleVariableDeclaration(checker::TSChecker *checker, ir::VariableDeclarator *declarator)
13023af6ab5fSopenharmony_ci{
13033af6ab5fSopenharmony_ci    varbinder::Variable *const bindingVar = declarator->Id()->AsIdentifier()->Variable();
13043af6ab5fSopenharmony_ci    checker::Type *previousType = bindingVar->TsType();
13053af6ab5fSopenharmony_ci    auto *const typeAnnotation = declarator->Id()->AsIdentifier()->TypeAnnotation();
13063af6ab5fSopenharmony_ci    auto *const initializer = declarator->Init();
13073af6ab5fSopenharmony_ci    const bool isConst = declarator->Parent()->AsVariableDeclaration()->Kind() ==
13083af6ab5fSopenharmony_ci                         ir::VariableDeclaration::VariableDeclarationKind::CONST;
13093af6ab5fSopenharmony_ci
13103af6ab5fSopenharmony_ci    if (isConst) {
13113af6ab5fSopenharmony_ci        checker->AddStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
13123af6ab5fSopenharmony_ci    }
13133af6ab5fSopenharmony_ci
13143af6ab5fSopenharmony_ci    if (typeAnnotation != nullptr) {
13153af6ab5fSopenharmony_ci        typeAnnotation->Check(checker);
13163af6ab5fSopenharmony_ci    }
13173af6ab5fSopenharmony_ci
13183af6ab5fSopenharmony_ci    if (typeAnnotation != nullptr && initializer != nullptr) {
13193af6ab5fSopenharmony_ci        checker::Type *const annotationType = typeAnnotation->GetType(checker);
13203af6ab5fSopenharmony_ci        checker->ElaborateElementwise(annotationType, initializer, declarator->Id()->Start());
13213af6ab5fSopenharmony_ci        bindingVar->SetTsType(annotationType);
13223af6ab5fSopenharmony_ci    } else if (typeAnnotation != nullptr) {
13233af6ab5fSopenharmony_ci        bindingVar->SetTsType(typeAnnotation->GetType(checker));
13243af6ab5fSopenharmony_ci    } else if (initializer != nullptr) {
13253af6ab5fSopenharmony_ci        checker::Type *initializerType = checker->CheckTypeCached(initializer);
13263af6ab5fSopenharmony_ci
13273af6ab5fSopenharmony_ci        if (!isConst) {
13283af6ab5fSopenharmony_ci            initializerType = checker->GetBaseTypeOfLiteralType(initializerType);
13293af6ab5fSopenharmony_ci        }
13303af6ab5fSopenharmony_ci
13313af6ab5fSopenharmony_ci        if (initializerType->IsNullType()) {
13323af6ab5fSopenharmony_ci            checker->ThrowTypeError(
13333af6ab5fSopenharmony_ci                {"Cannot infer type for variable '", declarator->Id()->AsIdentifier()->Name(), "'."},
13343af6ab5fSopenharmony_ci                declarator->Id()->Start());
13353af6ab5fSopenharmony_ci        }
13363af6ab5fSopenharmony_ci
13373af6ab5fSopenharmony_ci        bindingVar->SetTsType(initializerType);
13383af6ab5fSopenharmony_ci    } else {
13393af6ab5fSopenharmony_ci        checker->ThrowTypeError({"Variable ", declarator->Id()->AsIdentifier()->Name(), " implicitly has an any type."},
13403af6ab5fSopenharmony_ci                                declarator->Id()->Start());
13413af6ab5fSopenharmony_ci    }
13423af6ab5fSopenharmony_ci
13433af6ab5fSopenharmony_ci    if (previousType != nullptr) {
13443af6ab5fSopenharmony_ci        checker->IsTypeIdenticalTo(bindingVar->TsType(), previousType,
13453af6ab5fSopenharmony_ci                                   {"Subsequent variable declaration must have the same type. Variable '",
13463af6ab5fSopenharmony_ci                                    bindingVar->Name(), "' must be of type '", previousType, "', but here has type '",
13473af6ab5fSopenharmony_ci                                    bindingVar->TsType(), "'."},
13483af6ab5fSopenharmony_ci                                   declarator->Id()->Start());
13493af6ab5fSopenharmony_ci    }
13503af6ab5fSopenharmony_ci
13513af6ab5fSopenharmony_ci    checker->RemoveStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
13523af6ab5fSopenharmony_ci}
13533af6ab5fSopenharmony_ci
13543af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::VariableDeclarator *st) const
13553af6ab5fSopenharmony_ci{
13563af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
13573af6ab5fSopenharmony_ci
13583af6ab5fSopenharmony_ci    if (st->TsType() == st->CHECKED) {
13593af6ab5fSopenharmony_ci        return nullptr;
13603af6ab5fSopenharmony_ci    }
13613af6ab5fSopenharmony_ci
13623af6ab5fSopenharmony_ci    if (st->Id()->IsIdentifier()) {
13633af6ab5fSopenharmony_ci        CheckSimpleVariableDeclaration(checker, st);
13643af6ab5fSopenharmony_ci        st->SetTsType(st->CHECKED);
13653af6ab5fSopenharmony_ci        return nullptr;
13663af6ab5fSopenharmony_ci    }
13673af6ab5fSopenharmony_ci
13683af6ab5fSopenharmony_ci    if (st->Id()->IsArrayPattern()) {
13693af6ab5fSopenharmony_ci        auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
13703af6ab5fSopenharmony_ci        checker::ArrayDestructuringContext({checker, st->Id(), false,
13713af6ab5fSopenharmony_ci                                            st->Id()->AsArrayPattern()->TypeAnnotation() == nullptr,
13723af6ab5fSopenharmony_ci                                            st->Id()->AsArrayPattern()->TypeAnnotation(), st->Init()})
13733af6ab5fSopenharmony_ci            .Start();
13743af6ab5fSopenharmony_ci
13753af6ab5fSopenharmony_ci        st->SetTsType(st->CHECKED);
13763af6ab5fSopenharmony_ci        return nullptr;
13773af6ab5fSopenharmony_ci    }
13783af6ab5fSopenharmony_ci
13793af6ab5fSopenharmony_ci    ASSERT(st->Id()->IsObjectPattern());
13803af6ab5fSopenharmony_ci    auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
13813af6ab5fSopenharmony_ci    checker::ObjectDestructuringContext({checker, st->Id(), false,
13823af6ab5fSopenharmony_ci                                         st->Id()->AsObjectPattern()->TypeAnnotation() == nullptr,
13833af6ab5fSopenharmony_ci                                         st->Id()->AsObjectPattern()->TypeAnnotation(), st->Init()})
13843af6ab5fSopenharmony_ci        .Start();
13853af6ab5fSopenharmony_ci
13863af6ab5fSopenharmony_ci    st->SetTsType(st->CHECKED);
13873af6ab5fSopenharmony_ci    return nullptr;
13883af6ab5fSopenharmony_ci}
13893af6ab5fSopenharmony_ci
13903af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::VariableDeclaration *st) const
13913af6ab5fSopenharmony_ci{
13923af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
13933af6ab5fSopenharmony_ci    for (auto *it : st->Declarators()) {
13943af6ab5fSopenharmony_ci        it->Check(checker);
13953af6ab5fSopenharmony_ci    }
13963af6ab5fSopenharmony_ci
13973af6ab5fSopenharmony_ci    return nullptr;
13983af6ab5fSopenharmony_ci}
13993af6ab5fSopenharmony_ci
14003af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::WhileStatement *st) const
14013af6ab5fSopenharmony_ci{
14023af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
14033af6ab5fSopenharmony_ci    checker::ScopeContext scopeCtx(checker, st->Scope());
14043af6ab5fSopenharmony_ci
14053af6ab5fSopenharmony_ci    checker::Type *testType = st->Test()->Check(checker);
14063af6ab5fSopenharmony_ci    checker->CheckTruthinessOfType(testType, st->Test()->Start());
14073af6ab5fSopenharmony_ci
14083af6ab5fSopenharmony_ci    st->Body()->Check(checker);
14093af6ab5fSopenharmony_ci    return nullptr;
14103af6ab5fSopenharmony_ci}
14113af6ab5fSopenharmony_ci// from ts folder
14123af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSAnyKeyword *node) const
14133af6ab5fSopenharmony_ci{
14143af6ab5fSopenharmony_ci    return nullptr;
14153af6ab5fSopenharmony_ci}
14163af6ab5fSopenharmony_ci
14173af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSArrayType *node) const
14183af6ab5fSopenharmony_ci{
14193af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
14203af6ab5fSopenharmony_ci    node->elementType_->Check(checker);
14213af6ab5fSopenharmony_ci    return nullptr;
14223af6ab5fSopenharmony_ci}
14233af6ab5fSopenharmony_ci
14243af6ab5fSopenharmony_cistatic bool IsValidConstAssertionArgument(checker::Checker *checker, const ir::AstNode *arg)
14253af6ab5fSopenharmony_ci{
14263af6ab5fSopenharmony_ci    switch (arg->Type()) {
14273af6ab5fSopenharmony_ci        case ir::AstNodeType::NUMBER_LITERAL:
14283af6ab5fSopenharmony_ci        case ir::AstNodeType::STRING_LITERAL:
14293af6ab5fSopenharmony_ci        case ir::AstNodeType::BIGINT_LITERAL:
14303af6ab5fSopenharmony_ci        case ir::AstNodeType::BOOLEAN_LITERAL:
14313af6ab5fSopenharmony_ci        case ir::AstNodeType::ARRAY_EXPRESSION:
14323af6ab5fSopenharmony_ci        case ir::AstNodeType::OBJECT_EXPRESSION:
14333af6ab5fSopenharmony_ci        case ir::AstNodeType::TEMPLATE_LITERAL: {
14343af6ab5fSopenharmony_ci            return true;
14353af6ab5fSopenharmony_ci        }
14363af6ab5fSopenharmony_ci        case ir::AstNodeType::UNARY_EXPRESSION: {
14373af6ab5fSopenharmony_ci            const ir::UnaryExpression *unaryExpr = arg->AsUnaryExpression();
14383af6ab5fSopenharmony_ci            lexer::TokenType op = unaryExpr->OperatorType();
14393af6ab5fSopenharmony_ci            const ir::Expression *unaryArg = unaryExpr->Argument();
14403af6ab5fSopenharmony_ci            return (op == lexer::TokenType::PUNCTUATOR_MINUS && unaryArg->IsLiteral() &&
14413af6ab5fSopenharmony_ci                    (unaryArg->AsLiteral()->IsNumberLiteral() || unaryArg->AsLiteral()->IsBigIntLiteral())) ||
14423af6ab5fSopenharmony_ci                   (op == lexer::TokenType::PUNCTUATOR_PLUS && unaryArg->IsLiteral() &&
14433af6ab5fSopenharmony_ci                    unaryArg->AsLiteral()->IsNumberLiteral());
14443af6ab5fSopenharmony_ci        }
14453af6ab5fSopenharmony_ci        case ir::AstNodeType::MEMBER_EXPRESSION: {
14463af6ab5fSopenharmony_ci            const ir::MemberExpression *memberExpr = arg->AsMemberExpression();
14473af6ab5fSopenharmony_ci            if (memberExpr->Object()->IsIdentifier()) {
14483af6ab5fSopenharmony_ci                auto result = checker->Scope()->Find(memberExpr->Object()->AsIdentifier()->Name());
14493af6ab5fSopenharmony_ci                constexpr auto ENUM_LITERAL_TYPE = checker::EnumLiteralType::EnumLiteralTypeKind::LITERAL;
14503af6ab5fSopenharmony_ci                if (result.variable != nullptr &&
14513af6ab5fSopenharmony_ci                    result.variable->TsType()->HasTypeFlag(checker::TypeFlag::ENUM_LITERAL) &&
14523af6ab5fSopenharmony_ci                    result.variable->TsType()->AsEnumLiteralType()->Kind() == ENUM_LITERAL_TYPE) {
14533af6ab5fSopenharmony_ci                    return true;
14543af6ab5fSopenharmony_ci                }
14553af6ab5fSopenharmony_ci            }
14563af6ab5fSopenharmony_ci            return false;
14573af6ab5fSopenharmony_ci        }
14583af6ab5fSopenharmony_ci        default:
14593af6ab5fSopenharmony_ci            return false;
14603af6ab5fSopenharmony_ci    }
14613af6ab5fSopenharmony_ci}
14623af6ab5fSopenharmony_ci
14633af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSAsExpression *expr) const
14643af6ab5fSopenharmony_ci{
14653af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
14663af6ab5fSopenharmony_ci    if (expr->IsConst()) {
14673af6ab5fSopenharmony_ci        auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_CONST_CONTEXT);
14683af6ab5fSopenharmony_ci        checker::Type *exprType = expr->Expr()->Check(checker);
14693af6ab5fSopenharmony_ci
14703af6ab5fSopenharmony_ci        if (!IsValidConstAssertionArgument(checker, expr->Expr())) {
14713af6ab5fSopenharmony_ci            checker->ThrowTypeError(
14723af6ab5fSopenharmony_ci                "A 'const' assertions can only be applied to references to enum members, or string, number, "
14733af6ab5fSopenharmony_ci                "boolean, array, or object literals.",
14743af6ab5fSopenharmony_ci                expr->Expr()->Start());
14753af6ab5fSopenharmony_ci        }
14763af6ab5fSopenharmony_ci
14773af6ab5fSopenharmony_ci        return exprType;
14783af6ab5fSopenharmony_ci    }
14793af6ab5fSopenharmony_ci
14803af6ab5fSopenharmony_ci    auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::NO_OPTS);
14813af6ab5fSopenharmony_ci
14823af6ab5fSopenharmony_ci    expr->TypeAnnotation()->Check(checker);
14833af6ab5fSopenharmony_ci    checker::Type *exprType = checker->GetBaseTypeOfLiteralType(expr->Expr()->Check(checker));
14843af6ab5fSopenharmony_ci    checker::Type *targetType = expr->TypeAnnotation()->GetType(checker);
14853af6ab5fSopenharmony_ci
14863af6ab5fSopenharmony_ci    checker->IsTypeComparableTo(
14873af6ab5fSopenharmony_ci        targetType, exprType,
14883af6ab5fSopenharmony_ci        {"Conversion of type '", exprType, "' to type '", targetType,
14893af6ab5fSopenharmony_ci         "' may be a mistake because neither type sufficiently overlaps with the other. If this was ",
14903af6ab5fSopenharmony_ci         "intentional, convert the expression to 'unknown' first."},
14913af6ab5fSopenharmony_ci        expr->Start());
14923af6ab5fSopenharmony_ci
14933af6ab5fSopenharmony_ci    return targetType;
14943af6ab5fSopenharmony_ci}
14953af6ab5fSopenharmony_ci
14963af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSBigintKeyword *node) const
14973af6ab5fSopenharmony_ci{
14983af6ab5fSopenharmony_ci    return nullptr;
14993af6ab5fSopenharmony_ci}
15003af6ab5fSopenharmony_ci
15013af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSBooleanKeyword *node) const
15023af6ab5fSopenharmony_ci{
15033af6ab5fSopenharmony_ci    return nullptr;
15043af6ab5fSopenharmony_ci}
15053af6ab5fSopenharmony_ci
15063af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSConstructorType *node) const
15073af6ab5fSopenharmony_ci{
15083af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
15093af6ab5fSopenharmony_ci    checker::ScopeContext scopeCtx(checker, node->Scope());
15103af6ab5fSopenharmony_ci
15113af6ab5fSopenharmony_ci    auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
15123af6ab5fSopenharmony_ci    checker->CheckFunctionParameterDeclarations(node->Params(), signatureInfo);
15133af6ab5fSopenharmony_ci    node->ReturnType()->Check(checker);
15143af6ab5fSopenharmony_ci    auto *constructSignature =
15153af6ab5fSopenharmony_ci        checker->Allocator()->New<checker::Signature>(signatureInfo, node->ReturnType()->GetType(checker));
15163af6ab5fSopenharmony_ci
15173af6ab5fSopenharmony_ci    return checker->CreateConstructorTypeWithSignature(constructSignature);
15183af6ab5fSopenharmony_ci}
15193af6ab5fSopenharmony_ci
15203af6ab5fSopenharmony_cistatic varbinder::EnumMemberResult EvaluateIdentifier(checker::TSChecker *checker, varbinder::EnumVariable *enumVar,
15213af6ab5fSopenharmony_ci                                                      const ir::Identifier *expr)
15223af6ab5fSopenharmony_ci{
15233af6ab5fSopenharmony_ci    if (expr->Name() == "NaN") {
15243af6ab5fSopenharmony_ci        return std::nan("");
15253af6ab5fSopenharmony_ci    }
15263af6ab5fSopenharmony_ci    if (expr->Name() == "Infinity") {
15273af6ab5fSopenharmony_ci        return std::numeric_limits<double>::infinity();
15283af6ab5fSopenharmony_ci    }
15293af6ab5fSopenharmony_ci
15303af6ab5fSopenharmony_ci    varbinder::Variable *enumMember = expr->AsIdentifier()->Variable();
15313af6ab5fSopenharmony_ci
15323af6ab5fSopenharmony_ci    if (enumMember == nullptr) {
15333af6ab5fSopenharmony_ci        checker->ThrowTypeError({"Cannot find name ", expr->AsIdentifier()->Name()},
15343af6ab5fSopenharmony_ci                                enumVar->Declaration()->Node()->Start());
15353af6ab5fSopenharmony_ci    }
15363af6ab5fSopenharmony_ci
15373af6ab5fSopenharmony_ci    if (enumMember->IsEnumVariable()) {
15383af6ab5fSopenharmony_ci        varbinder::EnumVariable *exprEnumVar = enumMember->AsEnumVariable();
15393af6ab5fSopenharmony_ci        if (std::holds_alternative<bool>(exprEnumVar->Value())) {
15403af6ab5fSopenharmony_ci            checker->ThrowTypeError(
15413af6ab5fSopenharmony_ci                "A member initializer in a enum declaration cannot reference members declared after it, "
15423af6ab5fSopenharmony_ci                "including "
15433af6ab5fSopenharmony_ci                "members defined in other enums.",
15443af6ab5fSopenharmony_ci                enumVar->Declaration()->Node()->Start());
15453af6ab5fSopenharmony_ci        }
15463af6ab5fSopenharmony_ci
15473af6ab5fSopenharmony_ci        return exprEnumVar->Value();
15483af6ab5fSopenharmony_ci    }
15493af6ab5fSopenharmony_ci
15503af6ab5fSopenharmony_ci    return false;
15513af6ab5fSopenharmony_ci}
15523af6ab5fSopenharmony_ci
15533af6ab5fSopenharmony_cistatic int32_t ToInt(double num)
15543af6ab5fSopenharmony_ci{
15553af6ab5fSopenharmony_ci    if (num >= std::numeric_limits<int32_t>::min() && num <= std::numeric_limits<int32_t>::max()) {
15563af6ab5fSopenharmony_ci        return static_cast<int32_t>(num);
15573af6ab5fSopenharmony_ci    }
15583af6ab5fSopenharmony_ci
15593af6ab5fSopenharmony_ci    // NOTE (aszilagyi): Perform ECMA defined toInt conversion
15603af6ab5fSopenharmony_ci
15613af6ab5fSopenharmony_ci    return 0;
15623af6ab5fSopenharmony_ci}
15633af6ab5fSopenharmony_ci
15643af6ab5fSopenharmony_cistatic uint32_t ToUInt(double num)
15653af6ab5fSopenharmony_ci{
15663af6ab5fSopenharmony_ci    if (num >= std::numeric_limits<uint32_t>::min() && num <= std::numeric_limits<uint32_t>::max()) {
15673af6ab5fSopenharmony_ci        return static_cast<int32_t>(num);
15683af6ab5fSopenharmony_ci    }
15693af6ab5fSopenharmony_ci
15703af6ab5fSopenharmony_ci    // NOTE (aszilagyi): Perform ECMA defined toInt conversion
15713af6ab5fSopenharmony_ci
15723af6ab5fSopenharmony_ci    return 0;
15733af6ab5fSopenharmony_ci}
15743af6ab5fSopenharmony_ci
15753af6ab5fSopenharmony_civarbinder::EnumMemberResult GetOperationResulForDouble(lexer::TokenType type, varbinder::EnumMemberResult left,
15763af6ab5fSopenharmony_ci                                                       varbinder::EnumMemberResult right)
15773af6ab5fSopenharmony_ci{
15783af6ab5fSopenharmony_ci    switch (type) {
15793af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_OR: {
15803af6ab5fSopenharmony_ci            return static_cast<double>(ToUInt(std::get<double>(left)) | ToUInt(std::get<double>(right)));
15813af6ab5fSopenharmony_ci        }
15823af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_AND: {
15833af6ab5fSopenharmony_ci            return static_cast<double>(ToUInt(std::get<double>(left)) & ToUInt(std::get<double>(right)));
15843af6ab5fSopenharmony_ci        }
15853af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: {
15863af6ab5fSopenharmony_ci            return static_cast<double>(ToUInt(std::get<double>(left)) ^ ToUInt(std::get<double>(right)));
15873af6ab5fSopenharmony_ci        }
15883af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: {  // NOLINTNEXTLINE(hicpp-signed-bitwise)
15893af6ab5fSopenharmony_ci            return static_cast<double>(ToInt(std::get<double>(left)) << ToUInt(std::get<double>(right)));
15903af6ab5fSopenharmony_ci        }
15913af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: {  // NOLINTNEXTLINE(hicpp-signed-bitwise)
15923af6ab5fSopenharmony_ci            return static_cast<double>(ToInt(std::get<double>(left)) >> ToUInt(std::get<double>(right)));
15933af6ab5fSopenharmony_ci        }
15943af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: {
15953af6ab5fSopenharmony_ci            return static_cast<double>(ToUInt(std::get<double>(left)) >> ToUInt(std::get<double>(right)));
15963af6ab5fSopenharmony_ci        }
15973af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_PLUS: {
15983af6ab5fSopenharmony_ci            return std::get<double>(left) + std::get<double>(right);
15993af6ab5fSopenharmony_ci        }
16003af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MINUS: {
16013af6ab5fSopenharmony_ci            return std::get<double>(left) - std::get<double>(right);
16023af6ab5fSopenharmony_ci        }
16033af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MULTIPLY: {
16043af6ab5fSopenharmony_ci            return std::get<double>(left) * std::get<double>(right);
16053af6ab5fSopenharmony_ci        }
16063af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_DIVIDE: {
16073af6ab5fSopenharmony_ci            return std::get<double>(left) / std::get<double>(right);
16083af6ab5fSopenharmony_ci        }
16093af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MOD: {
16103af6ab5fSopenharmony_ci            return std::fmod(std::get<double>(left), std::get<double>(right));
16113af6ab5fSopenharmony_ci        }
16123af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: {
16133af6ab5fSopenharmony_ci            return std::pow(std::get<double>(left), std::get<double>(right));
16143af6ab5fSopenharmony_ci        }
16153af6ab5fSopenharmony_ci        default: {
16163af6ab5fSopenharmony_ci            return false;
16173af6ab5fSopenharmony_ci        }
16183af6ab5fSopenharmony_ci    }
16193af6ab5fSopenharmony_ci}
16203af6ab5fSopenharmony_ci
16213af6ab5fSopenharmony_civarbinder::EnumMemberResult TSAnalyzer::EvaluateBinaryExpression(checker::TSChecker *checker,
16223af6ab5fSopenharmony_ci                                                                 varbinder::EnumVariable *enumVar,
16233af6ab5fSopenharmony_ci                                                                 const ir::BinaryExpression *expr) const
16243af6ab5fSopenharmony_ci{
16253af6ab5fSopenharmony_ci    varbinder::EnumMemberResult left = EvaluateEnumMember(checker, enumVar, expr->AsBinaryExpression()->Left());
16263af6ab5fSopenharmony_ci    varbinder::EnumMemberResult right = EvaluateEnumMember(checker, enumVar, expr->AsBinaryExpression()->Right());
16273af6ab5fSopenharmony_ci    if (std::holds_alternative<double>(left) && std::holds_alternative<double>(right)) {
16283af6ab5fSopenharmony_ci        GetOperationResulForDouble(expr->AsBinaryExpression()->OperatorType(), left, right);
16293af6ab5fSopenharmony_ci    }
16303af6ab5fSopenharmony_ci
16313af6ab5fSopenharmony_ci    if (std::holds_alternative<util::StringView>(left) && std::holds_alternative<util::StringView>(right) &&
16323af6ab5fSopenharmony_ci        expr->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS) {
16333af6ab5fSopenharmony_ci        std::stringstream ss;
16343af6ab5fSopenharmony_ci        ss << std::get<util::StringView>(left) << std::get<util::StringView>(right);
16353af6ab5fSopenharmony_ci
16363af6ab5fSopenharmony_ci        util::UString res(ss.str(), checker->Allocator());
16373af6ab5fSopenharmony_ci        return res.View();
16383af6ab5fSopenharmony_ci    }
16393af6ab5fSopenharmony_ci
16403af6ab5fSopenharmony_ci    return false;
16413af6ab5fSopenharmony_ci}
16423af6ab5fSopenharmony_ci
16433af6ab5fSopenharmony_civarbinder::EnumMemberResult TSAnalyzer::EvaluateUnaryExpression(checker::TSChecker *checker,
16443af6ab5fSopenharmony_ci                                                                varbinder::EnumVariable *enumVar,
16453af6ab5fSopenharmony_ci                                                                const ir::UnaryExpression *expr) const
16463af6ab5fSopenharmony_ci{
16473af6ab5fSopenharmony_ci    varbinder::EnumMemberResult value = EvaluateEnumMember(checker, enumVar, expr->Argument());
16483af6ab5fSopenharmony_ci    if (!std::holds_alternative<double>(value)) {
16493af6ab5fSopenharmony_ci        return false;
16503af6ab5fSopenharmony_ci    }
16513af6ab5fSopenharmony_ci
16523af6ab5fSopenharmony_ci    switch (expr->OperatorType()) {
16533af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_PLUS: {
16543af6ab5fSopenharmony_ci            return std::get<double>(value);
16553af6ab5fSopenharmony_ci        }
16563af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_MINUS: {
16573af6ab5fSopenharmony_ci            return -std::get<double>(value);
16583af6ab5fSopenharmony_ci        }
16593af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_TILDE: {
16603af6ab5fSopenharmony_ci            return static_cast<double>(~ToInt(std::get<double>(value)));  // NOLINT(hicpp-signed-bitwise)
16613af6ab5fSopenharmony_ci        }
16623af6ab5fSopenharmony_ci        default: {
16633af6ab5fSopenharmony_ci            break;
16643af6ab5fSopenharmony_ci        }
16653af6ab5fSopenharmony_ci    }
16663af6ab5fSopenharmony_ci
16673af6ab5fSopenharmony_ci    return false;
16683af6ab5fSopenharmony_ci}
16693af6ab5fSopenharmony_ci
16703af6ab5fSopenharmony_civarbinder::EnumMemberResult TSAnalyzer::EvaluateEnumMember(checker::TSChecker *checker,
16713af6ab5fSopenharmony_ci                                                           varbinder::EnumVariable *enumVar,
16723af6ab5fSopenharmony_ci                                                           const ir::AstNode *expr) const
16733af6ab5fSopenharmony_ci{
16743af6ab5fSopenharmony_ci    switch (expr->Type()) {
16753af6ab5fSopenharmony_ci        case ir::AstNodeType::UNARY_EXPRESSION: {
16763af6ab5fSopenharmony_ci            return EvaluateUnaryExpression(checker, enumVar, expr->AsUnaryExpression());
16773af6ab5fSopenharmony_ci        }
16783af6ab5fSopenharmony_ci        case ir::AstNodeType::BINARY_EXPRESSION: {
16793af6ab5fSopenharmony_ci            return EvaluateBinaryExpression(checker, enumVar, expr->AsBinaryExpression());
16803af6ab5fSopenharmony_ci        }
16813af6ab5fSopenharmony_ci        case ir::AstNodeType::NUMBER_LITERAL: {
16823af6ab5fSopenharmony_ci            return expr->AsNumberLiteral()->Number().GetDouble();
16833af6ab5fSopenharmony_ci        }
16843af6ab5fSopenharmony_ci        case ir::AstNodeType::STRING_LITERAL: {
16853af6ab5fSopenharmony_ci            return expr->AsStringLiteral()->Str();
16863af6ab5fSopenharmony_ci        }
16873af6ab5fSopenharmony_ci        case ir::AstNodeType::IDENTIFIER: {
16883af6ab5fSopenharmony_ci            return EvaluateIdentifier(checker, enumVar, expr->AsIdentifier());
16893af6ab5fSopenharmony_ci        }
16903af6ab5fSopenharmony_ci        case ir::AstNodeType::MEMBER_EXPRESSION: {
16913af6ab5fSopenharmony_ci            return EvaluateEnumMember(checker, enumVar, expr->AsMemberExpression());
16923af6ab5fSopenharmony_ci        }
16933af6ab5fSopenharmony_ci        default:
16943af6ab5fSopenharmony_ci            break;
16953af6ab5fSopenharmony_ci    }
16963af6ab5fSopenharmony_ci
16973af6ab5fSopenharmony_ci    return false;
16983af6ab5fSopenharmony_ci}
16993af6ab5fSopenharmony_ci
17003af6ab5fSopenharmony_cistatic bool IsComputedEnumMember(const ir::Expression *init)
17013af6ab5fSopenharmony_ci{
17023af6ab5fSopenharmony_ci    if (init->IsLiteral()) {
17033af6ab5fSopenharmony_ci        return !init->AsLiteral()->IsStringLiteral() && !init->AsLiteral()->IsNumberLiteral();
17043af6ab5fSopenharmony_ci    }
17053af6ab5fSopenharmony_ci
17063af6ab5fSopenharmony_ci    if (init->IsTemplateLiteral()) {
17073af6ab5fSopenharmony_ci        return !init->AsTemplateLiteral()->Quasis().empty();
17083af6ab5fSopenharmony_ci    }
17093af6ab5fSopenharmony_ci
17103af6ab5fSopenharmony_ci    return true;
17113af6ab5fSopenharmony_ci}
17123af6ab5fSopenharmony_ci
17133af6ab5fSopenharmony_cistatic void AddEnumValueDeclaration(checker::TSChecker *checker, double number, varbinder::EnumVariable *variable)
17143af6ab5fSopenharmony_ci{
17153af6ab5fSopenharmony_ci    variable->SetTsType(checker->GlobalNumberType());
17163af6ab5fSopenharmony_ci
17173af6ab5fSopenharmony_ci    util::StringView memberStr = util::Helpers::ToStringView(checker->Allocator(), number);
17183af6ab5fSopenharmony_ci
17193af6ab5fSopenharmony_ci    varbinder::LocalScope *enumScope = checker->Scope()->AsLocalScope();
17203af6ab5fSopenharmony_ci    varbinder::Variable *res = enumScope->FindLocal(memberStr, varbinder::ResolveBindingOptions::BINDINGS);
17213af6ab5fSopenharmony_ci    varbinder::EnumVariable *enumVar = nullptr;
17223af6ab5fSopenharmony_ci
17233af6ab5fSopenharmony_ci    if (res == nullptr) {
17243af6ab5fSopenharmony_ci        auto *decl = checker->Allocator()->New<varbinder::EnumDecl>(memberStr);
17253af6ab5fSopenharmony_ci        decl->BindNode(variable->Declaration()->Node());
17263af6ab5fSopenharmony_ci        enumScope->AddDecl(checker->Allocator(), decl, ScriptExtension::TS);
17273af6ab5fSopenharmony_ci        res = enumScope->FindLocal(memberStr, varbinder::ResolveBindingOptions::BINDINGS);
17283af6ab5fSopenharmony_ci        ASSERT(res && res->IsEnumVariable());
17293af6ab5fSopenharmony_ci        enumVar = res->AsEnumVariable();
17303af6ab5fSopenharmony_ci        enumVar->AsEnumVariable()->SetBackReference();
17313af6ab5fSopenharmony_ci        enumVar->SetTsType(checker->GlobalStringType());
17323af6ab5fSopenharmony_ci    } else {
17333af6ab5fSopenharmony_ci        ASSERT(res->IsEnumVariable());
17343af6ab5fSopenharmony_ci        enumVar = res->AsEnumVariable();
17353af6ab5fSopenharmony_ci        auto *decl = checker->Allocator()->New<varbinder::EnumDecl>(memberStr);
17363af6ab5fSopenharmony_ci        decl->BindNode(variable->Declaration()->Node());
17373af6ab5fSopenharmony_ci        enumVar->ResetDecl(decl);
17383af6ab5fSopenharmony_ci    }
17393af6ab5fSopenharmony_ci
17403af6ab5fSopenharmony_ci    enumVar->SetValue(variable->Declaration()->Name());
17413af6ab5fSopenharmony_ci}
17423af6ab5fSopenharmony_ci
17433af6ab5fSopenharmony_ci// NOLINTBEGIN(modernize-avoid-c-arrays)
17443af6ab5fSopenharmony_cistatic constexpr char const INVALID_COMPUTED_WITH_STRING[] =
17453af6ab5fSopenharmony_ci    "Computed values are not permitted in an enum with string valued members.";
17463af6ab5fSopenharmony_cistatic constexpr char const INVALID_CONST_MEMBER[] =
17473af6ab5fSopenharmony_ci    "'const' enum member initializers can only contain literal values and other computed enum values.";
17483af6ab5fSopenharmony_cistatic constexpr char const INVALID_CONST_NAN[] =
17493af6ab5fSopenharmony_ci    "'const' enum member initializer was evaluated to disallowed value 'NaN'.";
17503af6ab5fSopenharmony_cistatic constexpr char const INVALID_CONST_INF[] =
17513af6ab5fSopenharmony_ci    "'const' enum member initializer was evaluated to a non-finite value.";
17523af6ab5fSopenharmony_ci// NOLINTEND(modernize-avoid-c-arrays)
17533af6ab5fSopenharmony_ci
17543af6ab5fSopenharmony_civoid TSAnalyzer::InferEnumVariableType(varbinder::EnumVariable *variable, double *value, bool *initNext,
17553af6ab5fSopenharmony_ci                                       bool *isLiteralEnum, bool isConstEnum) const
17563af6ab5fSopenharmony_ci{
17573af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
17583af6ab5fSopenharmony_ci    const ir::Expression *init = variable->Declaration()->Node()->AsTSEnumMember()->Init();
17593af6ab5fSopenharmony_ci
17603af6ab5fSopenharmony_ci    if (init == nullptr && *initNext) {
17613af6ab5fSopenharmony_ci        checker->ThrowTypeError("Enum member must have initializer.", variable->Declaration()->Node()->Start());
17623af6ab5fSopenharmony_ci    }
17633af6ab5fSopenharmony_ci
17643af6ab5fSopenharmony_ci    if (init == nullptr && !*initNext) {
17653af6ab5fSopenharmony_ci        variable->SetValue(++(*value));
17663af6ab5fSopenharmony_ci        AddEnumValueDeclaration(checker, *value, variable);
17673af6ab5fSopenharmony_ci        return;
17683af6ab5fSopenharmony_ci    }
17693af6ab5fSopenharmony_ci
17703af6ab5fSopenharmony_ci    ASSERT(init);
17713af6ab5fSopenharmony_ci    if (IsComputedEnumMember(init) && *isLiteralEnum) {
17723af6ab5fSopenharmony_ci        checker->ThrowTypeError(INVALID_COMPUTED_WITH_STRING, init->Start());
17733af6ab5fSopenharmony_ci    }
17743af6ab5fSopenharmony_ci
17753af6ab5fSopenharmony_ci    varbinder::EnumMemberResult res = EvaluateEnumMember(checker, variable, init);
17763af6ab5fSopenharmony_ci    if (std::holds_alternative<util::StringView>(res)) {
17773af6ab5fSopenharmony_ci        *isLiteralEnum = true;
17783af6ab5fSopenharmony_ci        variable->SetTsType(checker->GlobalStringType());
17793af6ab5fSopenharmony_ci        *initNext = true;
17803af6ab5fSopenharmony_ci        return;
17813af6ab5fSopenharmony_ci    }
17823af6ab5fSopenharmony_ci
17833af6ab5fSopenharmony_ci    if (std::holds_alternative<bool>(res)) {
17843af6ab5fSopenharmony_ci        if (isConstEnum) {
17853af6ab5fSopenharmony_ci            checker->ThrowTypeError(INVALID_CONST_MEMBER, init->Start());
17863af6ab5fSopenharmony_ci        }
17873af6ab5fSopenharmony_ci
17883af6ab5fSopenharmony_ci        *initNext = true;
17893af6ab5fSopenharmony_ci        return;
17903af6ab5fSopenharmony_ci    }
17913af6ab5fSopenharmony_ci
17923af6ab5fSopenharmony_ci    ASSERT(std::holds_alternative<double>(res));
17933af6ab5fSopenharmony_ci    variable->SetValue(res);
17943af6ab5fSopenharmony_ci
17953af6ab5fSopenharmony_ci    *value = std::get<double>(res);
17963af6ab5fSopenharmony_ci    if (isConstEnum && std::isnan(*value)) {
17973af6ab5fSopenharmony_ci        checker->ThrowTypeError(INVALID_CONST_NAN, init->Start());
17983af6ab5fSopenharmony_ci    }
17993af6ab5fSopenharmony_ci
18003af6ab5fSopenharmony_ci    if (isConstEnum && std::isinf(*value)) {
18013af6ab5fSopenharmony_ci        checker->ThrowTypeError(INVALID_CONST_INF, init->Start());
18023af6ab5fSopenharmony_ci    }
18033af6ab5fSopenharmony_ci
18043af6ab5fSopenharmony_ci    *initNext = false;
18053af6ab5fSopenharmony_ci    AddEnumValueDeclaration(checker, *value, variable);
18063af6ab5fSopenharmony_ci}
18073af6ab5fSopenharmony_ci
18083af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::InferType(checker::TSChecker *checker, bool isConst, ir::TSEnumDeclaration *st) const
18093af6ab5fSopenharmony_ci{
18103af6ab5fSopenharmony_ci    double value = -1.0;
18113af6ab5fSopenharmony_ci
18123af6ab5fSopenharmony_ci    varbinder::LocalScope *enumScope = checker->Scope()->AsLocalScope();
18133af6ab5fSopenharmony_ci
18143af6ab5fSopenharmony_ci    bool initNext = false;
18153af6ab5fSopenharmony_ci    bool isLiteralEnum = false;
18163af6ab5fSopenharmony_ci    size_t localsSize = enumScope->Decls().size();
18173af6ab5fSopenharmony_ci
18183af6ab5fSopenharmony_ci    for (size_t i = 0; i < localsSize; i++) {
18193af6ab5fSopenharmony_ci        const util::StringView &currentName = enumScope->Decls()[i]->Name();
18203af6ab5fSopenharmony_ci        varbinder::Variable *currentVar = enumScope->FindLocal(currentName, varbinder::ResolveBindingOptions::BINDINGS);
18213af6ab5fSopenharmony_ci        ASSERT(currentVar && currentVar->IsEnumVariable());
18223af6ab5fSopenharmony_ci        InferEnumVariableType(currentVar->AsEnumVariable(), &value, &initNext, &isLiteralEnum, isConst);
18233af6ab5fSopenharmony_ci    }
18243af6ab5fSopenharmony_ci
18253af6ab5fSopenharmony_ci    checker::Type *enumType = checker->Allocator()->New<checker::EnumLiteralType>(
18263af6ab5fSopenharmony_ci        st->Key()->Name(), checker->Scope(),
18273af6ab5fSopenharmony_ci        isLiteralEnum ? checker::EnumLiteralType::EnumLiteralTypeKind::LITERAL
18283af6ab5fSopenharmony_ci                      : checker::EnumLiteralType::EnumLiteralTypeKind::NUMERIC);
18293af6ab5fSopenharmony_ci
18303af6ab5fSopenharmony_ci    return enumType;
18313af6ab5fSopenharmony_ci}
18323af6ab5fSopenharmony_ci
18333af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSEnumDeclaration *st) const
18343af6ab5fSopenharmony_ci{
18353af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
18363af6ab5fSopenharmony_ci    varbinder::Variable *enumVar = st->Key()->Variable();
18373af6ab5fSopenharmony_ci    ASSERT(enumVar);
18383af6ab5fSopenharmony_ci
18393af6ab5fSopenharmony_ci    if (enumVar->TsType() == nullptr) {
18403af6ab5fSopenharmony_ci        checker::ScopeContext scopeCtx(checker, st->Scope());
18413af6ab5fSopenharmony_ci        checker::Type *enumType = InferType(checker, st->IsConst(), st);
18423af6ab5fSopenharmony_ci        enumType->SetVariable(enumVar);
18433af6ab5fSopenharmony_ci        enumVar->SetTsType(enumType);
18443af6ab5fSopenharmony_ci    }
18453af6ab5fSopenharmony_ci
18463af6ab5fSopenharmony_ci    return nullptr;
18473af6ab5fSopenharmony_ci}
18483af6ab5fSopenharmony_ci
18493af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSFunctionType *node) const
18503af6ab5fSopenharmony_ci{
18513af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
18523af6ab5fSopenharmony_ci    checker::ScopeContext scopeCtx(checker, node->Scope());
18533af6ab5fSopenharmony_ci
18543af6ab5fSopenharmony_ci    auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
18553af6ab5fSopenharmony_ci    checker->CheckFunctionParameterDeclarations(node->Params(), signatureInfo);
18563af6ab5fSopenharmony_ci    node->ReturnType()->Check(checker);
18573af6ab5fSopenharmony_ci    auto *callSignature =
18583af6ab5fSopenharmony_ci        checker->Allocator()->New<checker::Signature>(signatureInfo, node->ReturnType()->GetType(checker));
18593af6ab5fSopenharmony_ci
18603af6ab5fSopenharmony_ci    return checker->CreateFunctionTypeWithSignature(callSignature);
18613af6ab5fSopenharmony_ci}
18623af6ab5fSopenharmony_ci
18633af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSIndexedAccessType *node) const
18643af6ab5fSopenharmony_ci{
18653af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
18663af6ab5fSopenharmony_ci    node->objectType_->Check(checker);
18673af6ab5fSopenharmony_ci    node->indexType_->Check(checker);
18683af6ab5fSopenharmony_ci    checker::Type *resolved = node->GetType(checker);
18693af6ab5fSopenharmony_ci
18703af6ab5fSopenharmony_ci    if (resolved != nullptr) {
18713af6ab5fSopenharmony_ci        return nullptr;
18723af6ab5fSopenharmony_ci    }
18733af6ab5fSopenharmony_ci
18743af6ab5fSopenharmony_ci    checker::Type *indexType = checker->CheckTypeCached(node->indexType_);
18753af6ab5fSopenharmony_ci
18763af6ab5fSopenharmony_ci    if (!indexType->HasTypeFlag(checker::TypeFlag::STRING_LIKE | checker::TypeFlag::NUMBER_LIKE)) {
18773af6ab5fSopenharmony_ci        checker->ThrowTypeError({"Type ", indexType, " cannot be used as index type"}, node->IndexType()->Start());
18783af6ab5fSopenharmony_ci    }
18793af6ab5fSopenharmony_ci
18803af6ab5fSopenharmony_ci    if (indexType->IsNumberType()) {
18813af6ab5fSopenharmony_ci        checker->ThrowTypeError("Type has no matching signature for type 'number'", node->Start());
18823af6ab5fSopenharmony_ci    }
18833af6ab5fSopenharmony_ci
18843af6ab5fSopenharmony_ci    checker->ThrowTypeError("Type has no matching signature for type 'string'", node->Start());
18853af6ab5fSopenharmony_ci    return nullptr;
18863af6ab5fSopenharmony_ci}
18873af6ab5fSopenharmony_ci
18883af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSInterfaceBody *expr) const
18893af6ab5fSopenharmony_ci{
18903af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
18913af6ab5fSopenharmony_ci    for (auto *it : expr->Body()) {
18923af6ab5fSopenharmony_ci        it->Check(checker);
18933af6ab5fSopenharmony_ci    }
18943af6ab5fSopenharmony_ci
18953af6ab5fSopenharmony_ci    return nullptr;
18963af6ab5fSopenharmony_ci}
18973af6ab5fSopenharmony_ci
18983af6ab5fSopenharmony_cistatic void CheckInheritedPropertiesAreIdentical(checker::TSChecker *checker, checker::InterfaceType *type,
18993af6ab5fSopenharmony_ci                                                 const lexer::SourcePosition &locInfo)
19003af6ab5fSopenharmony_ci{
19013af6ab5fSopenharmony_ci    checker->GetBaseTypes(type);
19023af6ab5fSopenharmony_ci
19033af6ab5fSopenharmony_ci    size_t constexpr BASE_SIZE_LIMIT = 2;
19043af6ab5fSopenharmony_ci    if (type->Bases().size() < BASE_SIZE_LIMIT) {
19053af6ab5fSopenharmony_ci        return;
19063af6ab5fSopenharmony_ci    }
19073af6ab5fSopenharmony_ci
19083af6ab5fSopenharmony_ci    checker->ResolveDeclaredMembers(type);
19093af6ab5fSopenharmony_ci
19103af6ab5fSopenharmony_ci    checker::InterfacePropertyMap properties;
19113af6ab5fSopenharmony_ci
19123af6ab5fSopenharmony_ci    for (auto *it : type->Properties()) {
19133af6ab5fSopenharmony_ci        properties.insert({it->Name(), {it, type}});
19143af6ab5fSopenharmony_ci    }
19153af6ab5fSopenharmony_ci
19163af6ab5fSopenharmony_ci    for (auto *base : type->Bases()) {
19173af6ab5fSopenharmony_ci        checker->ResolveStructuredTypeMembers(base);
19183af6ab5fSopenharmony_ci        ArenaVector<varbinder::LocalVariable *> inheritedProperties(checker->Allocator()->Adapter());
19193af6ab5fSopenharmony_ci        base->AsInterfaceType()->CollectProperties(&inheritedProperties);
19203af6ab5fSopenharmony_ci
19213af6ab5fSopenharmony_ci        for (auto *inheritedProp : inheritedProperties) {
19223af6ab5fSopenharmony_ci            auto res = properties.find(inheritedProp->Name());
19233af6ab5fSopenharmony_ci            if (res == properties.end()) {
19243af6ab5fSopenharmony_ci                properties.insert({inheritedProp->Name(), {inheritedProp, base->AsInterfaceType()}});
19253af6ab5fSopenharmony_ci            } else if (res->second.second != type) {
19263af6ab5fSopenharmony_ci                checker::Type *sourceType = checker->GetTypeOfVariable(inheritedProp);
19273af6ab5fSopenharmony_ci                checker::Type *targetType = checker->GetTypeOfVariable(res->second.first);
19283af6ab5fSopenharmony_ci                checker->IsTypeIdenticalTo(sourceType, targetType,
19293af6ab5fSopenharmony_ci                                           {"Interface '", type, "' cannot simultaneously extend types '",
19303af6ab5fSopenharmony_ci                                            res->second.second, "' and '", base->AsInterfaceType(), "'."},
19313af6ab5fSopenharmony_ci                                           locInfo);
19323af6ab5fSopenharmony_ci            }
19333af6ab5fSopenharmony_ci        }
19343af6ab5fSopenharmony_ci    }
19353af6ab5fSopenharmony_ci}
19363af6ab5fSopenharmony_ci
19373af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSInterfaceDeclaration *st) const
19383af6ab5fSopenharmony_ci{
19393af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
19403af6ab5fSopenharmony_ci    varbinder::Variable *var = st->Id()->Variable();
19413af6ab5fSopenharmony_ci    ASSERT(var->Declaration()->Node() && var->Declaration()->Node()->IsTSInterfaceDeclaration());
19423af6ab5fSopenharmony_ci
19433af6ab5fSopenharmony_ci    if (st == var->Declaration()->Node()) {
19443af6ab5fSopenharmony_ci        checker::Type *resolvedType = var->TsType();
19453af6ab5fSopenharmony_ci
19463af6ab5fSopenharmony_ci        if (resolvedType == nullptr) {
19473af6ab5fSopenharmony_ci            checker::ObjectDescriptor *desc =
19483af6ab5fSopenharmony_ci                checker->Allocator()->New<checker::ObjectDescriptor>(checker->Allocator());
19493af6ab5fSopenharmony_ci            resolvedType =
19503af6ab5fSopenharmony_ci                checker->Allocator()->New<checker::InterfaceType>(checker->Allocator(), st->Id()->Name(), desc);
19513af6ab5fSopenharmony_ci            resolvedType->SetVariable(var);
19523af6ab5fSopenharmony_ci            var->SetTsType(resolvedType);
19533af6ab5fSopenharmony_ci        }
19543af6ab5fSopenharmony_ci
19553af6ab5fSopenharmony_ci        checker::InterfaceType *resolvedInterface = resolvedType->AsObjectType()->AsInterfaceType();
19563af6ab5fSopenharmony_ci        CheckInheritedPropertiesAreIdentical(checker, resolvedInterface, st->Id()->Start());
19573af6ab5fSopenharmony_ci
19583af6ab5fSopenharmony_ci        for (auto *base : resolvedInterface->Bases()) {
19593af6ab5fSopenharmony_ci            checker->IsTypeAssignableTo(
19603af6ab5fSopenharmony_ci                resolvedInterface, base,
19613af6ab5fSopenharmony_ci                {"Interface '", st->Id()->Name(), "' incorrectly extends interface '", base, "'"}, st->Id()->Start());
19623af6ab5fSopenharmony_ci        }
19633af6ab5fSopenharmony_ci
19643af6ab5fSopenharmony_ci        checker->CheckIndexConstraints(resolvedInterface);
19653af6ab5fSopenharmony_ci    }
19663af6ab5fSopenharmony_ci
19673af6ab5fSopenharmony_ci    st->Body()->Check(checker);
19683af6ab5fSopenharmony_ci
19693af6ab5fSopenharmony_ci    return nullptr;
19703af6ab5fSopenharmony_ci}
19713af6ab5fSopenharmony_ci
19723af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSLiteralType *node) const
19733af6ab5fSopenharmony_ci{
19743af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
19753af6ab5fSopenharmony_ci    node->GetType(checker);
19763af6ab5fSopenharmony_ci    return nullptr;
19773af6ab5fSopenharmony_ci}
19783af6ab5fSopenharmony_ci
19793af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSNamedTupleMember *node) const
19803af6ab5fSopenharmony_ci{
19813af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
19823af6ab5fSopenharmony_ci    node->ElementType()->Check(checker);
19833af6ab5fSopenharmony_ci    return nullptr;
19843af6ab5fSopenharmony_ci}
19853af6ab5fSopenharmony_ci
19863af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSNeverKeyword *node) const
19873af6ab5fSopenharmony_ci{
19883af6ab5fSopenharmony_ci    return nullptr;
19893af6ab5fSopenharmony_ci}
19903af6ab5fSopenharmony_ci
19913af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSNullKeyword *node) const
19923af6ab5fSopenharmony_ci{
19933af6ab5fSopenharmony_ci    return nullptr;
19943af6ab5fSopenharmony_ci}
19953af6ab5fSopenharmony_ci
19963af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSNumberKeyword *node) const
19973af6ab5fSopenharmony_ci{
19983af6ab5fSopenharmony_ci    return nullptr;
19993af6ab5fSopenharmony_ci}
20003af6ab5fSopenharmony_ci
20013af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSParenthesizedType *node) const
20023af6ab5fSopenharmony_ci{
20033af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
20043af6ab5fSopenharmony_ci    node->type_->Check(checker);
20053af6ab5fSopenharmony_ci    return nullptr;
20063af6ab5fSopenharmony_ci}
20073af6ab5fSopenharmony_ci
20083af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSQualifiedName *expr) const
20093af6ab5fSopenharmony_ci{
20103af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
20113af6ab5fSopenharmony_ci    checker::Type *baseType = checker->CheckNonNullType(expr->Left()->Check(checker), expr->Left()->Start());
20123af6ab5fSopenharmony_ci    varbinder::Variable *prop = checker->GetPropertyOfType(baseType, expr->Right()->Name());
20133af6ab5fSopenharmony_ci
20143af6ab5fSopenharmony_ci    if (prop != nullptr) {
20153af6ab5fSopenharmony_ci        return checker->GetTypeOfVariable(prop);
20163af6ab5fSopenharmony_ci    }
20173af6ab5fSopenharmony_ci
20183af6ab5fSopenharmony_ci    if (baseType->IsObjectType()) {
20193af6ab5fSopenharmony_ci        checker::ObjectType *objType = baseType->AsObjectType();
20203af6ab5fSopenharmony_ci
20213af6ab5fSopenharmony_ci        if (objType->StringIndexInfo() != nullptr) {
20223af6ab5fSopenharmony_ci            return objType->StringIndexInfo()->GetType();
20233af6ab5fSopenharmony_ci        }
20243af6ab5fSopenharmony_ci    }
20253af6ab5fSopenharmony_ci
20263af6ab5fSopenharmony_ci    checker->ThrowTypeError({"Property ", expr->Right()->Name(), " does not exist on this type."},
20273af6ab5fSopenharmony_ci                            expr->Right()->Start());
20283af6ab5fSopenharmony_ci    return nullptr;
20293af6ab5fSopenharmony_ci}
20303af6ab5fSopenharmony_ci
20313af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSStringKeyword *node) const
20323af6ab5fSopenharmony_ci{
20333af6ab5fSopenharmony_ci    return nullptr;
20343af6ab5fSopenharmony_ci}
20353af6ab5fSopenharmony_ci
20363af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSTupleType *node) const
20373af6ab5fSopenharmony_ci{
20383af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
20393af6ab5fSopenharmony_ci    for (auto *it : node->ElementType()) {
20403af6ab5fSopenharmony_ci        it->Check(checker);
20413af6ab5fSopenharmony_ci    }
20423af6ab5fSopenharmony_ci
20433af6ab5fSopenharmony_ci    node->GetType(checker);
20443af6ab5fSopenharmony_ci    return nullptr;
20453af6ab5fSopenharmony_ci}
20463af6ab5fSopenharmony_ci
20473af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSTypeAliasDeclaration *st) const
20483af6ab5fSopenharmony_ci{
20493af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
20503af6ab5fSopenharmony_ci    st->TypeAnnotation()->Check(checker);
20513af6ab5fSopenharmony_ci    return nullptr;
20523af6ab5fSopenharmony_ci}
20533af6ab5fSopenharmony_ci
20543af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSTypeLiteral *node) const
20553af6ab5fSopenharmony_ci{
20563af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
20573af6ab5fSopenharmony_ci
20583af6ab5fSopenharmony_ci    for (auto *it : node->Members()) {
20593af6ab5fSopenharmony_ci        it->Check(checker);
20603af6ab5fSopenharmony_ci    }
20613af6ab5fSopenharmony_ci
20623af6ab5fSopenharmony_ci    checker::Type *type = node->GetType(checker);
20633af6ab5fSopenharmony_ci    checker->CheckIndexConstraints(type);
20643af6ab5fSopenharmony_ci
20653af6ab5fSopenharmony_ci    return nullptr;
20663af6ab5fSopenharmony_ci}
20673af6ab5fSopenharmony_ci
20683af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSTypeQuery *node) const
20693af6ab5fSopenharmony_ci{
20703af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
20713af6ab5fSopenharmony_ci    if (node->TsType() != nullptr) {
20723af6ab5fSopenharmony_ci        return node->TsType();
20733af6ab5fSopenharmony_ci    }
20743af6ab5fSopenharmony_ci
20753af6ab5fSopenharmony_ci    node->SetTsType(node->exprName_->Check(checker));
20763af6ab5fSopenharmony_ci    return node->TsType();
20773af6ab5fSopenharmony_ci}
20783af6ab5fSopenharmony_ci
20793af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSTypeReference *node) const
20803af6ab5fSopenharmony_ci{
20813af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
20823af6ab5fSopenharmony_ci    node->GetType(checker);
20833af6ab5fSopenharmony_ci    return nullptr;
20843af6ab5fSopenharmony_ci}
20853af6ab5fSopenharmony_ci
20863af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSUndefinedKeyword *node) const
20873af6ab5fSopenharmony_ci{
20883af6ab5fSopenharmony_ci    return nullptr;
20893af6ab5fSopenharmony_ci}
20903af6ab5fSopenharmony_ci
20913af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check(ir::TSUnionType *node) const
20923af6ab5fSopenharmony_ci{
20933af6ab5fSopenharmony_ci    TSChecker *checker = GetTSChecker();
20943af6ab5fSopenharmony_ci    for (auto *it : node->Types()) {
20953af6ab5fSopenharmony_ci        it->Check(checker);
20963af6ab5fSopenharmony_ci    }
20973af6ab5fSopenharmony_ci
20983af6ab5fSopenharmony_ci    node->GetType(checker);
20993af6ab5fSopenharmony_ci    return nullptr;
21003af6ab5fSopenharmony_ci}
21013af6ab5fSopenharmony_ci
21023af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSUnknownKeyword *node) const
21033af6ab5fSopenharmony_ci{
21043af6ab5fSopenharmony_ci    return nullptr;
21053af6ab5fSopenharmony_ci}
21063af6ab5fSopenharmony_ci
21073af6ab5fSopenharmony_cichecker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSVoidKeyword *node) const
21083af6ab5fSopenharmony_ci{
21093af6ab5fSopenharmony_ci    return nullptr;
21103af6ab5fSopenharmony_ci}
21113af6ab5fSopenharmony_ci}  // namespace ark::es2panda::checker
2112