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 "util/helpers.h"
173af6ab5fSopenharmony_ci#include "macros.h"
183af6ab5fSopenharmony_ci#include "varbinder/ETSBinder.h"
193af6ab5fSopenharmony_ci#include "parser/ETSparser.h"
203af6ab5fSopenharmony_ci
213af6ab5fSopenharmony_ci#include "checker/types/ets/etsTupleType.h"
223af6ab5fSopenharmony_ci#include "checker/types/ets/etsReadonlyType.h"
233af6ab5fSopenharmony_ci#include "checker/ets/typeRelationContext.h"
243af6ab5fSopenharmony_ci#include "checker/ETSchecker.h"
253af6ab5fSopenharmony_ci#include "checker/types/globalTypesHolder.h"
263af6ab5fSopenharmony_ci#include "evaluate/scopedDebugInfoPlugin.h"
273af6ab5fSopenharmony_ci
283af6ab5fSopenharmony_ci#include "compiler/lowering/scopesInit/scopesInitPhase.h"
293af6ab5fSopenharmony_ci#include "generated/signatures.h"
303af6ab5fSopenharmony_ci
313af6ab5fSopenharmony_cinamespace ark::es2panda::checker {
323af6ab5fSopenharmony_civarbinder::Variable *ETSChecker::FindVariableInFunctionScope(const util::StringView name,
333af6ab5fSopenharmony_ci                                                             const varbinder::ResolveBindingOptions options)
343af6ab5fSopenharmony_ci{
353af6ab5fSopenharmony_ci    return Scope()->FindInFunctionScope(name, options).variable;
363af6ab5fSopenharmony_ci}
373af6ab5fSopenharmony_ci
383af6ab5fSopenharmony_cistd::pair<varbinder::Variable *, const ETSObjectType *> ETSChecker::FindVariableInClassOrEnclosing(
393af6ab5fSopenharmony_ci    const util::StringView name, const ETSObjectType *classType)
403af6ab5fSopenharmony_ci{
413af6ab5fSopenharmony_ci    const auto searchFlags = PropertySearchFlags::SEARCH_ALL | PropertySearchFlags::SEARCH_IN_BASE |
423af6ab5fSopenharmony_ci                             PropertySearchFlags::SEARCH_IN_INTERFACES;
433af6ab5fSopenharmony_ci    auto *resolved = classType->GetProperty(name, searchFlags);
443af6ab5fSopenharmony_ci    while (classType->EnclosingType() != nullptr && resolved == nullptr) {
453af6ab5fSopenharmony_ci        classType = classType->EnclosingType();
463af6ab5fSopenharmony_ci        resolved = classType->GetProperty(name, searchFlags);
473af6ab5fSopenharmony_ci    }
483af6ab5fSopenharmony_ci
493af6ab5fSopenharmony_ci    return {resolved, classType};
503af6ab5fSopenharmony_ci}
513af6ab5fSopenharmony_ci
523af6ab5fSopenharmony_civarbinder::Variable *ETSChecker::FindVariableInGlobal(const ir::Identifier *const identifier,
533af6ab5fSopenharmony_ci                                                      const varbinder::ResolveBindingOptions options)
543af6ab5fSopenharmony_ci{
553af6ab5fSopenharmony_ci    return Scope()->FindInGlobal(identifier->Name(), options).variable;
563af6ab5fSopenharmony_ci}
573af6ab5fSopenharmony_ci
583af6ab5fSopenharmony_cibool ETSChecker::IsVariableStatic(const varbinder::Variable *var)
593af6ab5fSopenharmony_ci{
603af6ab5fSopenharmony_ci    if (var->HasFlag(varbinder::VariableFlags::METHOD)) {
613af6ab5fSopenharmony_ci        return var->TsType()->AsETSFunctionType()->CallSignatures()[0]->HasSignatureFlag(SignatureFlags::STATIC);
623af6ab5fSopenharmony_ci    }
633af6ab5fSopenharmony_ci    return var->HasFlag(varbinder::VariableFlags::STATIC);
643af6ab5fSopenharmony_ci}
653af6ab5fSopenharmony_ci
663af6ab5fSopenharmony_cibool ETSChecker::IsVariableGetterSetter(const varbinder::Variable *var)
673af6ab5fSopenharmony_ci{
683af6ab5fSopenharmony_ci    return var->TsTypeOrError() != nullptr && var->TsTypeOrError()->HasTypeFlag(TypeFlag::GETTER_SETTER);
693af6ab5fSopenharmony_ci}
703af6ab5fSopenharmony_ci
713af6ab5fSopenharmony_civoid ETSChecker::LogUnResolvedError(ir::Identifier *const ident)
723af6ab5fSopenharmony_ci{
733af6ab5fSopenharmony_ci    LogTypeError({"Unresolved reference ", ident->Name()}, ident->Start());
743af6ab5fSopenharmony_ci}
753af6ab5fSopenharmony_ci
763af6ab5fSopenharmony_civoid ETSChecker::WrongContextErrorClassifyByType(ir::Identifier *ident, varbinder::Variable *const resolved)
773af6ab5fSopenharmony_ci{
783af6ab5fSopenharmony_ci    std::string identCategoryName;
793af6ab5fSopenharmony_ci    switch (static_cast<varbinder::VariableFlags>(
803af6ab5fSopenharmony_ci        resolved->Flags() &
813af6ab5fSopenharmony_ci        (varbinder::VariableFlags::CLASS_OR_INTERFACE_OR_ENUM | varbinder::VariableFlags::METHOD))) {
823af6ab5fSopenharmony_ci        case varbinder::VariableFlags::CLASS: {
833af6ab5fSopenharmony_ci            identCategoryName = "Class";
843af6ab5fSopenharmony_ci            break;
853af6ab5fSopenharmony_ci        }
863af6ab5fSopenharmony_ci        case varbinder::VariableFlags::METHOD: {
873af6ab5fSopenharmony_ci            identCategoryName = "Function";
883af6ab5fSopenharmony_ci            break;
893af6ab5fSopenharmony_ci        }
903af6ab5fSopenharmony_ci        case varbinder::VariableFlags::INTERFACE: {
913af6ab5fSopenharmony_ci            identCategoryName = "Interface";
923af6ab5fSopenharmony_ci            break;
933af6ab5fSopenharmony_ci        }
943af6ab5fSopenharmony_ci        case varbinder::VariableFlags::ENUM_LITERAL: {
953af6ab5fSopenharmony_ci            identCategoryName = "Enum";
963af6ab5fSopenharmony_ci            break;
973af6ab5fSopenharmony_ci        }
983af6ab5fSopenharmony_ci        default: {
993af6ab5fSopenharmony_ci            LogUnResolvedError(ident);
1003af6ab5fSopenharmony_ci            return;
1013af6ab5fSopenharmony_ci        }
1023af6ab5fSopenharmony_ci    }
1033af6ab5fSopenharmony_ci    LogTypeError({identCategoryName.c_str(), " name \"", ident->Name(), "\" used in the wrong context"},
1043af6ab5fSopenharmony_ci                 ident->Start());
1053af6ab5fSopenharmony_ci}
1063af6ab5fSopenharmony_ci
1073af6ab5fSopenharmony_civoid ETSChecker::NotResolvedError(ir::Identifier *const ident, const varbinder::Variable *classVar,
1083af6ab5fSopenharmony_ci                                  const ETSObjectType *classType)
1093af6ab5fSopenharmony_ci{
1103af6ab5fSopenharmony_ci    if (classVar == nullptr) {
1113af6ab5fSopenharmony_ci        LogUnResolvedError(ident);
1123af6ab5fSopenharmony_ci        return;
1133af6ab5fSopenharmony_ci    }
1143af6ab5fSopenharmony_ci
1153af6ab5fSopenharmony_ci    if (IsVariableStatic(classVar)) {
1163af6ab5fSopenharmony_ci        LogTypeError(
1173af6ab5fSopenharmony_ci            {"Static property '", ident->Name(), "' must be accessed through it's class '", classType->Name(), "'"},
1183af6ab5fSopenharmony_ci            ident->Start());
1193af6ab5fSopenharmony_ci    } else {
1203af6ab5fSopenharmony_ci        LogTypeError({"Property '", ident->Name(), "' must be accessed through 'this'"}, ident->Start());
1213af6ab5fSopenharmony_ci    }
1223af6ab5fSopenharmony_ci}
1233af6ab5fSopenharmony_ci
1243af6ab5fSopenharmony_cistd::pair<const ir::Identifier *, ir::TypeNode *> ETSChecker::GetTargetIdentifierAndType(ir::Identifier *const ident)
1253af6ab5fSopenharmony_ci{
1263af6ab5fSopenharmony_ci    if (ident->Parent()->IsClassProperty()) {
1273af6ab5fSopenharmony_ci        const auto *const classProp = ident->Parent()->AsClassProperty();
1283af6ab5fSopenharmony_ci        ASSERT(classProp->Value() && classProp->Value() == ident);
1293af6ab5fSopenharmony_ci        return std::make_pair(classProp->Key()->AsIdentifier(), classProp->TypeAnnotation());
1303af6ab5fSopenharmony_ci    }
1313af6ab5fSopenharmony_ci    const auto *const variableDecl = ident->Parent()->AsVariableDeclarator();
1323af6ab5fSopenharmony_ci    ASSERT(variableDecl->Init() && variableDecl->Init() == ident);
1333af6ab5fSopenharmony_ci    return std::make_pair(variableDecl->Id()->AsIdentifier(), variableDecl->Id()->AsIdentifier()->TypeAnnotation());
1343af6ab5fSopenharmony_ci}
1353af6ab5fSopenharmony_ci
1363af6ab5fSopenharmony_civarbinder::Variable *ETSChecker::ExtraCheckForResolvedError(ir::Identifier *const ident)
1373af6ab5fSopenharmony_ci{
1383af6ab5fSopenharmony_ci    const auto [class_var, class_type] = FindVariableInClassOrEnclosing(ident->Name(), Context().ContainingClass());
1393af6ab5fSopenharmony_ci    auto *parentClass = FindAncestorGivenByType(ident, ir::AstNodeType::CLASS_DEFINITION);
1403af6ab5fSopenharmony_ci    if (parentClass != nullptr && parentClass->AsClassDefinition()->IsLocal()) {
1413af6ab5fSopenharmony_ci        if (parentClass != class_type->GetDeclNode()) {
1423af6ab5fSopenharmony_ci            LogTypeError({"Property '", ident->Name(), "' of enclosing class '", class_type->Name(),
1433af6ab5fSopenharmony_ci                          "' is not allowed to be captured from the local class '",
1443af6ab5fSopenharmony_ci                          parentClass->AsClassDefinition()->Ident()->Name(), "'"},
1453af6ab5fSopenharmony_ci                         ident->Start());
1463af6ab5fSopenharmony_ci        }
1473af6ab5fSopenharmony_ci    }
1483af6ab5fSopenharmony_ci    NotResolvedError(ident, class_var, class_type);
1493af6ab5fSopenharmony_ci    return class_var;
1503af6ab5fSopenharmony_ci}
1513af6ab5fSopenharmony_ci
1523af6ab5fSopenharmony_cibool ETSChecker::SaveCapturedVariableInLocalClass(varbinder::Variable *const var, ir::Identifier *ident)
1533af6ab5fSopenharmony_ci{
1543af6ab5fSopenharmony_ci    const auto &pos = ident->Start();
1553af6ab5fSopenharmony_ci
1563af6ab5fSopenharmony_ci    if (!HasStatus(CheckerStatus::IN_LOCAL_CLASS)) {
1573af6ab5fSopenharmony_ci        return false;
1583af6ab5fSopenharmony_ci    }
1593af6ab5fSopenharmony_ci
1603af6ab5fSopenharmony_ci    if (!var->HasFlag(varbinder::VariableFlags::LOCAL)) {
1613af6ab5fSopenharmony_ci        return false;
1623af6ab5fSopenharmony_ci    }
1633af6ab5fSopenharmony_ci
1643af6ab5fSopenharmony_ci    LOG(DEBUG, ES2PANDA) << "Checking variable (line:" << pos.line << "): " << var->Name();
1653af6ab5fSopenharmony_ci    auto *scopeIter = Scope();
1663af6ab5fSopenharmony_ci    bool inStaticMethod = false;
1673af6ab5fSopenharmony_ci
1683af6ab5fSopenharmony_ci    auto captureVariable = [this, var, ident, &scopeIter, &inStaticMethod, &pos]() {
1693af6ab5fSopenharmony_ci        if (inStaticMethod) {
1703af6ab5fSopenharmony_ci            LogTypeError({"Not allowed to capture variable '", var->Name(), "' in static method"}, pos);
1713af6ab5fSopenharmony_ci            return false;
1723af6ab5fSopenharmony_ci        }
1733af6ab5fSopenharmony_ci        if (scopeIter->Node()->AsClassDefinition()->CaptureVariable(var)) {
1743af6ab5fSopenharmony_ci            LOG(DEBUG, ES2PANDA) << "  Captured in class:" << scopeIter->Node()->AsClassDefinition()->Ident()->Name();
1753af6ab5fSopenharmony_ci        }
1763af6ab5fSopenharmony_ci
1773af6ab5fSopenharmony_ci        auto *parent = ident->Parent();
1783af6ab5fSopenharmony_ci
1793af6ab5fSopenharmony_ci        if (parent->IsVariableDeclarator()) {
1803af6ab5fSopenharmony_ci            parent = parent->Parent()->Parent();
1813af6ab5fSopenharmony_ci        }
1823af6ab5fSopenharmony_ci
1833af6ab5fSopenharmony_ci        if (!(parent->IsUpdateExpression() ||
1843af6ab5fSopenharmony_ci              (parent->IsAssignmentExpression() && parent->AsAssignmentExpression()->Left() == ident)) ||
1853af6ab5fSopenharmony_ci            var->Declaration() == nullptr) {
1863af6ab5fSopenharmony_ci            return false;
1873af6ab5fSopenharmony_ci        }
1883af6ab5fSopenharmony_ci
1893af6ab5fSopenharmony_ci        if (var->Declaration()->IsParameterDecl()) {
1903af6ab5fSopenharmony_ci            LOG(DEBUG, ES2PANDA) << "    - Modified parameter ";
1913af6ab5fSopenharmony_ci            scopeIter->Node()->AsClassDefinition()->AddToLocalVariableIsNeeded(var);
1923af6ab5fSopenharmony_ci        }
1933af6ab5fSopenharmony_ci        return true;
1943af6ab5fSopenharmony_ci    };
1953af6ab5fSopenharmony_ci
1963af6ab5fSopenharmony_ci    while (scopeIter != var->GetScope()) {
1973af6ab5fSopenharmony_ci        if (scopeIter->Node() != nullptr) {
1983af6ab5fSopenharmony_ci            if (scopeIter->Node()->IsScriptFunction() && scopeIter->Node()->AsScriptFunction()->IsStatic()) {
1993af6ab5fSopenharmony_ci                inStaticMethod = true;
2003af6ab5fSopenharmony_ci            }
2013af6ab5fSopenharmony_ci
2023af6ab5fSopenharmony_ci            if (scopeIter->Node()->IsClassDefinition()) {
2033af6ab5fSopenharmony_ci                captureVariable();
2043af6ab5fSopenharmony_ci                return true;
2053af6ab5fSopenharmony_ci            }
2063af6ab5fSopenharmony_ci        }
2073af6ab5fSopenharmony_ci        scopeIter = scopeIter->Parent();
2083af6ab5fSopenharmony_ci    }
2093af6ab5fSopenharmony_ci
2103af6ab5fSopenharmony_ci    return false;
2113af6ab5fSopenharmony_ci}
2123af6ab5fSopenharmony_ci
2133af6ab5fSopenharmony_civoid ETSChecker::SaveCapturedVariable(varbinder::Variable *const var, ir::Identifier *ident)
2143af6ab5fSopenharmony_ci{
2153af6ab5fSopenharmony_ci    const auto &pos = ident->Start();
2163af6ab5fSopenharmony_ci
2173af6ab5fSopenharmony_ci    if (!HasStatus(CheckerStatus::IN_LAMBDA)) {
2183af6ab5fSopenharmony_ci        return;
2193af6ab5fSopenharmony_ci    }
2203af6ab5fSopenharmony_ci
2213af6ab5fSopenharmony_ci    if (var->HasFlag(varbinder::VariableFlags::PROPERTY)) {
2223af6ab5fSopenharmony_ci        Context().AddCapturedVar(var, pos);
2233af6ab5fSopenharmony_ci        return;
2243af6ab5fSopenharmony_ci    }
2253af6ab5fSopenharmony_ci
2263af6ab5fSopenharmony_ci    if ((!var->HasFlag(varbinder::VariableFlags::LOCAL) && !var->HasFlag(varbinder::VariableFlags::METHOD)) ||
2273af6ab5fSopenharmony_ci        Context().ContainingLambda()->IsVarFromSubscope(var)) {
2283af6ab5fSopenharmony_ci        return;
2293af6ab5fSopenharmony_ci    }
2303af6ab5fSopenharmony_ci
2313af6ab5fSopenharmony_ci    const auto *scopeIter = Scope();
2323af6ab5fSopenharmony_ci    while (scopeIter != var->GetScope()) {
2333af6ab5fSopenharmony_ci        if (scopeIter->IsFunctionScope()) {
2343af6ab5fSopenharmony_ci            Context().AddCapturedVar(var, pos);
2353af6ab5fSopenharmony_ci            return;
2363af6ab5fSopenharmony_ci        }
2373af6ab5fSopenharmony_ci        scopeIter = scopeIter->Parent();
2383af6ab5fSopenharmony_ci    }
2393af6ab5fSopenharmony_ci}
2403af6ab5fSopenharmony_ci
2413af6ab5fSopenharmony_ciType *ETSChecker::ResolveIdentifier(ir::Identifier *ident)
2423af6ab5fSopenharmony_ci{
2433af6ab5fSopenharmony_ci    if (ident->Variable() != nullptr) {
2443af6ab5fSopenharmony_ci        auto *const resolved = ident->Variable();
2453af6ab5fSopenharmony_ci        SaveCapturedVariable(resolved, ident);
2463af6ab5fSopenharmony_ci        return GetTypeOfVariable(resolved);
2473af6ab5fSopenharmony_ci    }
2483af6ab5fSopenharmony_ci
2493af6ab5fSopenharmony_ci    auto options = ident->Parent()->IsTSTypeAliasDeclaration() ? varbinder::ResolveBindingOptions::TYPE_ALIASES
2503af6ab5fSopenharmony_ci                                                               : varbinder::ResolveBindingOptions::ALL_NON_TYPE;
2513af6ab5fSopenharmony_ci
2523af6ab5fSopenharmony_ci    auto *resolved = FindVariableInFunctionScope(ident->Name(), options);
2533af6ab5fSopenharmony_ci    if (resolved == nullptr) {
2543af6ab5fSopenharmony_ci        // If the reference is not found already in the current class, then it is not bound to the class, so we have to
2553af6ab5fSopenharmony_ci        // find the reference in the global class first, then in the global scope
2563af6ab5fSopenharmony_ci        resolved = FindVariableInGlobal(ident, options);
2573af6ab5fSopenharmony_ci        if (UNLIKELY(resolved == nullptr && debugInfoPlugin_ != nullptr)) {
2583af6ab5fSopenharmony_ci            resolved = debugInfoPlugin_->FindIdentifier(ident);
2593af6ab5fSopenharmony_ci        }
2603af6ab5fSopenharmony_ci    }
2613af6ab5fSopenharmony_ci
2623af6ab5fSopenharmony_ci    if (resolved == nullptr) {
2633af6ab5fSopenharmony_ci        resolved = ExtraCheckForResolvedError(ident);
2643af6ab5fSopenharmony_ci        ident->SetVariable(resolved);
2653af6ab5fSopenharmony_ci        if (resolved == nullptr) {
2663af6ab5fSopenharmony_ci            return GlobalTypeError();
2673af6ab5fSopenharmony_ci        }
2683af6ab5fSopenharmony_ci        return GetTypeOfVariable(resolved);
2693af6ab5fSopenharmony_ci    }
2703af6ab5fSopenharmony_ci
2713af6ab5fSopenharmony_ci    ident->SetVariable(resolved);
2723af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
2733af6ab5fSopenharmony_ci    ValidateResolvedIdentifier(ident, resolved);
2743af6ab5fSopenharmony_ci
2753af6ab5fSopenharmony_ci    ValidatePropertyAccess(resolved, Context().ContainingClass(), ident->Start());
2763af6ab5fSopenharmony_ci    SaveCapturedVariable(resolved, ident);
2773af6ab5fSopenharmony_ci
2783af6ab5fSopenharmony_ci    return GetTypeOfVariable(resolved);
2793af6ab5fSopenharmony_ci}
2803af6ab5fSopenharmony_ci
2813af6ab5fSopenharmony_cistd::tuple<Type *, bool> ETSChecker::ApplyBinaryOperatorPromotion(Type *left, Type *right, TypeFlag test,
2823af6ab5fSopenharmony_ci                                                                  bool const doPromotion)
2833af6ab5fSopenharmony_ci{
2843af6ab5fSopenharmony_ci    Type *const unboxedL = ETSBuiltinTypeAsPrimitiveType(left);
2853af6ab5fSopenharmony_ci    Type *const unboxedR = ETSBuiltinTypeAsPrimitiveType(right);
2863af6ab5fSopenharmony_ci
2873af6ab5fSopenharmony_ci    if (unboxedL == nullptr || unboxedR == nullptr) {
2883af6ab5fSopenharmony_ci        return {nullptr, false};
2893af6ab5fSopenharmony_ci    }
2903af6ab5fSopenharmony_ci
2913af6ab5fSopenharmony_ci    if (!unboxedL->HasTypeFlag(test) || !unboxedR->HasTypeFlag(test)) {
2923af6ab5fSopenharmony_ci        return {nullptr, false};
2933af6ab5fSopenharmony_ci    }
2943af6ab5fSopenharmony_ci
2953af6ab5fSopenharmony_ci    bool const bothConst = unboxedL->HasTypeFlag(TypeFlag::CONSTANT) && unboxedR->HasTypeFlag(TypeFlag::CONSTANT);
2963af6ab5fSopenharmony_ci
2973af6ab5fSopenharmony_ci    // extract just to reduce nested levels
2983af6ab5fSopenharmony_ci    auto const numericPromotion = [this, unboxedL, unboxedR, bothConst]() -> std::tuple<checker::Type *, bool> {
2993af6ab5fSopenharmony_ci        if (unboxedL->IsDoubleType() || unboxedR->IsDoubleType()) {
3003af6ab5fSopenharmony_ci            return {GlobalDoubleType(), bothConst};
3013af6ab5fSopenharmony_ci        }
3023af6ab5fSopenharmony_ci
3033af6ab5fSopenharmony_ci        if (unboxedL->IsFloatType() || unboxedR->IsFloatType()) {
3043af6ab5fSopenharmony_ci            return {GlobalFloatType(), bothConst};
3053af6ab5fSopenharmony_ci        }
3063af6ab5fSopenharmony_ci
3073af6ab5fSopenharmony_ci        if (unboxedL->IsLongType() || unboxedR->IsLongType()) {
3083af6ab5fSopenharmony_ci            return {GlobalLongType(), bothConst};
3093af6ab5fSopenharmony_ci        }
3103af6ab5fSopenharmony_ci
3113af6ab5fSopenharmony_ci        if (unboxedL->IsCharType() && unboxedR->IsCharType()) {
3123af6ab5fSopenharmony_ci            return {GlobalCharType(), bothConst};
3133af6ab5fSopenharmony_ci        }
3143af6ab5fSopenharmony_ci
3153af6ab5fSopenharmony_ci        return {GlobalIntType(), bothConst};
3163af6ab5fSopenharmony_ci    };
3173af6ab5fSopenharmony_ci
3183af6ab5fSopenharmony_ci    if (doPromotion) {
3193af6ab5fSopenharmony_ci        if (unboxedL->HasTypeFlag(TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) &&
3203af6ab5fSopenharmony_ci            unboxedR->HasTypeFlag(TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) {
3213af6ab5fSopenharmony_ci            return numericPromotion();
3223af6ab5fSopenharmony_ci        }
3233af6ab5fSopenharmony_ci
3243af6ab5fSopenharmony_ci        if (IsTypeIdenticalTo(unboxedL, unboxedR)) {
3253af6ab5fSopenharmony_ci            return {unboxedL, bothConst};
3263af6ab5fSopenharmony_ci        }
3273af6ab5fSopenharmony_ci    }
3283af6ab5fSopenharmony_ci
3293af6ab5fSopenharmony_ci    return {unboxedR, bothConst};
3303af6ab5fSopenharmony_ci}
3313af6ab5fSopenharmony_ci
3323af6ab5fSopenharmony_cistd::optional<checker::Type *> CheckLeftRightType(checker::ETSChecker *checker, checker::Type *unboxedL,
3333af6ab5fSopenharmony_ci                                                  checker::Type *unboxedR)
3343af6ab5fSopenharmony_ci{
3353af6ab5fSopenharmony_ci    if (unboxedL->IsDoubleType() || unboxedR->IsDoubleType()) {
3363af6ab5fSopenharmony_ci        return checker->GlobalDoubleType();
3373af6ab5fSopenharmony_ci    }
3383af6ab5fSopenharmony_ci    if (unboxedL->IsFloatType() || unboxedR->IsFloatType()) {
3393af6ab5fSopenharmony_ci        return checker->GlobalFloatType();
3403af6ab5fSopenharmony_ci    }
3413af6ab5fSopenharmony_ci    if (unboxedL->IsLongType() || unboxedR->IsLongType()) {
3423af6ab5fSopenharmony_ci        return checker->GlobalLongType();
3433af6ab5fSopenharmony_ci    }
3443af6ab5fSopenharmony_ci    if (unboxedL->IsIntType() || unboxedR->IsIntType() || unboxedL->IsCharType() || unboxedR->IsCharType()) {
3453af6ab5fSopenharmony_ci        return checker->GlobalIntType();
3463af6ab5fSopenharmony_ci    }
3473af6ab5fSopenharmony_ci    if (unboxedL->IsShortType() || unboxedR->IsShortType()) {
3483af6ab5fSopenharmony_ci        return checker->GlobalShortType();
3493af6ab5fSopenharmony_ci    }
3503af6ab5fSopenharmony_ci    if (unboxedL->IsByteType() || unboxedR->IsByteType()) {
3513af6ab5fSopenharmony_ci        return checker->GlobalByteType();
3523af6ab5fSopenharmony_ci    }
3533af6ab5fSopenharmony_ci    return std::nullopt;
3543af6ab5fSopenharmony_ci}
3553af6ab5fSopenharmony_cichecker::Type *ETSChecker::ApplyConditionalOperatorPromotion(checker::ETSChecker *checker, checker::Type *unboxedL,
3563af6ab5fSopenharmony_ci                                                             checker::Type *unboxedR)
3573af6ab5fSopenharmony_ci{
3583af6ab5fSopenharmony_ci    if ((unboxedL->HasTypeFlag(checker::TypeFlag::CONSTANT) && unboxedL->IsIntType()) ||
3593af6ab5fSopenharmony_ci        (unboxedR->HasTypeFlag(checker::TypeFlag::CONSTANT) && unboxedR->IsIntType())) {
3603af6ab5fSopenharmony_ci        int value = unboxedL->IsIntType() ? unboxedL->AsIntType()->GetValue() : unboxedR->AsIntType()->GetValue();
3613af6ab5fSopenharmony_ci        checker::Type *otherType = !unboxedL->IsIntType() ? unboxedL : unboxedR;
3623af6ab5fSopenharmony_ci
3633af6ab5fSopenharmony_ci        switch (checker::ETSChecker::ETSType(otherType)) {
3643af6ab5fSopenharmony_ci            case checker::TypeFlag::BYTE:
3653af6ab5fSopenharmony_ci            case checker::TypeFlag::CHAR: {
3663af6ab5fSopenharmony_ci                if (value <= static_cast<int>(std::numeric_limits<char>::max()) &&
3673af6ab5fSopenharmony_ci                    value >= static_cast<int>(std::numeric_limits<char>::min())) {
3683af6ab5fSopenharmony_ci                    return checker->GetNonConstantType(otherType);
3693af6ab5fSopenharmony_ci                }
3703af6ab5fSopenharmony_ci                break;
3713af6ab5fSopenharmony_ci            }
3723af6ab5fSopenharmony_ci            case checker::TypeFlag::SHORT: {
3733af6ab5fSopenharmony_ci                if (value <= std::numeric_limits<int16_t>::max() && value >= std::numeric_limits<int16_t>::min()) {
3743af6ab5fSopenharmony_ci                    return checker->GlobalShortType();
3753af6ab5fSopenharmony_ci                }
3763af6ab5fSopenharmony_ci                break;
3773af6ab5fSopenharmony_ci            }
3783af6ab5fSopenharmony_ci            default: {
3793af6ab5fSopenharmony_ci                return otherType;
3803af6ab5fSopenharmony_ci            }
3813af6ab5fSopenharmony_ci        }
3823af6ab5fSopenharmony_ci        return checker->GlobalIntType();
3833af6ab5fSopenharmony_ci    }
3843af6ab5fSopenharmony_ci
3853af6ab5fSopenharmony_ci    auto checkLeftRight = CheckLeftRightType(checker, unboxedL, unboxedR);
3863af6ab5fSopenharmony_ci    if (checkLeftRight.has_value()) {
3873af6ab5fSopenharmony_ci        return checkLeftRight.value();
3883af6ab5fSopenharmony_ci    }
3893af6ab5fSopenharmony_ci    UNREACHABLE();
3903af6ab5fSopenharmony_ci}
3913af6ab5fSopenharmony_ci
3923af6ab5fSopenharmony_ciType *ETSChecker::ApplyUnaryOperatorPromotion(Type *type, const bool createConst, const bool doPromotion,
3933af6ab5fSopenharmony_ci                                              const bool isCondExpr)
3943af6ab5fSopenharmony_ci{
3953af6ab5fSopenharmony_ci    Type *unboxedType = isCondExpr ? ETSBuiltinTypeAsConditionalType(type) : ETSBuiltinTypeAsPrimitiveType(type);
3963af6ab5fSopenharmony_ci
3973af6ab5fSopenharmony_ci    if (unboxedType == nullptr) {
3983af6ab5fSopenharmony_ci        return nullptr;
3993af6ab5fSopenharmony_ci    }
4003af6ab5fSopenharmony_ci    if (doPromotion) {
4013af6ab5fSopenharmony_ci        switch (ETSType(unboxedType)) {
4023af6ab5fSopenharmony_ci            case TypeFlag::BYTE:
4033af6ab5fSopenharmony_ci            case TypeFlag::SHORT:
4043af6ab5fSopenharmony_ci            case TypeFlag::CHAR: {
4053af6ab5fSopenharmony_ci                if (!createConst) {
4063af6ab5fSopenharmony_ci                    return GlobalIntType();
4073af6ab5fSopenharmony_ci                }
4083af6ab5fSopenharmony_ci
4093af6ab5fSopenharmony_ci                return CreateIntTypeFromType(unboxedType);
4103af6ab5fSopenharmony_ci            }
4113af6ab5fSopenharmony_ci            default: {
4123af6ab5fSopenharmony_ci                break;
4133af6ab5fSopenharmony_ci            }
4143af6ab5fSopenharmony_ci        }
4153af6ab5fSopenharmony_ci    }
4163af6ab5fSopenharmony_ci    return unboxedType;
4173af6ab5fSopenharmony_ci}
4183af6ab5fSopenharmony_ci
4193af6ab5fSopenharmony_cibool ETSChecker::IsNullLikeOrVoidExpression(const ir::Expression *expr) const
4203af6ab5fSopenharmony_ci{
4213af6ab5fSopenharmony_ci    return expr->TsType()->DefinitelyETSNullish() || expr->TsType()->IsETSVoidType();
4223af6ab5fSopenharmony_ci}
4233af6ab5fSopenharmony_ci
4243af6ab5fSopenharmony_cistd::tuple<bool, bool> ETSChecker::IsResolvedAndValue(const ir::Expression *expr, Type *type) const
4253af6ab5fSopenharmony_ci{
4263af6ab5fSopenharmony_ci    auto [isResolve, isValue] =
4273af6ab5fSopenharmony_ci        IsNullLikeOrVoidExpression(expr) ? std::make_tuple(true, false) : type->ResolveConditionExpr();
4283af6ab5fSopenharmony_ci
4293af6ab5fSopenharmony_ci    const Type *tsType = expr->TsType();
4303af6ab5fSopenharmony_ci    if (tsType->DefinitelyNotETSNullish() && !type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
4313af6ab5fSopenharmony_ci        isResolve = true;
4323af6ab5fSopenharmony_ci        isValue = true;
4333af6ab5fSopenharmony_ci    }
4343af6ab5fSopenharmony_ci    return std::make_tuple(isResolve, isValue);
4353af6ab5fSopenharmony_ci}
4363af6ab5fSopenharmony_ci
4373af6ab5fSopenharmony_ciType *ETSChecker::HandleBooleanLogicalOperatorsExtended(Type *leftType, Type *rightType, ir::BinaryExpression *expr)
4383af6ab5fSopenharmony_ci{
4393af6ab5fSopenharmony_ci    ASSERT(leftType->IsConditionalExprType() && rightType->IsConditionalExprType());
4403af6ab5fSopenharmony_ci
4413af6ab5fSopenharmony_ci    auto [resolveLeft, leftValue] = IsResolvedAndValue(expr->Left(), leftType);
4423af6ab5fSopenharmony_ci    auto [resolveRight, rightValue] = IsResolvedAndValue(expr->Right(), rightType);
4433af6ab5fSopenharmony_ci
4443af6ab5fSopenharmony_ci    if (!resolveLeft && !resolveRight && IsTypeIdenticalTo(leftType, rightType)) {
4453af6ab5fSopenharmony_ci        return leftType;
4463af6ab5fSopenharmony_ci    }
4473af6ab5fSopenharmony_ci
4483af6ab5fSopenharmony_ci    switch (expr->OperatorType()) {
4493af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
4503af6ab5fSopenharmony_ci            if (leftValue) {
4513af6ab5fSopenharmony_ci                expr->SetResult(expr->Left());
4523af6ab5fSopenharmony_ci                return leftType->IsETSBooleanType() ? CreateETSBooleanType(true) : leftType;
4533af6ab5fSopenharmony_ci            }
4543af6ab5fSopenharmony_ci
4553af6ab5fSopenharmony_ci            expr->SetResult(expr->Right());
4563af6ab5fSopenharmony_ci            return rightType->IsETSBooleanType() && resolveRight ? CreateETSBooleanType(rightValue) : rightType;
4573af6ab5fSopenharmony_ci        }
4583af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
4593af6ab5fSopenharmony_ci            if (leftValue) {
4603af6ab5fSopenharmony_ci                expr->SetResult(expr->Right());
4613af6ab5fSopenharmony_ci                return rightType->IsETSBooleanType() && resolveRight ? CreateETSBooleanType(rightValue) : rightType;
4623af6ab5fSopenharmony_ci            }
4633af6ab5fSopenharmony_ci
4643af6ab5fSopenharmony_ci            expr->SetResult(expr->Left());
4653af6ab5fSopenharmony_ci            return leftType->IsETSBooleanType() ? CreateETSBooleanType(false) : leftType;
4663af6ab5fSopenharmony_ci        }
4673af6ab5fSopenharmony_ci        default: {
4683af6ab5fSopenharmony_ci            break;
4693af6ab5fSopenharmony_ci        }
4703af6ab5fSopenharmony_ci    }
4713af6ab5fSopenharmony_ci
4723af6ab5fSopenharmony_ci    UNREACHABLE();
4733af6ab5fSopenharmony_ci}
4743af6ab5fSopenharmony_ci
4753af6ab5fSopenharmony_ciType *ETSChecker::HandleBooleanLogicalOperators(Type *leftType, Type *rightType, lexer::TokenType tokenType)
4763af6ab5fSopenharmony_ci{
4773af6ab5fSopenharmony_ci    using UType = typename ETSBooleanType::UType;
4783af6ab5fSopenharmony_ci    ASSERT(leftType->IsETSBooleanType() && rightType->IsETSBooleanType());
4793af6ab5fSopenharmony_ci
4803af6ab5fSopenharmony_ci    if (!leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) || !rightType->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
4813af6ab5fSopenharmony_ci        return GlobalETSBooleanType();
4823af6ab5fSopenharmony_ci    }
4833af6ab5fSopenharmony_ci
4843af6ab5fSopenharmony_ci    UType leftValue = leftType->AsETSBooleanType()->GetValue();
4853af6ab5fSopenharmony_ci    UType rightValue = rightType->AsETSBooleanType()->GetValue();
4863af6ab5fSopenharmony_ci
4873af6ab5fSopenharmony_ci    switch (tokenType) {
4883af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: {
4893af6ab5fSopenharmony_ci            return CreateETSBooleanType(leftValue ^ rightValue);
4903af6ab5fSopenharmony_ci        }
4913af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_AND: {
4923af6ab5fSopenharmony_ci            return CreateETSBooleanType((static_cast<uint8_t>(leftValue) & static_cast<uint8_t>(rightValue)) != 0);
4933af6ab5fSopenharmony_ci        }
4943af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_BITWISE_OR: {
4953af6ab5fSopenharmony_ci            return CreateETSBooleanType((static_cast<uint8_t>(leftValue) | static_cast<uint8_t>(rightValue)) != 0);
4963af6ab5fSopenharmony_ci        }
4973af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
4983af6ab5fSopenharmony_ci            return CreateETSBooleanType(leftValue || rightValue);
4993af6ab5fSopenharmony_ci        }
5003af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
5013af6ab5fSopenharmony_ci            return CreateETSBooleanType(leftValue && rightValue);
5023af6ab5fSopenharmony_ci        }
5033af6ab5fSopenharmony_ci        default: {
5043af6ab5fSopenharmony_ci            break;
5053af6ab5fSopenharmony_ci        }
5063af6ab5fSopenharmony_ci    }
5073af6ab5fSopenharmony_ci
5083af6ab5fSopenharmony_ci    UNREACHABLE();
5093af6ab5fSopenharmony_ci    return nullptr;
5103af6ab5fSopenharmony_ci}
5113af6ab5fSopenharmony_ci
5123af6ab5fSopenharmony_civoid ETSChecker::ResolveReturnStatement(checker::Type *funcReturnType, checker::Type *argumentType,
5133af6ab5fSopenharmony_ci                                        ir::ScriptFunction *containingFunc, ir::ReturnStatement *st)
5143af6ab5fSopenharmony_ci{
5153af6ab5fSopenharmony_ci    if (funcReturnType->IsETSReferenceType() || argumentType->IsETSReferenceType()) {
5163af6ab5fSopenharmony_ci        // function return type should be of reference (object) type
5173af6ab5fSopenharmony_ci        Relation()->SetFlags(checker::TypeRelationFlag::NONE);
5183af6ab5fSopenharmony_ci
5193af6ab5fSopenharmony_ci        if (!argumentType->IsETSReferenceType()) {
5203af6ab5fSopenharmony_ci            argumentType = PrimitiveTypeAsETSBuiltinType(argumentType);
5213af6ab5fSopenharmony_ci            if (argumentType == nullptr) {
5223af6ab5fSopenharmony_ci                LogTypeError("Invalid return statement expression", st->Argument()->Start());
5233af6ab5fSopenharmony_ci            } else {
5243af6ab5fSopenharmony_ci                st->Argument()->AddBoxingUnboxingFlags(GetBoxingFlag(argumentType));
5253af6ab5fSopenharmony_ci            }
5263af6ab5fSopenharmony_ci        }
5273af6ab5fSopenharmony_ci
5283af6ab5fSopenharmony_ci        if (!funcReturnType->IsETSReferenceType()) {
5293af6ab5fSopenharmony_ci            funcReturnType = PrimitiveTypeAsETSBuiltinType(funcReturnType);
5303af6ab5fSopenharmony_ci            if (funcReturnType == nullptr) {
5313af6ab5fSopenharmony_ci                LogTypeError("Invalid return function expression", st->Start());
5323af6ab5fSopenharmony_ci            }
5333af6ab5fSopenharmony_ci        }
5343af6ab5fSopenharmony_ci        if (argumentType != nullptr && funcReturnType != nullptr) {
5353af6ab5fSopenharmony_ci            funcReturnType = CreateETSUnionType({funcReturnType, argumentType});
5363af6ab5fSopenharmony_ci            containingFunc->Signature()->SetReturnType(funcReturnType);
5373af6ab5fSopenharmony_ci            containingFunc->Signature()->AddSignatureFlag(checker::SignatureFlags::INFERRED_RETURN_TYPE);
5383af6ab5fSopenharmony_ci        }
5393af6ab5fSopenharmony_ci    } else if (funcReturnType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE_RETURN) &&
5403af6ab5fSopenharmony_ci               argumentType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE_RETURN)) {
5413af6ab5fSopenharmony_ci        // function return type is of primitive type (including enums):
5423af6ab5fSopenharmony_ci        Relation()->SetFlags(checker::TypeRelationFlag::DIRECT_RETURN |
5433af6ab5fSopenharmony_ci                             checker::TypeRelationFlag::IN_ASSIGNMENT_CONTEXT |
5443af6ab5fSopenharmony_ci                             checker::TypeRelationFlag::ASSIGNMENT_CONTEXT);
5453af6ab5fSopenharmony_ci        if (Relation()->IsAssignableTo(funcReturnType, argumentType)) {
5463af6ab5fSopenharmony_ci            funcReturnType = argumentType;
5473af6ab5fSopenharmony_ci            containingFunc->Signature()->SetReturnType(funcReturnType);
5483af6ab5fSopenharmony_ci            containingFunc->Signature()->AddSignatureFlag(checker::SignatureFlags::INFERRED_RETURN_TYPE);
5493af6ab5fSopenharmony_ci        } else if (!Relation()->IsAssignableTo(argumentType, funcReturnType)) {
5503af6ab5fSopenharmony_ci            const Type *targetType = TryGettingFunctionTypeFromInvokeFunction(funcReturnType);
5513af6ab5fSopenharmony_ci            const Type *sourceType = TryGettingFunctionTypeFromInvokeFunction(argumentType);
5523af6ab5fSopenharmony_ci
5533af6ab5fSopenharmony_ci            LogTypeError({"Function cannot have different primitive return types, require '", targetType, "', found '",
5543af6ab5fSopenharmony_ci                          sourceType, "'"},
5553af6ab5fSopenharmony_ci                         st->Argument()->Start());
5563af6ab5fSopenharmony_ci        }
5573af6ab5fSopenharmony_ci    } else {
5583af6ab5fSopenharmony_ci        // Should never in this branch.
5593af6ab5fSopenharmony_ci        UNREACHABLE();
5603af6ab5fSopenharmony_ci        return;
5613af6ab5fSopenharmony_ci    }
5623af6ab5fSopenharmony_ci}
5633af6ab5fSopenharmony_ci
5643af6ab5fSopenharmony_cichecker::Type *ETSChecker::CheckArrayElements(ir::ArrayExpression *init)
5653af6ab5fSopenharmony_ci{
5663af6ab5fSopenharmony_ci    ArenaVector<checker::Type *> elementTypes(Allocator()->Adapter());
5673af6ab5fSopenharmony_ci    for (auto e : init->AsArrayExpression()->Elements()) {
5683af6ab5fSopenharmony_ci        elementTypes.push_back(GetNonConstantType(e->Check(this)));
5693af6ab5fSopenharmony_ci    }
5703af6ab5fSopenharmony_ci
5713af6ab5fSopenharmony_ci    if (elementTypes.empty()) {
5723af6ab5fSopenharmony_ci        // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
5733af6ab5fSopenharmony_ci        return Allocator()->New<ETSArrayType>(GlobalETSObjectType());
5743af6ab5fSopenharmony_ci    }
5753af6ab5fSopenharmony_ci    auto const isNumeric = [](checker::Type *ct) { return ct->HasTypeFlag(TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC); };
5763af6ab5fSopenharmony_ci    auto const elementType = std::all_of(elementTypes.begin(), elementTypes.end(), isNumeric)
5773af6ab5fSopenharmony_ci                                 ? GlobalDoubleType()
5783af6ab5fSopenharmony_ci                                 : CreateETSUnionType(std::move(elementTypes));
5793af6ab5fSopenharmony_ci
5803af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
5813af6ab5fSopenharmony_ci    return Allocator()->New<ETSArrayType>(elementType);
5823af6ab5fSopenharmony_ci}
5833af6ab5fSopenharmony_ci
5843af6ab5fSopenharmony_civoid ETSChecker::InferAliasLambdaType(ir::TypeNode *localTypeAnnotation, ir::ArrowFunctionExpression *init)
5853af6ab5fSopenharmony_ci{
5863af6ab5fSopenharmony_ci    ASSERT(localTypeAnnotation != nullptr);
5873af6ab5fSopenharmony_ci
5883af6ab5fSopenharmony_ci    if (localTypeAnnotation->IsETSTypeReference()) {
5893af6ab5fSopenharmony_ci        bool isAnnotationTypeAlias = true;
5903af6ab5fSopenharmony_ci        while (localTypeAnnotation->IsETSTypeReference() && isAnnotationTypeAlias) {
5913af6ab5fSopenharmony_ci            auto *nodeVar = localTypeAnnotation->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Variable();
5923af6ab5fSopenharmony_ci            if (nodeVar == nullptr) {
5933af6ab5fSopenharmony_ci                break;
5943af6ab5fSopenharmony_ci            }
5953af6ab5fSopenharmony_ci
5963af6ab5fSopenharmony_ci            auto *node = nodeVar->Declaration()->Node();
5973af6ab5fSopenharmony_ci
5983af6ab5fSopenharmony_ci            isAnnotationTypeAlias = node->IsTSTypeAliasDeclaration();
5993af6ab5fSopenharmony_ci            if (isAnnotationTypeAlias) {
6003af6ab5fSopenharmony_ci                localTypeAnnotation = node->AsTSTypeAliasDeclaration()->TypeAnnotation();
6013af6ab5fSopenharmony_ci            }
6023af6ab5fSopenharmony_ci        }
6033af6ab5fSopenharmony_ci    }
6043af6ab5fSopenharmony_ci
6053af6ab5fSopenharmony_ci    if (localTypeAnnotation->IsETSFunctionType()) {
6063af6ab5fSopenharmony_ci        auto *const arrowFuncExpr = init;
6073af6ab5fSopenharmony_ci        ir::ScriptFunction *const lambda = arrowFuncExpr->Function();
6083af6ab5fSopenharmony_ci        if (lambda->Params().size() == localTypeAnnotation->AsETSFunctionType()->Params().size() &&
6093af6ab5fSopenharmony_ci            NeedTypeInference(lambda)) {
6103af6ab5fSopenharmony_ci            InferTypesForLambda(lambda, localTypeAnnotation->AsETSFunctionType());
6113af6ab5fSopenharmony_ci        }
6123af6ab5fSopenharmony_ci    }
6133af6ab5fSopenharmony_ci}
6143af6ab5fSopenharmony_ci
6153af6ab5fSopenharmony_cichecker::Type *ETSChecker::FixOptionalVariableType(varbinder::Variable *const bindingVar, ir::ModifierFlags flags,
6163af6ab5fSopenharmony_ci                                                   ir::Expression *init)
6173af6ab5fSopenharmony_ci{
6183af6ab5fSopenharmony_ci    if ((flags & ir::ModifierFlags::OPTIONAL) != 0) {
6193af6ab5fSopenharmony_ci        auto type = bindingVar->TsTypeOrError();
6203af6ab5fSopenharmony_ci        if (init != nullptr && init->TsType()->IsETSEnumType()) {
6213af6ab5fSopenharmony_ci            init->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::BOX_TO_ENUM);
6223af6ab5fSopenharmony_ci        }
6233af6ab5fSopenharmony_ci        if (type->IsETSEnumType()) {
6243af6ab5fSopenharmony_ci            type = type->AsETSEnumType()->GetDecl()->BoxedClass()->TsType();
6253af6ab5fSopenharmony_ci        }
6263af6ab5fSopenharmony_ci        if (type->IsETSUnionType()) {
6273af6ab5fSopenharmony_ci            auto constituentTypes = type->AsETSUnionType()->ConstituentTypes();
6283af6ab5fSopenharmony_ci            constituentTypes.push_back(GlobalETSUndefinedType());
6293af6ab5fSopenharmony_ci            type = CreateETSUnionType(std::move(constituentTypes));
6303af6ab5fSopenharmony_ci        } else {
6313af6ab5fSopenharmony_ci            type = CreateETSUnionType({GlobalETSUndefinedType(), type});
6323af6ab5fSopenharmony_ci        }
6333af6ab5fSopenharmony_ci        bindingVar->SetTsType(type);
6343af6ab5fSopenharmony_ci    }
6353af6ab5fSopenharmony_ci    return bindingVar->TsTypeOrError();
6363af6ab5fSopenharmony_ci}
6373af6ab5fSopenharmony_ci
6383af6ab5fSopenharmony_cichecker::Type *PreferredObjectTypeFromAnnotation(checker::Type *annotationType)
6393af6ab5fSopenharmony_ci{
6403af6ab5fSopenharmony_ci    if (!annotationType->IsETSUnionType()) {
6413af6ab5fSopenharmony_ci        return annotationType;
6423af6ab5fSopenharmony_ci    }
6433af6ab5fSopenharmony_ci
6443af6ab5fSopenharmony_ci    checker::Type *resolvedType = nullptr;
6453af6ab5fSopenharmony_ci    for (auto constituentType : annotationType->AsETSUnionType()->ConstituentTypes()) {
6463af6ab5fSopenharmony_ci        if (constituentType->IsETSObjectType()) {
6473af6ab5fSopenharmony_ci            if (resolvedType != nullptr) {
6483af6ab5fSopenharmony_ci                return nullptr;
6493af6ab5fSopenharmony_ci            }
6503af6ab5fSopenharmony_ci            resolvedType = constituentType;
6513af6ab5fSopenharmony_ci        }
6523af6ab5fSopenharmony_ci    }
6533af6ab5fSopenharmony_ci
6543af6ab5fSopenharmony_ci    return resolvedType;
6553af6ab5fSopenharmony_ci}
6563af6ab5fSopenharmony_ci
6573af6ab5fSopenharmony_cibool ETSChecker::CheckInit(ir::Identifier *ident, ir::TypeNode *typeAnnotation, ir::Expression *init,
6583af6ab5fSopenharmony_ci                           checker::Type *annotationType, varbinder::Variable *const bindingVar)
6593af6ab5fSopenharmony_ci{
6603af6ab5fSopenharmony_ci    if (typeAnnotation == nullptr) {
6613af6ab5fSopenharmony_ci        if (init->IsArrayExpression()) {
6623af6ab5fSopenharmony_ci            annotationType = CheckArrayElements(init->AsArrayExpression());
6633af6ab5fSopenharmony_ci            bindingVar->SetTsType(annotationType);
6643af6ab5fSopenharmony_ci        }
6653af6ab5fSopenharmony_ci
6663af6ab5fSopenharmony_ci        if (init->IsObjectExpression()) {
6673af6ab5fSopenharmony_ci            LogTypeError(
6683af6ab5fSopenharmony_ci                {"Cannot infer type for ", ident->Name(), " because class composite needs an explicit target type"},
6693af6ab5fSopenharmony_ci                ident->Start());
6703af6ab5fSopenharmony_ci            return false;
6713af6ab5fSopenharmony_ci        }
6723af6ab5fSopenharmony_ci    }
6733af6ab5fSopenharmony_ci
6743af6ab5fSopenharmony_ci    if (init->IsMemberExpression() && init->AsMemberExpression()->Object()->IsObjectExpression()) {
6753af6ab5fSopenharmony_ci        LogTypeError({"Class composite must be constructed separately before referring their members."},
6763af6ab5fSopenharmony_ci                     ident->Start());
6773af6ab5fSopenharmony_ci    }
6783af6ab5fSopenharmony_ci
6793af6ab5fSopenharmony_ci    if ((init->IsMemberExpression()) && (annotationType != nullptr)) {
6803af6ab5fSopenharmony_ci        SetArrayPreferredTypeForNestedMemberExpressions(init->AsMemberExpression(), annotationType);
6813af6ab5fSopenharmony_ci    }
6823af6ab5fSopenharmony_ci
6833af6ab5fSopenharmony_ci    if (init->IsArrayExpression() && (annotationType != nullptr) && annotationType->IsETSArrayType()) {
6843af6ab5fSopenharmony_ci        if (annotationType->IsETSTupleType()) {
6853af6ab5fSopenharmony_ci            if (!ValidateTupleMinElementSize(init->AsArrayExpression(), annotationType->AsETSTupleType())) {
6863af6ab5fSopenharmony_ci                return false;
6873af6ab5fSopenharmony_ci            }
6883af6ab5fSopenharmony_ci        }
6893af6ab5fSopenharmony_ci
6903af6ab5fSopenharmony_ci        init->AsArrayExpression()->SetPreferredType(annotationType);
6913af6ab5fSopenharmony_ci    }
6923af6ab5fSopenharmony_ci
6933af6ab5fSopenharmony_ci    if (init->IsObjectExpression()) {
6943af6ab5fSopenharmony_ci        init->AsObjectExpression()->SetPreferredType(PreferredObjectTypeFromAnnotation(annotationType));
6953af6ab5fSopenharmony_ci    }
6963af6ab5fSopenharmony_ci
6973af6ab5fSopenharmony_ci    if (typeAnnotation != nullptr && init->IsArrowFunctionExpression()) {
6983af6ab5fSopenharmony_ci        InferAliasLambdaType(typeAnnotation, init->AsArrowFunctionExpression());
6993af6ab5fSopenharmony_ci    }
7003af6ab5fSopenharmony_ci    return true;
7013af6ab5fSopenharmony_ci}
7023af6ab5fSopenharmony_civoid ETSChecker::CheckEnumType(ir::Expression *init, checker::Type *initType, const util::StringView &varName)
7033af6ab5fSopenharmony_ci{
7043af6ab5fSopenharmony_ci    if (initType->IsETSObjectType() && initType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::ENUM) &&
7053af6ab5fSopenharmony_ci        !init->IsMemberExpression()) {
7063af6ab5fSopenharmony_ci        LogTypeError({"Cannot assign type '", initType->AsETSObjectType()->Name(), "' for variable ", varName, "."},
7073af6ab5fSopenharmony_ci                     init->Start());
7083af6ab5fSopenharmony_ci    }
7093af6ab5fSopenharmony_ci}
7103af6ab5fSopenharmony_ci
7113af6ab5fSopenharmony_cistatic bool NeedWideningBasedOnInitializerHeuristics(ir::Expression *e)
7123af6ab5fSopenharmony_ci{
7133af6ab5fSopenharmony_ci    // NOTE: need to be done by smart casts. Return true if we need to infer wider type.
7143af6ab5fSopenharmony_ci    if (e->IsUnaryExpression()) {
7153af6ab5fSopenharmony_ci        return NeedWideningBasedOnInitializerHeuristics(e->AsUnaryExpression()->Argument());
7163af6ab5fSopenharmony_ci    }
7173af6ab5fSopenharmony_ci    const bool isConstInit = e->IsIdentifier() && e->Variable()->Declaration()->IsConstDecl();
7183af6ab5fSopenharmony_ci    return e->IsConditionalExpression() || e->IsLiteral() || isConstInit;
7193af6ab5fSopenharmony_ci}
7203af6ab5fSopenharmony_ci
7213af6ab5fSopenharmony_cichecker::Type *ETSChecker::CheckVariableDeclaration(ir::Identifier *ident, ir::TypeNode *typeAnnotation,
7223af6ab5fSopenharmony_ci                                                    ir::Expression *init, ir::ModifierFlags const flags)
7233af6ab5fSopenharmony_ci{
7243af6ab5fSopenharmony_ci    const util::StringView &varName = ident->Name();
7253af6ab5fSopenharmony_ci    ASSERT(ident->Variable());
7263af6ab5fSopenharmony_ci    varbinder::Variable *const bindingVar = ident->Variable();
7273af6ab5fSopenharmony_ci    checker::Type *annotationType = nullptr;
7283af6ab5fSopenharmony_ci
7293af6ab5fSopenharmony_ci    const bool isConst = (flags & ir::ModifierFlags::CONST) != 0;
7303af6ab5fSopenharmony_ci    const bool isReadonly = (flags & ir::ModifierFlags::READONLY) != 0;
7313af6ab5fSopenharmony_ci    const bool isStatic = (flags & ir::ModifierFlags::STATIC) != 0;
7323af6ab5fSopenharmony_ci    // Note(lujiahui): It should be checked if the readonly function parameter and readonly number[] parameters
7333af6ab5fSopenharmony_ci    // are assigned with CONSTANT, which would not be correct. (After feature supported)
7343af6ab5fSopenharmony_ci    const bool omitInitConstness = isConst || (isReadonly && isStatic);
7353af6ab5fSopenharmony_ci
7363af6ab5fSopenharmony_ci    if (typeAnnotation != nullptr) {
7373af6ab5fSopenharmony_ci        annotationType = typeAnnotation->GetType(this);
7383af6ab5fSopenharmony_ci        bindingVar->SetTsType(annotationType);
7393af6ab5fSopenharmony_ci    }
7403af6ab5fSopenharmony_ci
7413af6ab5fSopenharmony_ci    if (init == nullptr) {
7423af6ab5fSopenharmony_ci        return FixOptionalVariableType(bindingVar, flags, init);
7433af6ab5fSopenharmony_ci    }
7443af6ab5fSopenharmony_ci
7453af6ab5fSopenharmony_ci    if (!CheckInit(ident, typeAnnotation, init, annotationType, bindingVar)) {
7463af6ab5fSopenharmony_ci        return GlobalTypeError();
7473af6ab5fSopenharmony_ci    }
7483af6ab5fSopenharmony_ci
7493af6ab5fSopenharmony_ci    checker::Type *initType = init->Check(this);
7503af6ab5fSopenharmony_ci
7513af6ab5fSopenharmony_ci    if (initType == nullptr) {
7523af6ab5fSopenharmony_ci        LogTypeError("Cannot get the expression type", init->Start());
7533af6ab5fSopenharmony_ci        return GlobalTypeError();
7543af6ab5fSopenharmony_ci    }
7553af6ab5fSopenharmony_ci
7563af6ab5fSopenharmony_ci    if (typeAnnotation == nullptr && initType->IsETSFunctionType()) {
7573af6ab5fSopenharmony_ci        if (!init->IsArrowFunctionExpression() && (initType->AsETSFunctionType()->CallSignatures().size() != 1)) {
7583af6ab5fSopenharmony_ci            ThrowTypeError("Ambiguous function initialization because of multiple overloads", init->Start());
7593af6ab5fSopenharmony_ci        }
7603af6ab5fSopenharmony_ci
7613af6ab5fSopenharmony_ci        annotationType =
7623af6ab5fSopenharmony_ci            initType->AsETSFunctionType()->FunctionalInterface() == nullptr
7633af6ab5fSopenharmony_ci                ? FunctionTypeToFunctionalInterfaceType(initType->AsETSFunctionType()->CallSignatures().front())
7643af6ab5fSopenharmony_ci                : initType->AsETSFunctionType()->FunctionalInterface();
7653af6ab5fSopenharmony_ci        bindingVar->SetTsType(annotationType);
7663af6ab5fSopenharmony_ci    }
7673af6ab5fSopenharmony_ci
7683af6ab5fSopenharmony_ci    if (annotationType != nullptr) {
7693af6ab5fSopenharmony_ci        CheckAnnotationTypeForVariableDeclaration(annotationType, annotationType->IsETSUnionType(), init, initType);
7703af6ab5fSopenharmony_ci
7713af6ab5fSopenharmony_ci        if (omitInitConstness &&
7723af6ab5fSopenharmony_ci            ((initType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) && annotationType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) ||
7733af6ab5fSopenharmony_ci             (initType->IsETSStringType() && annotationType->IsETSStringType()))) {
7743af6ab5fSopenharmony_ci            bindingVar->SetTsType(init->TsType());
7753af6ab5fSopenharmony_ci        }
7763af6ab5fSopenharmony_ci        return FixOptionalVariableType(bindingVar, flags, init);
7773af6ab5fSopenharmony_ci    }
7783af6ab5fSopenharmony_ci
7793af6ab5fSopenharmony_ci    CheckEnumType(init, initType, varName);
7803af6ab5fSopenharmony_ci
7813af6ab5fSopenharmony_ci    // NOTE: need to be done by smart casts
7823af6ab5fSopenharmony_ci    const bool needWidening =
7833af6ab5fSopenharmony_ci        !omitInitConstness && typeAnnotation == nullptr && NeedWideningBasedOnInitializerHeuristics(init);
7843af6ab5fSopenharmony_ci    bindingVar->SetTsType(needWidening ? GetNonConstantType(initType) : initType);
7853af6ab5fSopenharmony_ci
7863af6ab5fSopenharmony_ci    return FixOptionalVariableType(bindingVar, flags, init);
7873af6ab5fSopenharmony_ci}
7883af6ab5fSopenharmony_ci
7893af6ab5fSopenharmony_civoid ETSChecker::CheckAnnotationTypeForVariableDeclaration(checker::Type *annotationType, bool isUnionFunction,
7903af6ab5fSopenharmony_ci                                                           ir::Expression *init, checker::Type *initType)
7913af6ab5fSopenharmony_ci{
7923af6ab5fSopenharmony_ci    Type *sourceType = TryGettingFunctionTypeFromInvokeFunction(initType);
7933af6ab5fSopenharmony_ci
7943af6ab5fSopenharmony_ci    if (!isUnionFunction && annotationType->IsETSUnionType()) {
7953af6ab5fSopenharmony_ci        for (auto it : annotationType->AsETSUnionType()->ConstituentTypes()) {
7963af6ab5fSopenharmony_ci            if (it->IsETSFunctionType() ||
7973af6ab5fSopenharmony_ci                (it->IsETSObjectType() && it->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL))) {
7983af6ab5fSopenharmony_ci                isUnionFunction = true;
7993af6ab5fSopenharmony_ci                break;
8003af6ab5fSopenharmony_ci            }
8013af6ab5fSopenharmony_ci        }
8023af6ab5fSopenharmony_ci    }
8033af6ab5fSopenharmony_ci
8043af6ab5fSopenharmony_ci    if (isUnionFunction) {
8053af6ab5fSopenharmony_ci        if (!AssignmentContext(Relation(), init, initType, annotationType, init->Start(), {},
8063af6ab5fSopenharmony_ci                               TypeRelationFlag::NO_THROW)
8073af6ab5fSopenharmony_ci                 .IsAssignable()) {
8083af6ab5fSopenharmony_ci            LogTypeError({"Type '", sourceType, "' cannot be assigned to type '", annotationType, "'"}, init->Start());
8093af6ab5fSopenharmony_ci        }
8103af6ab5fSopenharmony_ci    } else {
8113af6ab5fSopenharmony_ci        if (!AssignmentContext(Relation(), init, initType, annotationType, init->Start(), {},
8123af6ab5fSopenharmony_ci                               TypeRelationFlag::NO_THROW)
8133af6ab5fSopenharmony_ci                 .IsAssignable()) {
8143af6ab5fSopenharmony_ci            LogTypeError({"Type '", sourceType, "' cannot be assigned to type '",
8153af6ab5fSopenharmony_ci                          TryGettingFunctionTypeFromInvokeFunction(annotationType), "'"},
8163af6ab5fSopenharmony_ci                         init->Start());
8173af6ab5fSopenharmony_ci        }
8183af6ab5fSopenharmony_ci    }
8193af6ab5fSopenharmony_ci}
8203af6ab5fSopenharmony_ci
8213af6ab5fSopenharmony_ci//==============================================================================//
8223af6ab5fSopenharmony_ci// Smart cast support
8233af6ab5fSopenharmony_ci//==============================================================================//
8243af6ab5fSopenharmony_ci
8253af6ab5fSopenharmony_cichecker::Type *ETSChecker::ResolveSmartType(checker::Type *sourceType, checker::Type *targetType)
8263af6ab5fSopenharmony_ci{
8273af6ab5fSopenharmony_ci    //  For left-hand variable of primitive type leave it as is.
8283af6ab5fSopenharmony_ci    if (targetType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE_RETURN)) {
8293af6ab5fSopenharmony_ci        return targetType;
8303af6ab5fSopenharmony_ci    }
8313af6ab5fSopenharmony_ci
8323af6ab5fSopenharmony_ci    //  For left-hand variable of tuple type leave it as is.
8333af6ab5fSopenharmony_ci    if (targetType->IsETSTupleType()) {
8343af6ab5fSopenharmony_ci        return targetType;
8353af6ab5fSopenharmony_ci    }
8363af6ab5fSopenharmony_ci
8373af6ab5fSopenharmony_ci    //  For left-hand variable of builtin type leave it as is.
8383af6ab5fSopenharmony_ci    if (targetType->IsETSObjectType() && targetType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_TYPE)) {
8393af6ab5fSopenharmony_ci        return targetType;
8403af6ab5fSopenharmony_ci    }
8413af6ab5fSopenharmony_ci
8423af6ab5fSopenharmony_ci    //  For the Function source or target types leave the target type as is
8433af6ab5fSopenharmony_ci    //  until we will be able to create the functional interface type from the source.
8443af6ab5fSopenharmony_ci    if (targetType->HasTypeFlag(TypeFlag::FUNCTION) || sourceType->HasTypeFlag(TypeFlag::FUNCTION)) {
8453af6ab5fSopenharmony_ci        return targetType;
8463af6ab5fSopenharmony_ci    }
8473af6ab5fSopenharmony_ci
8483af6ab5fSopenharmony_ci    // Nothing to do with identical types:
8493af6ab5fSopenharmony_ci    auto *nonConstSourceType = GetNonConstantType(sourceType);
8503af6ab5fSopenharmony_ci    auto *nonConstTargetType = GetNonConstantType(targetType);
8513af6ab5fSopenharmony_ci
8523af6ab5fSopenharmony_ci    if (Relation()->IsIdenticalTo(nonConstSourceType, nonConstTargetType) ||
8533af6ab5fSopenharmony_ci        Relation()->IsIdenticalTo(GlobalBuiltinJSValueType(), nonConstTargetType)) {
8543af6ab5fSopenharmony_ci        return targetType;
8553af6ab5fSopenharmony_ci    }
8563af6ab5fSopenharmony_ci
8573af6ab5fSopenharmony_ci    //  For type parameter, null or undefined source type return it as is.
8583af6ab5fSopenharmony_ci    if (sourceType->IsETSTypeParameter() || sourceType->DefinitelyETSNullish()) {
8593af6ab5fSopenharmony_ci        return sourceType;
8603af6ab5fSopenharmony_ci    }
8613af6ab5fSopenharmony_ci
8623af6ab5fSopenharmony_ci    //  In case of Union left-hand type we have to select the proper type from the Union
8633af6ab5fSopenharmony_ci    //  NOTE: it always exists at this point!
8643af6ab5fSopenharmony_ci    if (targetType->IsETSUnionType()) {
8653af6ab5fSopenharmony_ci        sourceType = targetType->AsETSUnionType()->GetAssignableType(this, sourceType);
8663af6ab5fSopenharmony_ci        ASSERT(sourceType != nullptr);
8673af6ab5fSopenharmony_ci        return sourceType;
8683af6ab5fSopenharmony_ci    }
8693af6ab5fSopenharmony_ci
8703af6ab5fSopenharmony_ci    //  If source is reference type, set it as the current and use it for identifier smart cast
8713af6ab5fSopenharmony_ci    if (sourceType->IsETSReferenceType()) {
8723af6ab5fSopenharmony_ci        return sourceType;
8733af6ab5fSopenharmony_ci    }
8743af6ab5fSopenharmony_ci
8753af6ab5fSopenharmony_ci    //  For right-hand variable of primitive type apply boxing conversion (case: 'let x: Object = 5', then x => Int).
8763af6ab5fSopenharmony_ci    if (sourceType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) && !sourceType->IsETSVoidType() &&
8773af6ab5fSopenharmony_ci        targetType->IsETSObjectType()) {
8783af6ab5fSopenharmony_ci        return PrimitiveTypeAsETSBuiltinType(sourceType);
8793af6ab5fSopenharmony_ci    }
8803af6ab5fSopenharmony_ci
8813af6ab5fSopenharmony_ci    //  NOTE - it seems that all the other possible cases are assignments like:
8823af6ab5fSopenharmony_ci    //  'Object = ObjectLiteral' or smth similar ???
8833af6ab5fSopenharmony_ci    //  thus for such cases also leave the target type as is.
8843af6ab5fSopenharmony_ci    //  Possible errors in tests should clarify this hypothesis sooner or later :)
8853af6ab5fSopenharmony_ci    return targetType;
8863af6ab5fSopenharmony_ci}
8873af6ab5fSopenharmony_ci
8883af6ab5fSopenharmony_ci// Auxiliary method to reduce the size of common 'CheckTestSmartCastConditions' function.
8893af6ab5fSopenharmony_cistd::pair<Type *, Type *> ETSChecker::CheckTestNullishCondition(Type *testedType, Type *actualType, bool const strict)
8903af6ab5fSopenharmony_ci{
8913af6ab5fSopenharmony_ci    if (!strict) {
8923af6ab5fSopenharmony_ci        return RemoveNullishTypes(actualType);
8933af6ab5fSopenharmony_ci    }
8943af6ab5fSopenharmony_ci
8953af6ab5fSopenharmony_ci    if (testedType->IsETSNullType()) {
8963af6ab5fSopenharmony_ci        return {GlobalETSNullType(), RemoveNullType(actualType)};
8973af6ab5fSopenharmony_ci    }
8983af6ab5fSopenharmony_ci
8993af6ab5fSopenharmony_ci    if (testedType->IsETSUndefinedType()) {
9003af6ab5fSopenharmony_ci        return {GlobalETSUndefinedType(), RemoveUndefinedType(actualType)};
9013af6ab5fSopenharmony_ci    }
9023af6ab5fSopenharmony_ci
9033af6ab5fSopenharmony_ci    return {GlobalETSNullishType(), GetNonNullishType(actualType)};
9043af6ab5fSopenharmony_ci}
9053af6ab5fSopenharmony_ci
9063af6ab5fSopenharmony_ci// Auxiliary method to reduce the size of common 'CheckTestSmartCastConditions' function.
9073af6ab5fSopenharmony_cistd::pair<Type *, Type *> ETSChecker::CheckTestObjectCondition(ETSArrayType *testedType, Type *actualType)
9083af6ab5fSopenharmony_ci{
9093af6ab5fSopenharmony_ci    if (actualType->IsETSUnionType()) {
9103af6ab5fSopenharmony_ci        return actualType->AsETSUnionType()->GetComplimentaryType(this, testedType);
9113af6ab5fSopenharmony_ci    }
9123af6ab5fSopenharmony_ci
9133af6ab5fSopenharmony_ci    // Both testing and actual (smart) types are arrays. Set types according to their relation.
9143af6ab5fSopenharmony_ci    // NOTE: probably the rules of type extraction should be modified later on!
9153af6ab5fSopenharmony_ci    if (actualType->IsETSArrayType()) {
9163af6ab5fSopenharmony_ci        auto *const arrayType = actualType->AsETSArrayType();
9173af6ab5fSopenharmony_ci
9183af6ab5fSopenharmony_ci        if (Relation()->IsIdenticalTo(arrayType, testedType) ||
9193af6ab5fSopenharmony_ci            arrayType->AssemblerName() == testedType->AssemblerName()) {
9203af6ab5fSopenharmony_ci            return {testedType, GetGlobalTypesHolder()->GlobalNeverType()};
9213af6ab5fSopenharmony_ci        }
9223af6ab5fSopenharmony_ci
9233af6ab5fSopenharmony_ci        if (Relation()->IsSupertypeOf(arrayType, testedType)) {
9243af6ab5fSopenharmony_ci            return {testedType, actualType};
9253af6ab5fSopenharmony_ci        }
9263af6ab5fSopenharmony_ci
9273af6ab5fSopenharmony_ci        if (Relation()->IsSupertypeOf(testedType, arrayType)) {
9283af6ab5fSopenharmony_ci            return {testedType, actualType};
9293af6ab5fSopenharmony_ci        }
9303af6ab5fSopenharmony_ci    } else if (actualType->IsETSObjectType() && actualType->AsETSObjectType()->IsGlobalETSObjectType()) {
9313af6ab5fSopenharmony_ci        return {testedType, actualType};
9323af6ab5fSopenharmony_ci    }
9333af6ab5fSopenharmony_ci
9343af6ab5fSopenharmony_ci    return {GetGlobalTypesHolder()->GlobalNeverType(), actualType};
9353af6ab5fSopenharmony_ci}
9363af6ab5fSopenharmony_ci
9373af6ab5fSopenharmony_ci// Auxiliary method to reduce the size of common 'CheckTestSmartCastConditions' function.
9383af6ab5fSopenharmony_cistd::pair<Type *, Type *> ETSChecker::CheckTestObjectCondition(ETSObjectType *testedType, Type *actualType,
9393af6ab5fSopenharmony_ci                                                               bool const strict)
9403af6ab5fSopenharmony_ci{
9413af6ab5fSopenharmony_ci    if (actualType->IsETSUnionType()) {
9423af6ab5fSopenharmony_ci        return actualType->AsETSUnionType()->GetComplimentaryType(this, testedType);
9433af6ab5fSopenharmony_ci    }
9443af6ab5fSopenharmony_ci
9453af6ab5fSopenharmony_ci    // Both testing and actual (smart) types are objects. Set types according to their relation.
9463af6ab5fSopenharmony_ci    // NOTE: probably the rules of type extraction should be modified later on!
9473af6ab5fSopenharmony_ci    if (actualType->IsETSObjectType()) {
9483af6ab5fSopenharmony_ci        auto *const objectType = actualType->AsETSObjectType();
9493af6ab5fSopenharmony_ci
9503af6ab5fSopenharmony_ci        if (Relation()->IsIdenticalTo(objectType, testedType) ||
9513af6ab5fSopenharmony_ci            objectType->AssemblerName() == testedType->AssemblerName()) {
9523af6ab5fSopenharmony_ci            return {testedType, strict ? GetGlobalTypesHolder()->GlobalNeverType() : actualType};
9533af6ab5fSopenharmony_ci        }
9543af6ab5fSopenharmony_ci
9553af6ab5fSopenharmony_ci        if (Relation()->IsSupertypeOf(objectType, testedType)) {
9563af6ab5fSopenharmony_ci            return {testedType, actualType};
9573af6ab5fSopenharmony_ci        }
9583af6ab5fSopenharmony_ci
9593af6ab5fSopenharmony_ci        if (Relation()->IsSupertypeOf(testedType, objectType)) {
9603af6ab5fSopenharmony_ci            return {testedType, actualType};
9613af6ab5fSopenharmony_ci        }
9623af6ab5fSopenharmony_ci
9633af6ab5fSopenharmony_ci        return {GetGlobalTypesHolder()->GlobalNeverType(), actualType};
9643af6ab5fSopenharmony_ci    }
9653af6ab5fSopenharmony_ci
9663af6ab5fSopenharmony_ci    // NOTE: other cases (for example with functional types) will be implemented later on
9673af6ab5fSopenharmony_ci    return {testedType, actualType};
9683af6ab5fSopenharmony_ci}
9693af6ab5fSopenharmony_ci
9703af6ab5fSopenharmony_cistatic constexpr std::size_t const VARIABLE_POSITION = 0UL;
9713af6ab5fSopenharmony_cistatic constexpr std::size_t const CONSEQUENT_TYPE_POSITION = 1UL;
9723af6ab5fSopenharmony_cistatic constexpr std::size_t const ALTERNATE_TYPE_POSITION = 2UL;
9733af6ab5fSopenharmony_ci
9743af6ab5fSopenharmony_civoid CheckerContext::CheckTestSmartCastCondition(lexer::TokenType operatorType)
9753af6ab5fSopenharmony_ci{
9763af6ab5fSopenharmony_ci    if (operatorType != lexer::TokenType::EOS && operatorType != lexer::TokenType::PUNCTUATOR_LOGICAL_AND &&
9773af6ab5fSopenharmony_ci        operatorType != lexer::TokenType::PUNCTUATOR_LOGICAL_OR) {
9783af6ab5fSopenharmony_ci        return;
9793af6ab5fSopenharmony_ci    }
9803af6ab5fSopenharmony_ci
9813af6ab5fSopenharmony_ci    auto types = ResolveSmartCastTypes();
9823af6ab5fSopenharmony_ci
9833af6ab5fSopenharmony_ci    if (operatorType_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) {
9843af6ab5fSopenharmony_ci        if (types.has_value()) {
9853af6ab5fSopenharmony_ci            auto const &variable = std::get<VARIABLE_POSITION>(*types);
9863af6ab5fSopenharmony_ci            //  NOTE: now we support only cases like 'if (x != null && y == null)' but don't support different type
9873af6ab5fSopenharmony_ci            //  checks for a single variable (like 'if (x != null && x instanceof string)'), because it seems that
9883af6ab5fSopenharmony_ci            //  it doesn't make much sense.
9893af6ab5fSopenharmony_ci            //  Can be implemented later on if the need arises.
9903af6ab5fSopenharmony_ci            if (auto [_, inserted] =
9913af6ab5fSopenharmony_ci                    testSmartCasts_.emplace(variable, std::make_pair(std::get<CONSEQUENT_TYPE_POSITION>(*types),
9923af6ab5fSopenharmony_ci                                                                     std::get<ALTERNATE_TYPE_POSITION>(*types)));
9933af6ab5fSopenharmony_ci                !inserted) {
9943af6ab5fSopenharmony_ci                testSmartCasts_[variable] = {nullptr, nullptr};
9953af6ab5fSopenharmony_ci            }
9963af6ab5fSopenharmony_ci        }
9973af6ab5fSopenharmony_ci        //  Clear alternate types, because now they become indefinite
9983af6ab5fSopenharmony_ci        for (auto &smartCast : testSmartCasts_) {
9993af6ab5fSopenharmony_ci            smartCast.second.second = nullptr;
10003af6ab5fSopenharmony_ci        }
10013af6ab5fSopenharmony_ci    } else if (operatorType_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR) {
10023af6ab5fSopenharmony_ci        if (bool const cleanConsequent = types.has_value() ? CheckTestOrSmartCastCondition(*types) : true;
10033af6ab5fSopenharmony_ci            cleanConsequent) {
10043af6ab5fSopenharmony_ci            //  Clear consequent types, because now they become indefinite
10053af6ab5fSopenharmony_ci            for (auto &smartCast : testSmartCasts_) {
10063af6ab5fSopenharmony_ci                smartCast.second.first = nullptr;
10073af6ab5fSopenharmony_ci            }
10083af6ab5fSopenharmony_ci        }
10093af6ab5fSopenharmony_ci    } else if (types.has_value()) {
10103af6ab5fSopenharmony_ci        testSmartCasts_.emplace(
10113af6ab5fSopenharmony_ci            std::get<VARIABLE_POSITION>(*types),
10123af6ab5fSopenharmony_ci            std::make_pair(std::get<CONSEQUENT_TYPE_POSITION>(*types), std::get<ALTERNATE_TYPE_POSITION>(*types)));
10133af6ab5fSopenharmony_ci    }
10143af6ab5fSopenharmony_ci
10153af6ab5fSopenharmony_ci    testCondition_ = {};
10163af6ab5fSopenharmony_ci    operatorType_ = operatorType;
10173af6ab5fSopenharmony_ci}
10183af6ab5fSopenharmony_ci
10193af6ab5fSopenharmony_cistd::optional<SmartCastTuple> CheckerContext::ResolveSmartCastTypes()
10203af6ab5fSopenharmony_ci{
10213af6ab5fSopenharmony_ci    if (testCondition_.variable == nullptr) {
10223af6ab5fSopenharmony_ci        return std::nullopt;
10233af6ab5fSopenharmony_ci    }
10243af6ab5fSopenharmony_ci
10253af6ab5fSopenharmony_ci    // Exclude processing of global variables and those captured in lambdas and modified there
10263af6ab5fSopenharmony_ci    auto const *const variableScope = testCondition_.variable->GetScope();
10273af6ab5fSopenharmony_ci    auto const topLevelVariable =
10283af6ab5fSopenharmony_ci        variableScope != nullptr ? variableScope->IsGlobalScope() ||
10293af6ab5fSopenharmony_ci                                       (variableScope->Parent() != nullptr && variableScope->Parent()->IsGlobalScope())
10303af6ab5fSopenharmony_ci                                 : false;
10313af6ab5fSopenharmony_ci    if (topLevelVariable) {
10323af6ab5fSopenharmony_ci        return std::nullopt;
10333af6ab5fSopenharmony_ci    }
10343af6ab5fSopenharmony_ci
10353af6ab5fSopenharmony_ci    ASSERT(testCondition_.testedType != nullptr);
10363af6ab5fSopenharmony_ci    // NOTE: functional types are not supported now
10373af6ab5fSopenharmony_ci    if (!testCondition_.testedType->IsETSReferenceType() ||
10383af6ab5fSopenharmony_ci        testCondition_.testedType->HasTypeFlag(TypeFlag::FUNCTION)) {
10393af6ab5fSopenharmony_ci        return std::nullopt;
10403af6ab5fSopenharmony_ci    }
10413af6ab5fSopenharmony_ci
10423af6ab5fSopenharmony_ci    auto *smartType = GetSmartCast(testCondition_.variable);
10433af6ab5fSopenharmony_ci    if (smartType == nullptr) {
10443af6ab5fSopenharmony_ci        smartType = testCondition_.variable->TsType();
10453af6ab5fSopenharmony_ci    }
10463af6ab5fSopenharmony_ci
10473af6ab5fSopenharmony_ci    auto *const checker = parent_->AsETSChecker();
10483af6ab5fSopenharmony_ci    Type *consequentType = nullptr;
10493af6ab5fSopenharmony_ci    Type *alternateType = nullptr;
10503af6ab5fSopenharmony_ci
10513af6ab5fSopenharmony_ci    if (testCondition_.testedType->DefinitelyETSNullish()) {
10523af6ab5fSopenharmony_ci        // In case of testing for 'null' and/or 'undefined' remove corresponding null-like types.
10533af6ab5fSopenharmony_ci        std::tie(consequentType, alternateType) =
10543af6ab5fSopenharmony_ci            checker->CheckTestNullishCondition(testCondition_.testedType, smartType, testCondition_.strict);
10553af6ab5fSopenharmony_ci    } else {
10563af6ab5fSopenharmony_ci        if (testCondition_.testedType->IsETSObjectType()) {
10573af6ab5fSopenharmony_ci            auto *const testedType = testCondition_.testedType->AsETSObjectType();
10583af6ab5fSopenharmony_ci            std::tie(consequentType, alternateType) =
10593af6ab5fSopenharmony_ci                checker->CheckTestObjectCondition(testedType, smartType, testCondition_.strict);
10603af6ab5fSopenharmony_ci        } else if (testCondition_.testedType->IsETSArrayType()) {
10613af6ab5fSopenharmony_ci            auto *const testedType = testCondition_.testedType->AsETSArrayType();
10623af6ab5fSopenharmony_ci            std::tie(consequentType, alternateType) = checker->CheckTestObjectCondition(testedType, smartType);
10633af6ab5fSopenharmony_ci        } else if (testCondition_.testedType->IsETSUnionType()) {
10643af6ab5fSopenharmony_ci            //  NOTE: now we don't support 'instanceof' operation for union types?
10653af6ab5fSopenharmony_ci            UNREACHABLE();
10663af6ab5fSopenharmony_ci        } else {
10673af6ab5fSopenharmony_ci            // NOTE: it seems that no more cases are possible here! :)
10683af6ab5fSopenharmony_ci            UNREACHABLE();
10693af6ab5fSopenharmony_ci        }
10703af6ab5fSopenharmony_ci    }
10713af6ab5fSopenharmony_ci
10723af6ab5fSopenharmony_ci    return !testCondition_.negate
10733af6ab5fSopenharmony_ci               ? std::make_optional(std::make_tuple(testCondition_.variable, consequentType, alternateType))
10743af6ab5fSopenharmony_ci               : std::make_optional(std::make_tuple(testCondition_.variable, alternateType, consequentType));
10753af6ab5fSopenharmony_ci}
10763af6ab5fSopenharmony_cibool ETSChecker::CheckVoidAnnotation(const ir::ETSPrimitiveType *typeAnnotation)
10773af6ab5fSopenharmony_ci{
10783af6ab5fSopenharmony_ci    // Void annotation is valid only when used as 'return type' , 'type parameter instantiation', 'default type'.
10793af6ab5fSopenharmony_ci    if (typeAnnotation->GetPrimitiveType() != ir::PrimitiveType::VOID) {
10803af6ab5fSopenharmony_ci        return true;
10813af6ab5fSopenharmony_ci    }
10823af6ab5fSopenharmony_ci
10833af6ab5fSopenharmony_ci    auto parent = typeAnnotation->Parent();
10843af6ab5fSopenharmony_ci    if (parent->IsScriptFunction() && parent->AsScriptFunction()->ReturnTypeAnnotation() == typeAnnotation) {
10853af6ab5fSopenharmony_ci        return true;
10863af6ab5fSopenharmony_ci    }
10873af6ab5fSopenharmony_ci    if (parent->IsETSFunctionType() && parent->AsETSFunctionType()->ReturnType() == typeAnnotation) {
10883af6ab5fSopenharmony_ci        return true;
10893af6ab5fSopenharmony_ci    }
10903af6ab5fSopenharmony_ci    if (parent->IsTSTypeParameterInstantiation() || parent->IsTSTypeParameter()) {
10913af6ab5fSopenharmony_ci        return true;
10923af6ab5fSopenharmony_ci    }
10933af6ab5fSopenharmony_ci    LogTypeError({"'void' used as type annotation."}, typeAnnotation->Start());
10943af6ab5fSopenharmony_ci    return false;
10953af6ab5fSopenharmony_ci}
10963af6ab5fSopenharmony_civoid ETSChecker::ApplySmartCast(varbinder::Variable const *const variable, checker::Type *const smartType) noexcept
10973af6ab5fSopenharmony_ci{
10983af6ab5fSopenharmony_ci    ASSERT(variable != nullptr);
10993af6ab5fSopenharmony_ci    if (smartType != nullptr) {
11003af6ab5fSopenharmony_ci        auto *variableType = variable->TsType();
11013af6ab5fSopenharmony_ci
11023af6ab5fSopenharmony_ci        if (Relation()->IsIdenticalTo(variableType, smartType)) {
11033af6ab5fSopenharmony_ci            Context().RemoveSmartCast(variable);
11043af6ab5fSopenharmony_ci        } else {
11053af6ab5fSopenharmony_ci            Context().SetSmartCast(variable, smartType);
11063af6ab5fSopenharmony_ci        }
11073af6ab5fSopenharmony_ci    }
11083af6ab5fSopenharmony_ci}
11093af6ab5fSopenharmony_ci
11103af6ab5fSopenharmony_cibool CheckerContext::CheckTestOrSmartCastCondition(SmartCastTuple const &types)
11113af6ab5fSopenharmony_ci{
11123af6ab5fSopenharmony_ci    auto *const &variable = std::get<VARIABLE_POSITION>(types);
11133af6ab5fSopenharmony_ci    auto *const &consequentTypeNew = std::get<CONSEQUENT_TYPE_POSITION>(types);
11143af6ab5fSopenharmony_ci    auto *const &alternateTypeNew = std::get<ALTERNATE_TYPE_POSITION>(types);
11153af6ab5fSopenharmony_ci
11163af6ab5fSopenharmony_ci    if (auto const it = testSmartCasts_.find(variable); it != testSmartCasts_.end()) {
11173af6ab5fSopenharmony_ci        auto *const consequentTypeOld = it->second.first;
11183af6ab5fSopenharmony_ci        if (consequentTypeOld == nullptr) {
11193af6ab5fSopenharmony_ci            return true;
11203af6ab5fSopenharmony_ci        }
11213af6ab5fSopenharmony_ci
11223af6ab5fSopenharmony_ci        if (consequentTypeNew != nullptr && !parent_->Relation()->IsIdenticalTo(consequentTypeOld, consequentTypeNew)) {
11233af6ab5fSopenharmony_ci            it->second.first = parent_->AsETSChecker()->CreateETSUnionType({consequentTypeOld, consequentTypeNew});
11243af6ab5fSopenharmony_ci        }
11253af6ab5fSopenharmony_ci
11263af6ab5fSopenharmony_ci        if (auto *const alternateTypeOld = it->second.second; alternateTypeOld != nullptr) {
11273af6ab5fSopenharmony_ci            if (alternateTypeNew != nullptr &&
11283af6ab5fSopenharmony_ci                !parent_->Relation()->IsIdenticalTo(alternateTypeOld, alternateTypeNew)) {
11293af6ab5fSopenharmony_ci                it->second.second = parent_->AsETSChecker()->CreateETSUnionType({alternateTypeOld, alternateTypeNew});
11303af6ab5fSopenharmony_ci            }
11313af6ab5fSopenharmony_ci        } else {
11323af6ab5fSopenharmony_ci            it->second.second = alternateTypeNew;
11333af6ab5fSopenharmony_ci        }
11343af6ab5fSopenharmony_ci
11353af6ab5fSopenharmony_ci        return false;
11363af6ab5fSopenharmony_ci    }
11373af6ab5fSopenharmony_ci
11383af6ab5fSopenharmony_ci    //  NOTE: now we support only cases like 'if (x != null || y != null)' or 'if (x instanceof A || x instanceof B)'
11393af6ab5fSopenharmony_ci    //  although it seems that the resulting variable type in the second case isn't used in subsequent code directly.
11403af6ab5fSopenharmony_ci    //  More complex conditions can be implemented later on if the need arises.
11413af6ab5fSopenharmony_ci    testSmartCasts_.emplace(variable, std::make_pair(consequentTypeNew, alternateTypeNew));
11423af6ab5fSopenharmony_ci    return true;
11433af6ab5fSopenharmony_ci}
11443af6ab5fSopenharmony_ci
11453af6ab5fSopenharmony_ci//==============================================================================//
11463af6ab5fSopenharmony_ci
11473af6ab5fSopenharmony_civoid ETSChecker::SetArrayPreferredTypeForNestedMemberExpressions(ir::MemberExpression *expr, Type *annotationType)
11483af6ab5fSopenharmony_ci{
11493af6ab5fSopenharmony_ci    if ((expr == nullptr) || (annotationType == nullptr)) {
11503af6ab5fSopenharmony_ci        return;
11513af6ab5fSopenharmony_ci    }
11523af6ab5fSopenharmony_ci
11533af6ab5fSopenharmony_ci    if (expr->Kind() != ir::MemberExpressionKind::ELEMENT_ACCESS) {
11543af6ab5fSopenharmony_ci        return;
11553af6ab5fSopenharmony_ci    }
11563af6ab5fSopenharmony_ci
11573af6ab5fSopenharmony_ci    // Expand all member expressions
11583af6ab5fSopenharmony_ci    Type *elementType = annotationType;
11593af6ab5fSopenharmony_ci    ir::Expression *object = expr->Object();
11603af6ab5fSopenharmony_ci    while ((object != nullptr) && (object->IsMemberExpression())) {
11613af6ab5fSopenharmony_ci        ir::MemberExpression *memberExpr = object->AsMemberExpression();
11623af6ab5fSopenharmony_ci        if (memberExpr->Kind() != ir::MemberExpressionKind::ELEMENT_ACCESS) {
11633af6ab5fSopenharmony_ci            return;
11643af6ab5fSopenharmony_ci        }
11653af6ab5fSopenharmony_ci
11663af6ab5fSopenharmony_ci        object = memberExpr->Object();
11673af6ab5fSopenharmony_ci        elementType = CreateETSArrayType(elementType);
11683af6ab5fSopenharmony_ci    }
11693af6ab5fSopenharmony_ci
11703af6ab5fSopenharmony_ci    // Set explicit target type for array
11713af6ab5fSopenharmony_ci    if ((object != nullptr) && (object->IsArrayExpression())) {
11723af6ab5fSopenharmony_ci        ir::ArrayExpression *array = object->AsArrayExpression();
11733af6ab5fSopenharmony_ci        array->SetPreferredType(CreateETSArrayType(elementType));
11743af6ab5fSopenharmony_ci    }
11753af6ab5fSopenharmony_ci}
11763af6ab5fSopenharmony_ci
11773af6ab5fSopenharmony_cistatic void CheckExpandedType(Type *expandedAliasType, std::set<util::StringView> &parametersNeedToBeBoxed,
11783af6ab5fSopenharmony_ci                              bool needToBeBoxed)
11793af6ab5fSopenharmony_ci{
11803af6ab5fSopenharmony_ci    if (expandedAliasType->IsETSTypeParameter()) {
11813af6ab5fSopenharmony_ci        auto paramName = expandedAliasType->AsETSTypeParameter()->GetDeclNode()->Name()->Name();
11823af6ab5fSopenharmony_ci        if (needToBeBoxed) {
11833af6ab5fSopenharmony_ci            parametersNeedToBeBoxed.insert(paramName);
11843af6ab5fSopenharmony_ci        }
11853af6ab5fSopenharmony_ci    } else if (expandedAliasType->IsETSObjectType()) {
11863af6ab5fSopenharmony_ci        auto objectType = expandedAliasType->AsETSObjectType();
11873af6ab5fSopenharmony_ci        needToBeBoxed =
11883af6ab5fSopenharmony_ci            objectType->GetDeclNode()->IsClassDefinition() || objectType->GetDeclNode()->IsTSInterfaceDeclaration();
11893af6ab5fSopenharmony_ci        for (const auto typeArgument : objectType->TypeArguments()) {
11903af6ab5fSopenharmony_ci            CheckExpandedType(typeArgument, parametersNeedToBeBoxed, needToBeBoxed);
11913af6ab5fSopenharmony_ci        }
11923af6ab5fSopenharmony_ci    } else if (expandedAliasType->IsETSTupleType()) {
11933af6ab5fSopenharmony_ci        auto tupleType = expandedAliasType->AsETSTupleType();
11943af6ab5fSopenharmony_ci        needToBeBoxed = false;
11953af6ab5fSopenharmony_ci        for (auto type : tupleType->GetTupleTypesList()) {
11963af6ab5fSopenharmony_ci            CheckExpandedType(type, parametersNeedToBeBoxed, needToBeBoxed);
11973af6ab5fSopenharmony_ci        }
11983af6ab5fSopenharmony_ci    } else if (expandedAliasType->IsETSArrayType()) {
11993af6ab5fSopenharmony_ci        auto arrayType = expandedAliasType->AsETSArrayType();
12003af6ab5fSopenharmony_ci        needToBeBoxed = false;
12013af6ab5fSopenharmony_ci        auto elementType = arrayType->ElementType();
12023af6ab5fSopenharmony_ci        CheckExpandedType(elementType, parametersNeedToBeBoxed, needToBeBoxed);
12033af6ab5fSopenharmony_ci    } else if (expandedAliasType->IsETSUnionType()) {
12043af6ab5fSopenharmony_ci        auto unionType = expandedAliasType->AsETSUnionType();
12053af6ab5fSopenharmony_ci        needToBeBoxed = false;
12063af6ab5fSopenharmony_ci        for (auto type : unionType->ConstituentTypes()) {
12073af6ab5fSopenharmony_ci            CheckExpandedType(type, parametersNeedToBeBoxed, needToBeBoxed);
12083af6ab5fSopenharmony_ci        }
12093af6ab5fSopenharmony_ci    }
12103af6ab5fSopenharmony_ci}
12113af6ab5fSopenharmony_ci
12123af6ab5fSopenharmony_ciType *ETSChecker::HandleTypeAlias(ir::Expression *const name, const ir::TSTypeParameterInstantiation *const typeParams)
12133af6ab5fSopenharmony_ci{
12143af6ab5fSopenharmony_ci    ASSERT(name->IsIdentifier() && name->AsIdentifier()->Variable() &&
12153af6ab5fSopenharmony_ci           name->AsIdentifier()->Variable()->Declaration()->IsTypeAliasDecl());
12163af6ab5fSopenharmony_ci
12173af6ab5fSopenharmony_ci    auto *const typeAliasNode =
12183af6ab5fSopenharmony_ci        name->AsIdentifier()->Variable()->Declaration()->AsTypeAliasDecl()->Node()->AsTSTypeAliasDeclaration();
12193af6ab5fSopenharmony_ci
12203af6ab5fSopenharmony_ci    // NOTE (mmartin): modify for default params
12213af6ab5fSopenharmony_ci    if ((typeParams == nullptr) != (typeAliasNode->TypeParams() == nullptr)) {
12223af6ab5fSopenharmony_ci        if (typeParams == nullptr) {
12233af6ab5fSopenharmony_ci            LogTypeError("Type alias declaration is generic, but no type parameters were provided", name->Start());
12243af6ab5fSopenharmony_ci            return GlobalTypeError();
12253af6ab5fSopenharmony_ci        }
12263af6ab5fSopenharmony_ci
12273af6ab5fSopenharmony_ci        LogTypeError("Type alias declaration is not generic, but type parameters were provided", typeParams->Start());
12283af6ab5fSopenharmony_ci        return GlobalTypeError();
12293af6ab5fSopenharmony_ci    }
12303af6ab5fSopenharmony_ci
12313af6ab5fSopenharmony_ci    if (typeParams == nullptr) {
12323af6ab5fSopenharmony_ci        // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
12333af6ab5fSopenharmony_ci        return GetReferencedTypeBase(name);
12343af6ab5fSopenharmony_ci    }
12353af6ab5fSopenharmony_ci
12363af6ab5fSopenharmony_ci    for (auto *const origTypeParam : typeParams->Params()) {
12373af6ab5fSopenharmony_ci        origTypeParam->Check(this);
12383af6ab5fSopenharmony_ci    }
12393af6ab5fSopenharmony_ci
12403af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
12413af6ab5fSopenharmony_ci    Type *const aliasType = GetReferencedTypeBase(name);
12423af6ab5fSopenharmony_ci    auto *aliasSub = NewSubstitution();
12433af6ab5fSopenharmony_ci    if (typeAliasNode->TypeParams()->Params().size() != typeParams->Params().size()) {
12443af6ab5fSopenharmony_ci        LogTypeError("Wrong number of type parameters for generic type alias", typeParams->Start());
12453af6ab5fSopenharmony_ci        return GlobalTypeError();
12463af6ab5fSopenharmony_ci    }
12473af6ab5fSopenharmony_ci
12483af6ab5fSopenharmony_ci    std::set<util::StringView> parametersNeedToBeBoxed;
12493af6ab5fSopenharmony_ci    auto expandedAliasType = aliasType->Substitute(Relation(), aliasSub);
12503af6ab5fSopenharmony_ci    CheckExpandedType(expandedAliasType, parametersNeedToBeBoxed, false);
12513af6ab5fSopenharmony_ci
12523af6ab5fSopenharmony_ci    for (std::size_t idx = 0; idx < typeAliasNode->TypeParams()->Params().size(); ++idx) {
12533af6ab5fSopenharmony_ci        auto *typeAliasTypeName = typeAliasNode->TypeParams()->Params().at(idx)->Name();
12543af6ab5fSopenharmony_ci        auto *typeAliasType = typeAliasTypeName->Variable()->TsType();
12553af6ab5fSopenharmony_ci        if (!typeAliasType->IsETSTypeParameter()) {
12563af6ab5fSopenharmony_ci            continue;
12573af6ab5fSopenharmony_ci        }
12583af6ab5fSopenharmony_ci        auto paramType = typeParams->Params().at(idx)->TsType();
12593af6ab5fSopenharmony_ci        if (parametersNeedToBeBoxed.find(typeAliasTypeName->Name()) != parametersNeedToBeBoxed.end()) {
12603af6ab5fSopenharmony_ci            auto boxedType = PrimitiveTypeAsETSBuiltinType(typeParams->Params().at(idx)->GetType(this));
12613af6ab5fSopenharmony_ci            if (boxedType != nullptr) {
12623af6ab5fSopenharmony_ci                paramType = boxedType;
12633af6ab5fSopenharmony_ci            }
12643af6ab5fSopenharmony_ci        }
12653af6ab5fSopenharmony_ci        aliasSub->insert({typeAliasType->AsETSTypeParameter(), paramType});
12663af6ab5fSopenharmony_ci    }
12673af6ab5fSopenharmony_ci
12683af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
12693af6ab5fSopenharmony_ci    ValidateGenericTypeAliasForClonedNode(typeAliasNode->AsTSTypeAliasDeclaration(), typeParams);
12703af6ab5fSopenharmony_ci
12713af6ab5fSopenharmony_ci    return aliasType->Substitute(Relation(), aliasSub);
12723af6ab5fSopenharmony_ci}
12733af6ab5fSopenharmony_ci
12743af6ab5fSopenharmony_cistd::vector<util::StringView> ETSChecker::GetNameForSynteticObjectType(const util::StringView &source)
12753af6ab5fSopenharmony_ci{
12763af6ab5fSopenharmony_ci    const std::string str = source.Mutf8();
12773af6ab5fSopenharmony_ci    std::istringstream ss {str};
12783af6ab5fSopenharmony_ci    const char delimiter = '.';
12793af6ab5fSopenharmony_ci    std::string token;
12803af6ab5fSopenharmony_ci
12813af6ab5fSopenharmony_ci    std::vector<util::StringView> syntheticName {};
12823af6ab5fSopenharmony_ci
12833af6ab5fSopenharmony_ci    while (std::getline(ss, token, delimiter)) {
12843af6ab5fSopenharmony_ci        if (!token.empty()) {
12853af6ab5fSopenharmony_ci            util::UString sV(token, Allocator());
12863af6ab5fSopenharmony_ci            syntheticName.emplace_back(sV.View());
12873af6ab5fSopenharmony_ci        }
12883af6ab5fSopenharmony_ci    }
12893af6ab5fSopenharmony_ci
12903af6ab5fSopenharmony_ci    return syntheticName;
12913af6ab5fSopenharmony_ci}
12923af6ab5fSopenharmony_ci
12933af6ab5fSopenharmony_cistd::pair<bool, util::StringView> FindSpecifierForModuleObject(ir::ETSImportDeclaration *importDecl,
12943af6ab5fSopenharmony_ci                                                               util::StringView const &name)
12953af6ab5fSopenharmony_ci{
12963af6ab5fSopenharmony_ci    if (importDecl == nullptr) {
12973af6ab5fSopenharmony_ci        return std::make_pair(true, util::StringView());
12983af6ab5fSopenharmony_ci    }
12993af6ab5fSopenharmony_ci
13003af6ab5fSopenharmony_ci    for (auto item : importDecl->Specifiers()) {
13013af6ab5fSopenharmony_ci        if (item->IsImportSpecifier() && item->AsImportSpecifier()->Imported()->Name().Is(name.Mutf8())) {
13023af6ab5fSopenharmony_ci            if (!item->AsImportSpecifier()->Imported()->Name().Is(item->AsImportSpecifier()->Local()->Name().Mutf8())) {
13033af6ab5fSopenharmony_ci                return std::make_pair(true, item->AsImportSpecifier()->Local()->Name());
13043af6ab5fSopenharmony_ci            }
13053af6ab5fSopenharmony_ci            return std::make_pair(true, util::StringView());
13063af6ab5fSopenharmony_ci        }
13073af6ab5fSopenharmony_ci    }
13083af6ab5fSopenharmony_ci    return std::make_pair(false, util::StringView());
13093af6ab5fSopenharmony_ci}
13103af6ab5fSopenharmony_ci
13113af6ab5fSopenharmony_citemplate <checker::PropertyType TYPE>
13123af6ab5fSopenharmony_civoid ETSChecker::BindingsModuleObjectAddProperty(checker::ETSObjectType *moduleObjType,
13133af6ab5fSopenharmony_ci                                                 ir::ETSImportDeclaration *importDecl,
13143af6ab5fSopenharmony_ci                                                 const varbinder::Scope::VariableMap &bindings)
13153af6ab5fSopenharmony_ci{
13163af6ab5fSopenharmony_ci    for (auto [_, var] : bindings) {
13173af6ab5fSopenharmony_ci        (void)_;
13183af6ab5fSopenharmony_ci        auto [found, aliasedName] = FindSpecifierForModuleObject(importDecl, var->AsLocalVariable()->Name());
13193af6ab5fSopenharmony_ci        if ((var->AsLocalVariable()->Declaration()->Node()->IsExported() ||
13203af6ab5fSopenharmony_ci             var->AsLocalVariable()->Declaration()->Node()->IsExportedType()) &&
13213af6ab5fSopenharmony_ci            found) {
13223af6ab5fSopenharmony_ci            if (!aliasedName.Empty()) {
13233af6ab5fSopenharmony_ci                moduleObjType->AddReExportAlias(var->Declaration()->Name(), aliasedName);
13243af6ab5fSopenharmony_ci            }
13253af6ab5fSopenharmony_ci            moduleObjType->AddProperty<TYPE>(var->AsLocalVariable(),
13263af6ab5fSopenharmony_ci                                             FindPropNameForNamespaceImport(var->AsLocalVariable()->Name()));
13273af6ab5fSopenharmony_ci        }
13283af6ab5fSopenharmony_ci    }
13293af6ab5fSopenharmony_ci}
13303af6ab5fSopenharmony_ci
13313af6ab5fSopenharmony_ciutil::StringView ETSChecker::FindPropNameForNamespaceImport(const util::StringView &originalName)
13323af6ab5fSopenharmony_ci{
13333af6ab5fSopenharmony_ci    if (auto relatedMapItem =
13343af6ab5fSopenharmony_ci            VarBinder()->AsETSBinder()->GetSelectiveExportAliasMultimap().find(Program()->SourceFilePath());
13353af6ab5fSopenharmony_ci        relatedMapItem != VarBinder()->AsETSBinder()->GetSelectiveExportAliasMultimap().end()) {
13363af6ab5fSopenharmony_ci        if (auto result = std::find_if(relatedMapItem->second.begin(), relatedMapItem->second.end(),
13373af6ab5fSopenharmony_ci                                       [originalName](const auto &item) { return item.second == originalName; });
13383af6ab5fSopenharmony_ci            result != relatedMapItem->second.end()) {
13393af6ab5fSopenharmony_ci            return result->first;
13403af6ab5fSopenharmony_ci        }
13413af6ab5fSopenharmony_ci    }
13423af6ab5fSopenharmony_ci
13433af6ab5fSopenharmony_ci    return originalName;
13443af6ab5fSopenharmony_ci}
13453af6ab5fSopenharmony_ci
13463af6ab5fSopenharmony_ci// Helps to prevent searching for the imported file among external sources if it is the entry program
13473af6ab5fSopenharmony_cistatic parser::Program *SelectEntryOrExternalProgram(varbinder::ETSBinder *etsBinder,
13483af6ab5fSopenharmony_ci                                                     const util::StringView &importPath)
13493af6ab5fSopenharmony_ci{
13503af6ab5fSopenharmony_ci    if (importPath.Is(etsBinder->GetGlobalRecordTable()->Program()->AbsoluteName().Mutf8())) {
13513af6ab5fSopenharmony_ci        return etsBinder->GetGlobalRecordTable()->Program();
13523af6ab5fSopenharmony_ci    }
13533af6ab5fSopenharmony_ci
13543af6ab5fSopenharmony_ci    auto programList = etsBinder->GetProgramList(importPath);
13553af6ab5fSopenharmony_ci    ASSERT(!programList.empty());
13563af6ab5fSopenharmony_ci    return programList.front();
13573af6ab5fSopenharmony_ci}
13583af6ab5fSopenharmony_ci
13593af6ab5fSopenharmony_civoid ETSChecker::SetPropertiesForModuleObject(checker::ETSObjectType *moduleObjType, const util::StringView &importPath,
13603af6ab5fSopenharmony_ci                                              ir::ETSImportDeclaration *importDecl)
13613af6ab5fSopenharmony_ci{
13623af6ab5fSopenharmony_ci    parser::Program *program =
13633af6ab5fSopenharmony_ci        SelectEntryOrExternalProgram(static_cast<varbinder::ETSBinder *>(VarBinder()), importPath);
13643af6ab5fSopenharmony_ci    // Check imported properties before assigning them to module object
13653af6ab5fSopenharmony_ci    if (!program->IsASTChecked()) {
13663af6ab5fSopenharmony_ci        // NOTE: helps to avoid endless loop in case of recursive imports that uses all bindings
13673af6ab5fSopenharmony_ci        program->MarkASTAsChecked();
13683af6ab5fSopenharmony_ci        program->Ast()->Check(this);
13693af6ab5fSopenharmony_ci    }
13703af6ab5fSopenharmony_ci
13713af6ab5fSopenharmony_ci    BindingsModuleObjectAddProperty<checker::PropertyType::STATIC_FIELD>(
13723af6ab5fSopenharmony_ci        moduleObjType, importDecl, program->GlobalClassScope()->StaticFieldScope()->Bindings());
13733af6ab5fSopenharmony_ci
13743af6ab5fSopenharmony_ci    BindingsModuleObjectAddProperty<checker::PropertyType::STATIC_METHOD>(
13753af6ab5fSopenharmony_ci        moduleObjType, importDecl, program->GlobalClassScope()->StaticMethodScope()->Bindings());
13763af6ab5fSopenharmony_ci
13773af6ab5fSopenharmony_ci    BindingsModuleObjectAddProperty<checker::PropertyType::STATIC_DECL>(
13783af6ab5fSopenharmony_ci        moduleObjType, importDecl, program->GlobalClassScope()->StaticDeclScope()->Bindings());
13793af6ab5fSopenharmony_ci
13803af6ab5fSopenharmony_ci    BindingsModuleObjectAddProperty<checker::PropertyType::STATIC_DECL>(
13813af6ab5fSopenharmony_ci        moduleObjType, importDecl, program->GlobalClassScope()->InstanceDeclScope()->Bindings());
13823af6ab5fSopenharmony_ci
13833af6ab5fSopenharmony_ci    BindingsModuleObjectAddProperty<checker::PropertyType::STATIC_DECL>(
13843af6ab5fSopenharmony_ci        moduleObjType, importDecl, program->GlobalClassScope()->TypeAliasScope()->Bindings());
13853af6ab5fSopenharmony_ci}
13863af6ab5fSopenharmony_ci
13873af6ab5fSopenharmony_civoid ETSChecker::SetrModuleObjectTsType(ir::Identifier *local, checker::ETSObjectType *moduleObjType)
13883af6ab5fSopenharmony_ci{
13893af6ab5fSopenharmony_ci    auto *etsBinder = static_cast<varbinder::ETSBinder *>(VarBinder());
13903af6ab5fSopenharmony_ci
13913af6ab5fSopenharmony_ci    for (auto [bindingName, var] : etsBinder->TopScope()->Bindings()) {
13923af6ab5fSopenharmony_ci        if (bindingName.Is(local->Name().Mutf8())) {
13933af6ab5fSopenharmony_ci            var->SetTsType(moduleObjType);
13943af6ab5fSopenharmony_ci        }
13953af6ab5fSopenharmony_ci    }
13963af6ab5fSopenharmony_ci}
13973af6ab5fSopenharmony_ci
13983af6ab5fSopenharmony_ciType *ETSChecker::GetReferencedTypeFromBase([[maybe_unused]] Type *baseType, [[maybe_unused]] ir::Expression *name)
13993af6ab5fSopenharmony_ci{
14003af6ab5fSopenharmony_ci    LogTypeError("Invalid type reference.", name->Start());
14013af6ab5fSopenharmony_ci    name->SetTsType(GlobalTypeError());
14023af6ab5fSopenharmony_ci    return name->TsTypeOrError();
14033af6ab5fSopenharmony_ci}
14043af6ab5fSopenharmony_ci
14053af6ab5fSopenharmony_ciType *ETSChecker::GetReferencedTypeBase(ir::Expression *name)
14063af6ab5fSopenharmony_ci{
14073af6ab5fSopenharmony_ci    if (name->IsTSQualifiedName()) {
14083af6ab5fSopenharmony_ci        return name->Check(this);
14093af6ab5fSopenharmony_ci    }
14103af6ab5fSopenharmony_ci
14113af6ab5fSopenharmony_ci    ASSERT(name->IsIdentifier() && name->AsIdentifier()->Variable() != nullptr);
14123af6ab5fSopenharmony_ci
14133af6ab5fSopenharmony_ci    // NOTE: kbaladurin. forbid usage imported entities as types without declarations
14143af6ab5fSopenharmony_ci    auto *importData = VarBinder()->AsETSBinder()->DynamicImportDataForVar(name->AsIdentifier()->Variable());
14153af6ab5fSopenharmony_ci    if (importData != nullptr && importData->import->IsPureDynamic()) {
14163af6ab5fSopenharmony_ci        name->SetTsType(GlobalBuiltinDynamicType(importData->import->Language()));
14173af6ab5fSopenharmony_ci        return name->TsType();
14183af6ab5fSopenharmony_ci    }
14193af6ab5fSopenharmony_ci
14203af6ab5fSopenharmony_ci    auto *refVar = name->AsIdentifier()->Variable()->AsLocalVariable();
14213af6ab5fSopenharmony_ci
14223af6ab5fSopenharmony_ci    checker::Type *tsType = nullptr;
14233af6ab5fSopenharmony_ci    switch (refVar->Declaration()->Node()->Type()) {
14243af6ab5fSopenharmony_ci        case ir::AstNodeType::TS_INTERFACE_DECLARATION: {
14253af6ab5fSopenharmony_ci            tsType = GetTypeFromInterfaceReference(refVar);
14263af6ab5fSopenharmony_ci            break;
14273af6ab5fSopenharmony_ci        }
14283af6ab5fSopenharmony_ci        case ir::AstNodeType::CLASS_DECLARATION:
14293af6ab5fSopenharmony_ci        case ir::AstNodeType::STRUCT_DECLARATION:
14303af6ab5fSopenharmony_ci        case ir::AstNodeType::CLASS_DEFINITION: {
14313af6ab5fSopenharmony_ci            tsType = GetTypeFromClassReference(refVar);
14323af6ab5fSopenharmony_ci            break;
14333af6ab5fSopenharmony_ci        }
14343af6ab5fSopenharmony_ci        case ir::AstNodeType::TS_ENUM_DECLARATION: {
14353af6ab5fSopenharmony_ci            // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
14363af6ab5fSopenharmony_ci            tsType = GetTypeFromEnumReference(refVar);
14373af6ab5fSopenharmony_ci            break;
14383af6ab5fSopenharmony_ci        }
14393af6ab5fSopenharmony_ci        case ir::AstNodeType::TS_TYPE_PARAMETER: {
14403af6ab5fSopenharmony_ci            tsType = GetTypeFromTypeParameterReference(refVar, name->Start());
14413af6ab5fSopenharmony_ci            break;
14423af6ab5fSopenharmony_ci        }
14433af6ab5fSopenharmony_ci        case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION: {
14443af6ab5fSopenharmony_ci            tsType = GetTypeFromTypeAliasReference(refVar);
14453af6ab5fSopenharmony_ci            break;
14463af6ab5fSopenharmony_ci        }
14473af6ab5fSopenharmony_ci        default: {
14483af6ab5fSopenharmony_ci            UNREACHABLE();
14493af6ab5fSopenharmony_ci        }
14503af6ab5fSopenharmony_ci    }
14513af6ab5fSopenharmony_ci    name->SetTsType(tsType);
14523af6ab5fSopenharmony_ci    return tsType;
14533af6ab5fSopenharmony_ci}
14543af6ab5fSopenharmony_ci
14553af6ab5fSopenharmony_civoid ETSChecker::ConcatConstantString(util::UString &target, Type *type)
14563af6ab5fSopenharmony_ci{
14573af6ab5fSopenharmony_ci    switch (ETSType(type)) {
14583af6ab5fSopenharmony_ci        case TypeFlag::ETS_OBJECT: {
14593af6ab5fSopenharmony_ci            ASSERT(type->IsETSStringType());
14603af6ab5fSopenharmony_ci            target.Append(type->AsETSStringType()->GetValue());
14613af6ab5fSopenharmony_ci            break;
14623af6ab5fSopenharmony_ci        }
14633af6ab5fSopenharmony_ci        case TypeFlag::ETS_BOOLEAN: {
14643af6ab5fSopenharmony_ci            target.Append(type->AsETSBooleanType()->GetValue() ? "true" : "false");
14653af6ab5fSopenharmony_ci            break;
14663af6ab5fSopenharmony_ci        }
14673af6ab5fSopenharmony_ci        case TypeFlag::BYTE: {
14683af6ab5fSopenharmony_ci            target.Append(std::to_string(type->AsByteType()->GetValue()));
14693af6ab5fSopenharmony_ci            break;
14703af6ab5fSopenharmony_ci        }
14713af6ab5fSopenharmony_ci        case TypeFlag::CHAR: {
14723af6ab5fSopenharmony_ci            std::string s(1, type->AsCharType()->GetValue());
14733af6ab5fSopenharmony_ci            target.Append(s);
14743af6ab5fSopenharmony_ci            break;
14753af6ab5fSopenharmony_ci        }
14763af6ab5fSopenharmony_ci        case TypeFlag::SHORT: {
14773af6ab5fSopenharmony_ci            target.Append(std::to_string(type->AsShortType()->GetValue()));
14783af6ab5fSopenharmony_ci            break;
14793af6ab5fSopenharmony_ci        }
14803af6ab5fSopenharmony_ci        case TypeFlag::INT: {
14813af6ab5fSopenharmony_ci            target.Append(std::to_string(type->AsIntType()->GetValue()));
14823af6ab5fSopenharmony_ci            break;
14833af6ab5fSopenharmony_ci        }
14843af6ab5fSopenharmony_ci        case TypeFlag::LONG: {
14853af6ab5fSopenharmony_ci            target.Append(std::to_string(type->AsLongType()->GetValue()));
14863af6ab5fSopenharmony_ci            break;
14873af6ab5fSopenharmony_ci        }
14883af6ab5fSopenharmony_ci        case TypeFlag::FLOAT: {
14893af6ab5fSopenharmony_ci            target.Append(std::to_string(type->AsFloatType()->GetValue()));
14903af6ab5fSopenharmony_ci            break;
14913af6ab5fSopenharmony_ci        }
14923af6ab5fSopenharmony_ci        case TypeFlag::DOUBLE: {
14933af6ab5fSopenharmony_ci            target.Append(std::to_string(type->AsDoubleType()->GetValue()));
14943af6ab5fSopenharmony_ci            break;
14953af6ab5fSopenharmony_ci        }
14963af6ab5fSopenharmony_ci        default: {
14973af6ab5fSopenharmony_ci            UNREACHABLE();
14983af6ab5fSopenharmony_ci        }
14993af6ab5fSopenharmony_ci    }
15003af6ab5fSopenharmony_ci}
15013af6ab5fSopenharmony_ci
15023af6ab5fSopenharmony_ciType *ETSChecker::HandleStringConcatenation(Type *leftType, Type *rightType)
15033af6ab5fSopenharmony_ci{
15043af6ab5fSopenharmony_ci    ASSERT(leftType->IsETSStringType() || rightType->IsETSStringType());
15053af6ab5fSopenharmony_ci
15063af6ab5fSopenharmony_ci    if (!leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) || !rightType->HasTypeFlag(checker::TypeFlag::CONSTANT) ||
15073af6ab5fSopenharmony_ci        leftType->IsETSBigIntType() || rightType->IsETSBigIntType()) {
15083af6ab5fSopenharmony_ci        return GlobalETSStringLiteralType();
15093af6ab5fSopenharmony_ci    }
15103af6ab5fSopenharmony_ci
15113af6ab5fSopenharmony_ci    util::UString concatenated(Allocator());
15123af6ab5fSopenharmony_ci    ConcatConstantString(concatenated, leftType);
15133af6ab5fSopenharmony_ci    ConcatConstantString(concatenated, rightType);
15143af6ab5fSopenharmony_ci
15153af6ab5fSopenharmony_ci    return CreateETSStringLiteralType(concatenated.View());
15163af6ab5fSopenharmony_ci}
15173af6ab5fSopenharmony_ci
15183af6ab5fSopenharmony_cichecker::ETSFunctionType *ETSChecker::FindFunctionInVectorGivenByName(util::StringView name,
15193af6ab5fSopenharmony_ci                                                                      ArenaVector<checker::ETSFunctionType *> &list)
15203af6ab5fSopenharmony_ci{
15213af6ab5fSopenharmony_ci    for (auto *it : list) {
15223af6ab5fSopenharmony_ci        if (it->Name() == name) {
15233af6ab5fSopenharmony_ci            return it;
15243af6ab5fSopenharmony_ci        }
15253af6ab5fSopenharmony_ci    }
15263af6ab5fSopenharmony_ci
15273af6ab5fSopenharmony_ci    return nullptr;
15283af6ab5fSopenharmony_ci}
15293af6ab5fSopenharmony_ci
15303af6ab5fSopenharmony_cibool ETSChecker::IsFunctionContainsSignature(checker::ETSFunctionType *funcType, Signature *signature)
15313af6ab5fSopenharmony_ci{
15323af6ab5fSopenharmony_ci    for (auto *it : funcType->CallSignatures()) {
15333af6ab5fSopenharmony_ci        Relation()->IsCompatibleTo(it, signature);
15343af6ab5fSopenharmony_ci        if (Relation()->IsTrue()) {
15353af6ab5fSopenharmony_ci            return true;
15363af6ab5fSopenharmony_ci        }
15373af6ab5fSopenharmony_ci    }
15383af6ab5fSopenharmony_ci
15393af6ab5fSopenharmony_ci    return false;
15403af6ab5fSopenharmony_ci}
15413af6ab5fSopenharmony_ci
15423af6ab5fSopenharmony_cibool ETSChecker::CheckFunctionContainsClashingSignature(const checker::ETSFunctionType *funcType, Signature *signature)
15433af6ab5fSopenharmony_ci{
15443af6ab5fSopenharmony_ci    for (auto *it : funcType->CallSignatures()) {
15453af6ab5fSopenharmony_ci        SavedTypeRelationFlagsContext strfCtx(Relation(), TypeRelationFlag::NONE);
15463af6ab5fSopenharmony_ci        Relation()->IsCompatibleTo(it, signature);
15473af6ab5fSopenharmony_ci        if (Relation()->IsTrue() && it->Function()->Id()->Name() == signature->Function()->Id()->Name()) {
15483af6ab5fSopenharmony_ci            std::stringstream ss;
15493af6ab5fSopenharmony_ci            it->ToString(ss, nullptr, true);
15503af6ab5fSopenharmony_ci            auto sigStr1 = ss.str();
15513af6ab5fSopenharmony_ci            ss.str(std::string {});  // Clear buffer
15523af6ab5fSopenharmony_ci            signature->ToString(ss, nullptr, true);
15533af6ab5fSopenharmony_ci            auto sigStr2 = ss.str();
15543af6ab5fSopenharmony_ci            LogTypeError({"Function '", it->Function()->Id()->Name(), sigStr1.c_str(),
15553af6ab5fSopenharmony_ci                          "' is redeclared with different signature '", signature->Function()->Id()->Name(),
15563af6ab5fSopenharmony_ci                          sigStr2.c_str(), "'"},
15573af6ab5fSopenharmony_ci                         signature->Function()->ReturnTypeAnnotation()->Start());
15583af6ab5fSopenharmony_ci            return false;
15593af6ab5fSopenharmony_ci        }
15603af6ab5fSopenharmony_ci    }
15613af6ab5fSopenharmony_ci    return true;
15623af6ab5fSopenharmony_ci}
15633af6ab5fSopenharmony_ci
15643af6ab5fSopenharmony_civoid ETSChecker::MergeSignatures(checker::ETSFunctionType *target, checker::ETSFunctionType *source)
15653af6ab5fSopenharmony_ci{
15663af6ab5fSopenharmony_ci    for (auto *s : source->CallSignatures()) {
15673af6ab5fSopenharmony_ci        if (IsFunctionContainsSignature(target, s)) {
15683af6ab5fSopenharmony_ci            continue;
15693af6ab5fSopenharmony_ci        }
15703af6ab5fSopenharmony_ci
15713af6ab5fSopenharmony_ci        if (!CheckFunctionContainsClashingSignature(target, s)) {
15723af6ab5fSopenharmony_ci            continue;
15733af6ab5fSopenharmony_ci        }
15743af6ab5fSopenharmony_ci        target->AddCallSignature(s);
15753af6ab5fSopenharmony_ci    }
15763af6ab5fSopenharmony_ci}
15773af6ab5fSopenharmony_ci
15783af6ab5fSopenharmony_civoid ETSChecker::MergeComputedAbstracts(ArenaVector<checker::ETSFunctionType *> &merged,
15793af6ab5fSopenharmony_ci                                        ArenaVector<checker::ETSFunctionType *> &current)
15803af6ab5fSopenharmony_ci{
15813af6ab5fSopenharmony_ci    for (auto *curr : current) {
15823af6ab5fSopenharmony_ci        auto name = curr->Name();
15833af6ab5fSopenharmony_ci        auto *found = FindFunctionInVectorGivenByName(name, merged);
15843af6ab5fSopenharmony_ci        if (found != nullptr) {
15853af6ab5fSopenharmony_ci            MergeSignatures(found, curr);
15863af6ab5fSopenharmony_ci            continue;
15873af6ab5fSopenharmony_ci        }
15883af6ab5fSopenharmony_ci
15893af6ab5fSopenharmony_ci        merged.push_back(curr);
15903af6ab5fSopenharmony_ci    }
15913af6ab5fSopenharmony_ci}
15923af6ab5fSopenharmony_ci
15933af6ab5fSopenharmony_ciir::AstNode *ETSChecker::FindAncestorGivenByType(ir::AstNode *node, ir::AstNodeType type, const ir::AstNode *endNode)
15943af6ab5fSopenharmony_ci{
15953af6ab5fSopenharmony_ci    auto *iter = node->Parent();
15963af6ab5fSopenharmony_ci
15973af6ab5fSopenharmony_ci    while (iter != endNode) {
15983af6ab5fSopenharmony_ci        if (iter->Type() == type) {
15993af6ab5fSopenharmony_ci            return iter;
16003af6ab5fSopenharmony_ci        }
16013af6ab5fSopenharmony_ci
16023af6ab5fSopenharmony_ci        iter = iter->Parent();
16033af6ab5fSopenharmony_ci    }
16043af6ab5fSopenharmony_ci
16053af6ab5fSopenharmony_ci    return nullptr;
16063af6ab5fSopenharmony_ci}
16073af6ab5fSopenharmony_ci
16083af6ab5fSopenharmony_ciutil::StringView ETSChecker::GetContainingObjectNameFromSignature(Signature *signature)
16093af6ab5fSopenharmony_ci{
16103af6ab5fSopenharmony_ci    ASSERT(signature->Function());
16113af6ab5fSopenharmony_ci    auto *iter = signature->Function()->Parent();
16123af6ab5fSopenharmony_ci
16133af6ab5fSopenharmony_ci    while (iter != nullptr) {
16143af6ab5fSopenharmony_ci        if (iter->IsClassDefinition()) {
16153af6ab5fSopenharmony_ci            return iter->AsClassDefinition()->Ident()->Name();
16163af6ab5fSopenharmony_ci        }
16173af6ab5fSopenharmony_ci
16183af6ab5fSopenharmony_ci        if (iter->IsTSInterfaceDeclaration()) {
16193af6ab5fSopenharmony_ci            return iter->AsTSInterfaceDeclaration()->Id()->Name();
16203af6ab5fSopenharmony_ci        }
16213af6ab5fSopenharmony_ci
16223af6ab5fSopenharmony_ci        iter = iter->Parent();
16233af6ab5fSopenharmony_ci    }
16243af6ab5fSopenharmony_ci
16253af6ab5fSopenharmony_ci    UNREACHABLE();
16263af6ab5fSopenharmony_ci    return {""};
16273af6ab5fSopenharmony_ci}
16283af6ab5fSopenharmony_ci
16293af6ab5fSopenharmony_cistd::optional<const ir::AstNode *> ETSChecker::FindJumpTarget(ir::AstNode *node)
16303af6ab5fSopenharmony_ci{
16313af6ab5fSopenharmony_ci    ASSERT(node->IsBreakStatement() || node->IsContinueStatement());
16323af6ab5fSopenharmony_ci
16333af6ab5fSopenharmony_ci    bool const isContinue = node->IsContinueStatement();
16343af6ab5fSopenharmony_ci
16353af6ab5fSopenharmony_ci    // Look for label
16363af6ab5fSopenharmony_ci    auto label = isContinue ? node->AsContinueStatement()->Ident() : node->AsBreakStatement()->Ident();
16373af6ab5fSopenharmony_ci    if (label != nullptr) {
16383af6ab5fSopenharmony_ci        auto var = label->Variable();
16393af6ab5fSopenharmony_ci        if (var != nullptr && var->Declaration()->IsLabelDecl()) {
16403af6ab5fSopenharmony_ci            return var->Declaration()->Node();
16413af6ab5fSopenharmony_ci        }
16423af6ab5fSopenharmony_ci
16433af6ab5fSopenharmony_ci        // Failed to resolve variable for label
16443af6ab5fSopenharmony_ci        LogUnResolvedError(label);
16453af6ab5fSopenharmony_ci        return {};
16463af6ab5fSopenharmony_ci    }
16473af6ab5fSopenharmony_ci
16483af6ab5fSopenharmony_ci    // No label, find the nearest loop or switch statement
16493af6ab5fSopenharmony_ci    const auto *iter = node->Parent();
16503af6ab5fSopenharmony_ci    while (iter != nullptr) {
16513af6ab5fSopenharmony_ci        switch (iter->Type()) {
16523af6ab5fSopenharmony_ci            case ir::AstNodeType::DO_WHILE_STATEMENT:
16533af6ab5fSopenharmony_ci            case ir::AstNodeType::WHILE_STATEMENT:
16543af6ab5fSopenharmony_ci            case ir::AstNodeType::FOR_UPDATE_STATEMENT:
16553af6ab5fSopenharmony_ci            case ir::AstNodeType::FOR_OF_STATEMENT:
16563af6ab5fSopenharmony_ci            case ir::AstNodeType::SWITCH_STATEMENT: {
16573af6ab5fSopenharmony_ci                return iter;
16583af6ab5fSopenharmony_ci            }
16593af6ab5fSopenharmony_ci            default: {
16603af6ab5fSopenharmony_ci                break;
16613af6ab5fSopenharmony_ci            }
16623af6ab5fSopenharmony_ci        }
16633af6ab5fSopenharmony_ci
16643af6ab5fSopenharmony_ci        iter = iter->Parent();
16653af6ab5fSopenharmony_ci    }
16663af6ab5fSopenharmony_ci
16673af6ab5fSopenharmony_ci    UNREACHABLE();
16683af6ab5fSopenharmony_ci}
16693af6ab5fSopenharmony_ci
16703af6ab5fSopenharmony_civarbinder::VariableFlags ETSChecker::GetAccessFlagFromNode(const ir::AstNode *node)
16713af6ab5fSopenharmony_ci{
16723af6ab5fSopenharmony_ci    if (node->IsPrivate()) {
16733af6ab5fSopenharmony_ci        return varbinder::VariableFlags::PRIVATE;
16743af6ab5fSopenharmony_ci    }
16753af6ab5fSopenharmony_ci
16763af6ab5fSopenharmony_ci    if (node->IsProtected()) {
16773af6ab5fSopenharmony_ci        return varbinder::VariableFlags::PROTECTED;
16783af6ab5fSopenharmony_ci    }
16793af6ab5fSopenharmony_ci
16803af6ab5fSopenharmony_ci    return varbinder::VariableFlags::PUBLIC;
16813af6ab5fSopenharmony_ci}
16823af6ab5fSopenharmony_ci
16833af6ab5fSopenharmony_ciType *ETSChecker::CheckSwitchDiscriminant(ir::Expression *discriminant)
16843af6ab5fSopenharmony_ci{
16853af6ab5fSopenharmony_ci    discriminant->Check(this);
16863af6ab5fSopenharmony_ci    auto *discriminantType = GetNonConstantType(MaybeUnboxExpression(discriminant));
16873af6ab5fSopenharmony_ci    if (!discriminantType->HasTypeFlag(TypeFlag::VALID_SWITCH_TYPE)) {
16883af6ab5fSopenharmony_ci        if (!(discriminantType->IsETSObjectType() &&
16893af6ab5fSopenharmony_ci              discriminantType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_STRING |
16903af6ab5fSopenharmony_ci                                                                 ETSObjectFlags::STRING | ETSObjectFlags::ENUM))) {
16913af6ab5fSopenharmony_ci            LogTypeError({"Incompatible types. Found: ", discriminantType,
16923af6ab5fSopenharmony_ci                          ", required: char , byte , short , int, long , Char , Byte , Short , Int, Long , String "
16933af6ab5fSopenharmony_ci                          "or an enum type"},
16943af6ab5fSopenharmony_ci                         discriminant->Start());
16953af6ab5fSopenharmony_ci        }
16963af6ab5fSopenharmony_ci    }
16973af6ab5fSopenharmony_ci
16983af6ab5fSopenharmony_ci    return discriminantType;
16993af6ab5fSopenharmony_ci}
17003af6ab5fSopenharmony_ci
17013af6ab5fSopenharmony_civoid ETSChecker::AddBoxingUnboxingFlagsToNode(ir::AstNode *node, Type *boxingUnboxingType)
17023af6ab5fSopenharmony_ci{
17033af6ab5fSopenharmony_ci    if (boxingUnboxingType->IsETSObjectType()) {
17043af6ab5fSopenharmony_ci        node->AddBoxingUnboxingFlags(GetBoxingFlag(boxingUnboxingType));
17053af6ab5fSopenharmony_ci    } else if (!boxingUnboxingType->IsETSUnionType()) {
17063af6ab5fSopenharmony_ci        node->AddBoxingUnboxingFlags(GetUnboxingFlag(boxingUnboxingType));
17073af6ab5fSopenharmony_ci    }
17083af6ab5fSopenharmony_ci}
17093af6ab5fSopenharmony_ci
17103af6ab5fSopenharmony_ciType *ETSChecker::MaybeBoxExpression(ir::Expression *expr)
17113af6ab5fSopenharmony_ci{
17123af6ab5fSopenharmony_ci    auto *promoted = MaybePromotedBuiltinType(expr->TsTypeOrError());
17133af6ab5fSopenharmony_ci    if (promoted != expr->TsTypeOrError()) {
17143af6ab5fSopenharmony_ci        expr->AddBoxingUnboxingFlags(GetBoxingFlag(promoted));
17153af6ab5fSopenharmony_ci    }
17163af6ab5fSopenharmony_ci    return promoted;
17173af6ab5fSopenharmony_ci}
17183af6ab5fSopenharmony_ci
17193af6ab5fSopenharmony_ciType *ETSChecker::MaybeUnboxExpression(ir::Expression *expr)
17203af6ab5fSopenharmony_ci{
17213af6ab5fSopenharmony_ci    auto *primitive = MaybePrimitiveBuiltinType(expr->TsType());
17223af6ab5fSopenharmony_ci    if (primitive != expr->TsType()) {
17233af6ab5fSopenharmony_ci        expr->AddBoxingUnboxingFlags(GetUnboxingFlag(primitive));
17243af6ab5fSopenharmony_ci    }
17253af6ab5fSopenharmony_ci    return primitive;
17263af6ab5fSopenharmony_ci}
17273af6ab5fSopenharmony_ci
17283af6ab5fSopenharmony_civoid ETSChecker::CheckForSameSwitchCases(ArenaVector<ir::SwitchCaseStatement *> const &cases)
17293af6ab5fSopenharmony_ci{
17303af6ab5fSopenharmony_ci    CheckItemCasesConstant(cases);
17313af6ab5fSopenharmony_ci    CheckItemCasesDuplicate(cases);
17323af6ab5fSopenharmony_ci}
17333af6ab5fSopenharmony_ci
17343af6ab5fSopenharmony_cistd::string ETSChecker::GetStringFromIdentifierValue(checker::Type *caseType) const
17353af6ab5fSopenharmony_ci{
17363af6ab5fSopenharmony_ci    const auto identifierTypeKind = ETSChecker::TypeKind(caseType);
17373af6ab5fSopenharmony_ci    switch (identifierTypeKind) {
17383af6ab5fSopenharmony_ci        case TypeFlag::BYTE: {
17393af6ab5fSopenharmony_ci            return std::to_string(caseType->AsByteType()->GetValue());
17403af6ab5fSopenharmony_ci        }
17413af6ab5fSopenharmony_ci        case TypeFlag::SHORT: {
17423af6ab5fSopenharmony_ci            return std::to_string(caseType->AsShortType()->GetValue());
17433af6ab5fSopenharmony_ci        }
17443af6ab5fSopenharmony_ci        case TypeFlag::CHAR: {
17453af6ab5fSopenharmony_ci            return std::to_string(caseType->AsCharType()->GetValue());
17463af6ab5fSopenharmony_ci        }
17473af6ab5fSopenharmony_ci        case TypeFlag::INT: {
17483af6ab5fSopenharmony_ci            return std::to_string(caseType->AsIntType()->GetValue());
17493af6ab5fSopenharmony_ci        }
17503af6ab5fSopenharmony_ci        case TypeFlag::LONG: {
17513af6ab5fSopenharmony_ci            return std::to_string(caseType->AsLongType()->GetValue());
17523af6ab5fSopenharmony_ci        }
17533af6ab5fSopenharmony_ci        case TypeFlag::ETS_OBJECT: {
17543af6ab5fSopenharmony_ci            VarBinder()->ThrowError(caseType->AsETSObjectType()->Variable()->Declaration()->Node()->Start(),
17553af6ab5fSopenharmony_ci                                    "not implemented");
17563af6ab5fSopenharmony_ci        }
17573af6ab5fSopenharmony_ci        default: {
17583af6ab5fSopenharmony_ci            UNREACHABLE();
17593af6ab5fSopenharmony_ci        }
17603af6ab5fSopenharmony_ci    }
17613af6ab5fSopenharmony_ci}
17623af6ab5fSopenharmony_ci
17633af6ab5fSopenharmony_cibool IsConstantMemberOrIdentifierExpression(ir::Expression *expression)
17643af6ab5fSopenharmony_ci{
17653af6ab5fSopenharmony_ci    if (expression->IsMemberExpression()) {
17663af6ab5fSopenharmony_ci        auto *var = expression->AsMemberExpression()->PropVar();
17673af6ab5fSopenharmony_ci        return var->Declaration()->IsConstDecl() ||
17683af6ab5fSopenharmony_ci               (var->Declaration()->IsReadonlyDecl() && var->HasFlag(varbinder::VariableFlags::STATIC));
17693af6ab5fSopenharmony_ci    }
17703af6ab5fSopenharmony_ci
17713af6ab5fSopenharmony_ci    if (expression->IsIdentifier()) {
17723af6ab5fSopenharmony_ci        auto *var = expression->AsIdentifier()->Variable();
17733af6ab5fSopenharmony_ci        return var->Declaration()->IsConstDecl() ||
17743af6ab5fSopenharmony_ci               (var->Declaration()->IsReadonlyDecl() && var->HasFlag(varbinder::VariableFlags::STATIC));
17753af6ab5fSopenharmony_ci    }
17763af6ab5fSopenharmony_ci
17773af6ab5fSopenharmony_ci    return false;
17783af6ab5fSopenharmony_ci}
17793af6ab5fSopenharmony_ci
17803af6ab5fSopenharmony_civoid ETSChecker::CheckItemCasesConstant(ArenaVector<ir::SwitchCaseStatement *> const &cases)
17813af6ab5fSopenharmony_ci{
17823af6ab5fSopenharmony_ci    for (auto &it : cases) {
17833af6ab5fSopenharmony_ci        auto *caseTest = it->Test();
17843af6ab5fSopenharmony_ci        if (caseTest == nullptr) {
17853af6ab5fSopenharmony_ci            continue;
17863af6ab5fSopenharmony_ci        }
17873af6ab5fSopenharmony_ci        auto *caseType = caseTest->TsType();
17883af6ab5fSopenharmony_ci        if (caseTest->TsType()->IsETSIntEnumType() || caseTest->TsType()->IsETSStringEnumType()) {
17893af6ab5fSopenharmony_ci            continue;
17903af6ab5fSopenharmony_ci        }
17913af6ab5fSopenharmony_ci
17923af6ab5fSopenharmony_ci        if (caseTest->IsIdentifier() || caseTest->IsMemberExpression()) {
17933af6ab5fSopenharmony_ci            if (!IsConstantMemberOrIdentifierExpression(caseTest)) {
17943af6ab5fSopenharmony_ci                LogTypeError("Constant expression required", it->Start());
17953af6ab5fSopenharmony_ci                continue;
17963af6ab5fSopenharmony_ci            }
17973af6ab5fSopenharmony_ci
17983af6ab5fSopenharmony_ci            if (!caseType->HasTypeFlag(checker::TypeFlag::VALID_SWITCH_TYPE)) {
17993af6ab5fSopenharmony_ci                LogTypeError("Unexpected type " + caseType->ToString(), it->Start());
18003af6ab5fSopenharmony_ci                continue;
18013af6ab5fSopenharmony_ci            }
18023af6ab5fSopenharmony_ci            continue;
18033af6ab5fSopenharmony_ci        }
18043af6ab5fSopenharmony_ci    }
18053af6ab5fSopenharmony_ci}
18063af6ab5fSopenharmony_ci
18073af6ab5fSopenharmony_civoid CheckItemEnumType(ir::Expression const *const caseTest, ETSChecker *checker, ETSIntEnumType const *const type,
18083af6ab5fSopenharmony_ci                       bool &isDup)
18093af6ab5fSopenharmony_ci{
18103af6ab5fSopenharmony_ci    if (caseTest->TsType()->AsETSIntEnumType()->IsSameEnumLiteralType(type)) {
18113af6ab5fSopenharmony_ci        isDup = true;
18123af6ab5fSopenharmony_ci        checker->LogTypeError("Case duplicate", caseTest->Start());
18133af6ab5fSopenharmony_ci    }
18143af6ab5fSopenharmony_ci}
18153af6ab5fSopenharmony_ci
18163af6ab5fSopenharmony_civoid CheckItemStringEnumType(ir::Expression const *const caseTest, ETSChecker *checker,
18173af6ab5fSopenharmony_ci                             ETSStringEnumType const *const type, bool &isDup)
18183af6ab5fSopenharmony_ci{
18193af6ab5fSopenharmony_ci    if (caseTest->TsType()->AsETSStringEnumType()->IsSameEnumLiteralType(type)) {
18203af6ab5fSopenharmony_ci        isDup = true;
18213af6ab5fSopenharmony_ci        checker->LogTypeError("Case duplicate", caseTest->Start());
18223af6ab5fSopenharmony_ci    }
18233af6ab5fSopenharmony_ci}
18243af6ab5fSopenharmony_ci
18253af6ab5fSopenharmony_civoid ETSChecker::CheckItemCasesDuplicate(ArenaVector<ir::SwitchCaseStatement *> const &cases)
18263af6ab5fSopenharmony_ci{
18273af6ab5fSopenharmony_ci    for (size_t caseNum = 0; caseNum < cases.size(); caseNum++) {
18283af6ab5fSopenharmony_ci        bool isItemDuplicate = false;
18293af6ab5fSopenharmony_ci        for (size_t compareCase = caseNum + 1; compareCase < cases.size(); compareCase++) {
18303af6ab5fSopenharmony_ci            auto *caseTest = cases.at(caseNum)->Test();
18313af6ab5fSopenharmony_ci            auto *compareCaseTest = cases.at(compareCase)->Test();
18323af6ab5fSopenharmony_ci
18333af6ab5fSopenharmony_ci            if (caseTest == nullptr || compareCaseTest == nullptr) {
18343af6ab5fSopenharmony_ci                continue;
18353af6ab5fSopenharmony_ci            }
18363af6ab5fSopenharmony_ci
18373af6ab5fSopenharmony_ci            if (caseTest->TsType()->IsETSIntEnumType()) {
18383af6ab5fSopenharmony_ci                CheckItemEnumType(caseTest, this, compareCaseTest->TsType()->AsETSIntEnumType(), isItemDuplicate);
18393af6ab5fSopenharmony_ci                continue;
18403af6ab5fSopenharmony_ci            }
18413af6ab5fSopenharmony_ci
18423af6ab5fSopenharmony_ci            if (caseTest->TsType()->IsETSStringEnumType()) {
18433af6ab5fSopenharmony_ci                CheckItemStringEnumType(caseTest, this, compareCaseTest->TsType()->AsETSStringEnumType(),
18443af6ab5fSopenharmony_ci                                        isItemDuplicate);
18453af6ab5fSopenharmony_ci                continue;
18463af6ab5fSopenharmony_ci            }
18473af6ab5fSopenharmony_ci
18483af6ab5fSopenharmony_ci            if (caseTest->IsIdentifier() || caseTest->IsMemberExpression()) {
18493af6ab5fSopenharmony_ci                CheckIdentifierSwitchCase(caseTest, compareCaseTest, cases.at(caseNum)->Start());
18503af6ab5fSopenharmony_ci                continue;
18513af6ab5fSopenharmony_ci            }
18523af6ab5fSopenharmony_ci
18533af6ab5fSopenharmony_ci            if (compareCaseTest->IsIdentifier() || compareCaseTest->IsMemberExpression()) {
18543af6ab5fSopenharmony_ci                CheckIdentifierSwitchCase(compareCaseTest, caseTest, cases.at(compareCase)->Start());
18553af6ab5fSopenharmony_ci                continue;
18563af6ab5fSopenharmony_ci            }
18573af6ab5fSopenharmony_ci
18583af6ab5fSopenharmony_ci            if (caseTest->IsLiteral() && compareCaseTest->IsLiteral() &&
18593af6ab5fSopenharmony_ci                GetStringFromLiteral(caseTest) != GetStringFromLiteral(compareCaseTest)) {
18603af6ab5fSopenharmony_ci                continue;
18613af6ab5fSopenharmony_ci            }
18623af6ab5fSopenharmony_ci
18633af6ab5fSopenharmony_ci            if (!(IsConstantExpression(caseTest, caseTest->TsType()) || caseTest->IsLiteral()) ||
18643af6ab5fSopenharmony_ci                !(IsConstantExpression(compareCaseTest, compareCaseTest->TsType()) || compareCaseTest->IsLiteral())) {
18653af6ab5fSopenharmony_ci                continue;
18663af6ab5fSopenharmony_ci            }
18673af6ab5fSopenharmony_ci
18683af6ab5fSopenharmony_ci            if (!isItemDuplicate) {
18693af6ab5fSopenharmony_ci                isItemDuplicate = true;
18703af6ab5fSopenharmony_ci                LogTypeError("Case duplicate", cases.at(compareCase)->Start());
18713af6ab5fSopenharmony_ci            }
18723af6ab5fSopenharmony_ci        }
18733af6ab5fSopenharmony_ci    }
18743af6ab5fSopenharmony_ci}
18753af6ab5fSopenharmony_ci
18763af6ab5fSopenharmony_cibool ETSChecker::CompareIdentifiersValuesAreDifferent(ir::Expression *compareValue, const std::string &caseValue)
18773af6ab5fSopenharmony_ci{
18783af6ab5fSopenharmony_ci    if (IsConstantMemberOrIdentifierExpression(compareValue)) {
18793af6ab5fSopenharmony_ci        checker::Type *compareCaseType = compareValue->TsType();
18803af6ab5fSopenharmony_ci
18813af6ab5fSopenharmony_ci        const auto compareCaseValue = GetStringFromIdentifierValue(compareCaseType);
18823af6ab5fSopenharmony_ci        return caseValue != compareCaseValue;
18833af6ab5fSopenharmony_ci    }
18843af6ab5fSopenharmony_ci
18853af6ab5fSopenharmony_ci    return caseValue != GetStringFromLiteral(compareValue);
18863af6ab5fSopenharmony_ci}
18873af6ab5fSopenharmony_ci
18883af6ab5fSopenharmony_civoid ETSChecker::CheckIdentifierSwitchCase(ir::Expression *currentCase, ir::Expression *compareCase,
18893af6ab5fSopenharmony_ci                                           const lexer::SourcePosition &pos)
18903af6ab5fSopenharmony_ci{
18913af6ab5fSopenharmony_ci    currentCase->Check(this);
18923af6ab5fSopenharmony_ci
18933af6ab5fSopenharmony_ci    if (!IsConstantMemberOrIdentifierExpression(currentCase)) {
18943af6ab5fSopenharmony_ci        return;
18953af6ab5fSopenharmony_ci    }
18963af6ab5fSopenharmony_ci
18973af6ab5fSopenharmony_ci    checker::Type *caseType = currentCase->TsType();
18983af6ab5fSopenharmony_ci
18993af6ab5fSopenharmony_ci    if (!caseType->HasTypeFlag(checker::TypeFlag::VALID_SWITCH_TYPE)) {
19003af6ab5fSopenharmony_ci        return;
19013af6ab5fSopenharmony_ci    }
19023af6ab5fSopenharmony_ci
19033af6ab5fSopenharmony_ci    if (!CompareIdentifiersValuesAreDifferent(compareCase, GetStringFromIdentifierValue(caseType))) {
19043af6ab5fSopenharmony_ci        LogTypeError("Variable has same value with another switch case", pos);
19053af6ab5fSopenharmony_ci        return;
19063af6ab5fSopenharmony_ci    }
19073af6ab5fSopenharmony_ci}
19083af6ab5fSopenharmony_ci
19093af6ab5fSopenharmony_cistd::string ETSChecker::GetStringFromLiteral(ir::Expression *caseTest) const
19103af6ab5fSopenharmony_ci{
19113af6ab5fSopenharmony_ci    switch (caseTest->Type()) {
19123af6ab5fSopenharmony_ci        case ir::AstNodeType::CHAR_LITERAL: {
19133af6ab5fSopenharmony_ci            return std::to_string(caseTest->AsCharLiteral()->Char());
19143af6ab5fSopenharmony_ci        }
19153af6ab5fSopenharmony_ci        case ir::AstNodeType::STRING_LITERAL:
19163af6ab5fSopenharmony_ci        case ir::AstNodeType::NUMBER_LITERAL: {
19173af6ab5fSopenharmony_ci            return util::Helpers::LiteralToPropName(caseTest).Mutf8();
19183af6ab5fSopenharmony_ci        }
19193af6ab5fSopenharmony_ci        default:
19203af6ab5fSopenharmony_ci            UNREACHABLE();
19213af6ab5fSopenharmony_ci    }
19223af6ab5fSopenharmony_ci}
19233af6ab5fSopenharmony_ci
19243af6ab5fSopenharmony_cibool ETSChecker::IsSameDeclarationType(varbinder::LocalVariable *target, varbinder::LocalVariable *compare)
19253af6ab5fSopenharmony_ci{
19263af6ab5fSopenharmony_ci    return target->Declaration()->Type() == compare->Declaration()->Type();
19273af6ab5fSopenharmony_ci}
19283af6ab5fSopenharmony_ci
19293af6ab5fSopenharmony_cibool ETSChecker::CheckRethrowingParams(const ir::AstNode *ancestorFunction, const ir::AstNode *node)
19303af6ab5fSopenharmony_ci{
19313af6ab5fSopenharmony_ci    for (const auto param : ancestorFunction->AsScriptFunction()->Signature()->Function()->Params()) {
19323af6ab5fSopenharmony_ci        if (node->AsCallExpression()->Callee()->AsIdentifier()->Name().Is(
19333af6ab5fSopenharmony_ci                param->AsETSParameterExpression()->Ident()->Name().Mutf8())) {
19343af6ab5fSopenharmony_ci            return true;
19353af6ab5fSopenharmony_ci        }
19363af6ab5fSopenharmony_ci    }
19373af6ab5fSopenharmony_ci    return false;
19383af6ab5fSopenharmony_ci}
19393af6ab5fSopenharmony_ci
19403af6ab5fSopenharmony_civoid ETSChecker::CheckThrowingStatements(ir::AstNode *node)
19413af6ab5fSopenharmony_ci{
19423af6ab5fSopenharmony_ci    ir::AstNode *ancestorFunction = FindAncestorGivenByType(node, ir::AstNodeType::SCRIPT_FUNCTION);
19433af6ab5fSopenharmony_ci
19443af6ab5fSopenharmony_ci    if (ancestorFunction == nullptr) {
19453af6ab5fSopenharmony_ci        LogTypeError(
19463af6ab5fSopenharmony_ci            "This statement can cause an exception, therefore it must be enclosed in a try statement with a default "
19473af6ab5fSopenharmony_ci            "catch clause",
19483af6ab5fSopenharmony_ci            node->Start());
19493af6ab5fSopenharmony_ci        return;
19503af6ab5fSopenharmony_ci    }
19513af6ab5fSopenharmony_ci
19523af6ab5fSopenharmony_ci    if (ancestorFunction->AsScriptFunction()->IsThrowing() ||
19533af6ab5fSopenharmony_ci        (ancestorFunction->AsScriptFunction()->IsRethrowing() &&
19543af6ab5fSopenharmony_ci         (!node->IsThrowStatement() && CheckRethrowingParams(ancestorFunction, node)))) {
19553af6ab5fSopenharmony_ci        return;
19563af6ab5fSopenharmony_ci    }
19573af6ab5fSopenharmony_ci
19583af6ab5fSopenharmony_ci    if (!CheckThrowingPlacement(node, ancestorFunction)) {
19593af6ab5fSopenharmony_ci        if (ancestorFunction->AsScriptFunction()->IsRethrowing() && !node->IsThrowStatement()) {
19603af6ab5fSopenharmony_ci            LogTypeError(
19613af6ab5fSopenharmony_ci                "This statement can cause an exception, re-throwing functions can throw exception only by their "
19623af6ab5fSopenharmony_ci                "parameters.",
19633af6ab5fSopenharmony_ci                node->Start());
19643af6ab5fSopenharmony_ci            return;
19653af6ab5fSopenharmony_ci        }
19663af6ab5fSopenharmony_ci
19673af6ab5fSopenharmony_ci        if (auto interfaces =
19683af6ab5fSopenharmony_ci                ancestorFunction->AsScriptFunction()->Signature()->Owner()->AsETSObjectType()->Interfaces();
19693af6ab5fSopenharmony_ci            !(!interfaces.empty() &&
19703af6ab5fSopenharmony_ci              interfaces[0]->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::FUNCTIONAL_INTERFACE))) {
19713af6ab5fSopenharmony_ci            LogTypeError(
19723af6ab5fSopenharmony_ci                "This statement can cause an exception, therefore it must be enclosed in a try statement with a "
19733af6ab5fSopenharmony_ci                "default "
19743af6ab5fSopenharmony_ci                "catch clause",
19753af6ab5fSopenharmony_ci                node->Start());
19763af6ab5fSopenharmony_ci            return;
19773af6ab5fSopenharmony_ci        }
19783af6ab5fSopenharmony_ci    }
19793af6ab5fSopenharmony_ci}
19803af6ab5fSopenharmony_ci
19813af6ab5fSopenharmony_cibool ETSChecker::CheckThrowingPlacement(ir::AstNode *node, const ir::AstNode *ancestorFunction)
19823af6ab5fSopenharmony_ci{
19833af6ab5fSopenharmony_ci    ir::AstNode *startPoint = node;
19843af6ab5fSopenharmony_ci    ir::AstNode *enclosingCatchClause = nullptr;
19853af6ab5fSopenharmony_ci    ir::BlockStatement *enclosingFinallyBlock = nullptr;
19863af6ab5fSopenharmony_ci    ir::AstNode *p = startPoint->Parent();
19873af6ab5fSopenharmony_ci
19883af6ab5fSopenharmony_ci    bool isHandled = false;
19893af6ab5fSopenharmony_ci    const auto predicateFunc = [&enclosingCatchClause](ir::CatchClause *clause) {
19903af6ab5fSopenharmony_ci        return clause == enclosingCatchClause;
19913af6ab5fSopenharmony_ci    };
19923af6ab5fSopenharmony_ci
19933af6ab5fSopenharmony_ci    do {
19943af6ab5fSopenharmony_ci        if (p->IsTryStatement() && p->AsTryStatement()->HasDefaultCatchClause()) {
19953af6ab5fSopenharmony_ci            enclosingCatchClause = FindAncestorGivenByType(startPoint, ir::AstNodeType::CATCH_CLAUSE, p);
19963af6ab5fSopenharmony_ci            enclosingFinallyBlock = FindFinalizerOfTryStatement(startPoint, p);
19973af6ab5fSopenharmony_ci            const auto catches = p->AsTryStatement()->CatchClauses();
19983af6ab5fSopenharmony_ci            if (std::any_of(catches.begin(), catches.end(), predicateFunc)) {
19993af6ab5fSopenharmony_ci                startPoint = enclosingCatchClause;
20003af6ab5fSopenharmony_ci            } else if (enclosingFinallyBlock != nullptr &&
20013af6ab5fSopenharmony_ci                       enclosingFinallyBlock == p->AsTryStatement()->FinallyBlock()) {
20023af6ab5fSopenharmony_ci                startPoint = enclosingFinallyBlock;
20033af6ab5fSopenharmony_ci            } else {
20043af6ab5fSopenharmony_ci                isHandled = true;
20053af6ab5fSopenharmony_ci                break;
20063af6ab5fSopenharmony_ci            }
20073af6ab5fSopenharmony_ci        }
20083af6ab5fSopenharmony_ci
20093af6ab5fSopenharmony_ci        p = p->Parent();
20103af6ab5fSopenharmony_ci    } while (p != ancestorFunction);
20113af6ab5fSopenharmony_ci
20123af6ab5fSopenharmony_ci    return isHandled;
20133af6ab5fSopenharmony_ci}
20143af6ab5fSopenharmony_ci
20153af6ab5fSopenharmony_ciir::BlockStatement *ETSChecker::FindFinalizerOfTryStatement(ir::AstNode *startFrom, const ir::AstNode *p)
20163af6ab5fSopenharmony_ci{
20173af6ab5fSopenharmony_ci    auto *iter = startFrom->Parent();
20183af6ab5fSopenharmony_ci
20193af6ab5fSopenharmony_ci    do {
20203af6ab5fSopenharmony_ci        if (iter->IsBlockStatement()) {
20213af6ab5fSopenharmony_ci            ir::BlockStatement *finallyBlock = iter->AsBlockStatement();
20223af6ab5fSopenharmony_ci
20233af6ab5fSopenharmony_ci            if (finallyBlock == p->AsTryStatement()->FinallyBlock()) {
20243af6ab5fSopenharmony_ci                return finallyBlock;
20253af6ab5fSopenharmony_ci            }
20263af6ab5fSopenharmony_ci        }
20273af6ab5fSopenharmony_ci
20283af6ab5fSopenharmony_ci        iter = iter->Parent();
20293af6ab5fSopenharmony_ci    } while (iter != p);
20303af6ab5fSopenharmony_ci
20313af6ab5fSopenharmony_ci    return nullptr;
20323af6ab5fSopenharmony_ci}
20333af6ab5fSopenharmony_ci
20343af6ab5fSopenharmony_civoid ETSChecker::CheckRethrowingFunction(ir::ScriptFunction *func)
20353af6ab5fSopenharmony_ci{
20363af6ab5fSopenharmony_ci    if (func->Signature()->Owner()->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL_INTERFACE)) {
20373af6ab5fSopenharmony_ci        return;
20383af6ab5fSopenharmony_ci    }
20393af6ab5fSopenharmony_ci
20403af6ab5fSopenharmony_ci    bool foundThrowingParam = false;
20413af6ab5fSopenharmony_ci
20423af6ab5fSopenharmony_ci    // It doesn't support lambdas yet.
20433af6ab5fSopenharmony_ci    for (auto item : func->Params()) {
20443af6ab5fSopenharmony_ci        auto const *type = item->AsETSParameterExpression()->Ident()->TypeAnnotation();
20453af6ab5fSopenharmony_ci
20463af6ab5fSopenharmony_ci        if (type->IsETSTypeReference()) {
20473af6ab5fSopenharmony_ci            auto *typeDecl = type->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Variable()->Declaration();
20483af6ab5fSopenharmony_ci            if (typeDecl->IsTypeAliasDecl()) {
20493af6ab5fSopenharmony_ci                type = typeDecl->Node()->AsTSTypeAliasDeclaration()->TypeAnnotation();
20503af6ab5fSopenharmony_ci            }
20513af6ab5fSopenharmony_ci        }
20523af6ab5fSopenharmony_ci
20533af6ab5fSopenharmony_ci        if (type->IsETSFunctionType() && type->AsETSFunctionType()->IsThrowing()) {
20543af6ab5fSopenharmony_ci            foundThrowingParam = true;
20553af6ab5fSopenharmony_ci            break;
20563af6ab5fSopenharmony_ci        }
20573af6ab5fSopenharmony_ci    }
20583af6ab5fSopenharmony_ci
20593af6ab5fSopenharmony_ci    if (!foundThrowingParam) {
20603af6ab5fSopenharmony_ci        LogTypeError("A rethrowing function must have a throwing function parameter", func->Start());
20613af6ab5fSopenharmony_ci    }
20623af6ab5fSopenharmony_ci}
20633af6ab5fSopenharmony_ci
20643af6ab5fSopenharmony_ciETSObjectType *ETSChecker::GetRelevantArgumentedTypeFromChild(ETSObjectType *const child, ETSObjectType *const target)
20653af6ab5fSopenharmony_ci{
20663af6ab5fSopenharmony_ci    if (child->GetDeclNode() == target->GetDeclNode()) {
20673af6ab5fSopenharmony_ci        auto *relevantType = CreateNewETSObjectType(child->Name(), child->GetDeclNode(), child->ObjectFlags());
20683af6ab5fSopenharmony_ci
20693af6ab5fSopenharmony_ci        ArenaVector<Type *> params = child->TypeArguments();
20703af6ab5fSopenharmony_ci
20713af6ab5fSopenharmony_ci        relevantType->SetTypeArguments(std::move(params));
20723af6ab5fSopenharmony_ci        relevantType->SetEnclosingType(child->EnclosingType());
20733af6ab5fSopenharmony_ci        relevantType->SetSuperType(child->SuperType());
20743af6ab5fSopenharmony_ci
20753af6ab5fSopenharmony_ci        return relevantType;
20763af6ab5fSopenharmony_ci    }
20773af6ab5fSopenharmony_ci
20783af6ab5fSopenharmony_ci    ASSERT(child->SuperType() != nullptr);
20793af6ab5fSopenharmony_ci
20803af6ab5fSopenharmony_ci    return GetRelevantArgumentedTypeFromChild(child->SuperType(), target);
20813af6ab5fSopenharmony_ci}
20823af6ab5fSopenharmony_ci
20833af6ab5fSopenharmony_civoid ETSChecker::EmplaceSubstituted(Substitution *substitution, ETSTypeParameter *tparam, Type *typeArg)
20843af6ab5fSopenharmony_ci{
20853af6ab5fSopenharmony_ci    substitution->emplace(tparam, typeArg);
20863af6ab5fSopenharmony_ci}
20873af6ab5fSopenharmony_ci
20883af6ab5fSopenharmony_ciutil::StringView ETSChecker::GetHashFromTypeArguments(const ArenaVector<Type *> &typeArgTypes)
20893af6ab5fSopenharmony_ci{
20903af6ab5fSopenharmony_ci    std::stringstream ss;
20913af6ab5fSopenharmony_ci
20923af6ab5fSopenharmony_ci    for (auto *it : typeArgTypes) {
20933af6ab5fSopenharmony_ci        it->ToString(ss, true);
20943af6ab5fSopenharmony_ci        ss << compiler::Signatures::MANGLE_SEPARATOR;
20953af6ab5fSopenharmony_ci
20963af6ab5fSopenharmony_ci        // In case of ETSTypeParameters storing the name might not be sufficient as there can
20973af6ab5fSopenharmony_ci        // be multiple different type parameters with the same name. For those we test identity based
20983af6ab5fSopenharmony_ci        // on their memory address equality, so we store them in the hash to keep it unique.
20993af6ab5fSopenharmony_ci        // To make it consistent we store it for every type.
21003af6ab5fSopenharmony_ci        // NOTE (mmartin): change bare address to something more appropriate unique representation
21013af6ab5fSopenharmony_ci        ss << it << compiler::Signatures::MANGLE_SEPARATOR;
21023af6ab5fSopenharmony_ci    }
21033af6ab5fSopenharmony_ci
21043af6ab5fSopenharmony_ci    return util::UString(ss.str(), Allocator()).View();
21053af6ab5fSopenharmony_ci}
21063af6ab5fSopenharmony_ci
21073af6ab5fSopenharmony_ciutil::StringView ETSChecker::GetHashFromSubstitution(const Substitution *substitution)
21083af6ab5fSopenharmony_ci{
21093af6ab5fSopenharmony_ci    std::vector<std::string> fields;
21103af6ab5fSopenharmony_ci    for (auto [k, v] : *substitution) {
21113af6ab5fSopenharmony_ci        std::stringstream ss;
21123af6ab5fSopenharmony_ci        k->ToString(ss, true);
21133af6ab5fSopenharmony_ci        ss << ":";
21143af6ab5fSopenharmony_ci        v->ToString(ss, true);
21153af6ab5fSopenharmony_ci        // NOTE (mmartin): change bare address to something more appropriate unique representation
21163af6ab5fSopenharmony_ci        ss << ":" << k << ":" << v;
21173af6ab5fSopenharmony_ci        fields.push_back(ss.str());
21183af6ab5fSopenharmony_ci    }
21193af6ab5fSopenharmony_ci    std::sort(fields.begin(), fields.end());
21203af6ab5fSopenharmony_ci
21213af6ab5fSopenharmony_ci    std::stringstream ss;
21223af6ab5fSopenharmony_ci    for (auto &fstr : fields) {
21233af6ab5fSopenharmony_ci        ss << fstr;
21243af6ab5fSopenharmony_ci        ss << ";";
21253af6ab5fSopenharmony_ci    }
21263af6ab5fSopenharmony_ci    return util::UString(ss.str(), Allocator()).View();
21273af6ab5fSopenharmony_ci}
21283af6ab5fSopenharmony_ci
21293af6ab5fSopenharmony_ciutil::StringView ETSChecker::GetHashFromFunctionType(ir::ETSFunctionType *type)
21303af6ab5fSopenharmony_ci{
21313af6ab5fSopenharmony_ci    std::stringstream ss;
21323af6ab5fSopenharmony_ci    for (auto *p : type->Params()) {
21333af6ab5fSopenharmony_ci        auto *const param = p->AsETSParameterExpression();
21343af6ab5fSopenharmony_ci        param->TypeAnnotation()->GetType(this)->ToString(ss, true);
21353af6ab5fSopenharmony_ci        ss << ";";
21363af6ab5fSopenharmony_ci    }
21373af6ab5fSopenharmony_ci
21383af6ab5fSopenharmony_ci    type->ReturnType()->GetType(this)->ToString(ss, true);
21393af6ab5fSopenharmony_ci    ss << ";";
21403af6ab5fSopenharmony_ci
21413af6ab5fSopenharmony_ci    if (type->IsThrowing()) {
21423af6ab5fSopenharmony_ci        ss << "throws;";
21433af6ab5fSopenharmony_ci    }
21443af6ab5fSopenharmony_ci
21453af6ab5fSopenharmony_ci    if (type->IsRethrowing()) {
21463af6ab5fSopenharmony_ci        ss << "rethrows;";
21473af6ab5fSopenharmony_ci    }
21483af6ab5fSopenharmony_ci
21493af6ab5fSopenharmony_ci    return util::UString(ss.str(), Allocator()).View();
21503af6ab5fSopenharmony_ci}
21513af6ab5fSopenharmony_ci
21523af6ab5fSopenharmony_ciETSObjectType *ETSChecker::GetOriginalBaseType(Type *const object)
21533af6ab5fSopenharmony_ci{
21543af6ab5fSopenharmony_ci    if (object == nullptr || !object->IsETSObjectType()) {
21553af6ab5fSopenharmony_ci        return nullptr;
21563af6ab5fSopenharmony_ci    }
21573af6ab5fSopenharmony_ci
21583af6ab5fSopenharmony_ci    return object->AsETSObjectType()->GetOriginalBaseType();
21593af6ab5fSopenharmony_ci}
21603af6ab5fSopenharmony_ci
21613af6ab5fSopenharmony_civoid ETSChecker::CheckValidGenericTypeParameter(Type *const argType, const lexer::SourcePosition &pos)
21623af6ab5fSopenharmony_ci{
21633af6ab5fSopenharmony_ci    if (!argType->IsETSEnumType()) {
21643af6ab5fSopenharmony_ci        return;
21653af6ab5fSopenharmony_ci    }
21663af6ab5fSopenharmony_ci    std::stringstream ss;
21673af6ab5fSopenharmony_ci    argType->ToString(ss);
21683af6ab5fSopenharmony_ci    LogTypeError("Type '" + ss.str() + "' is not valid for generic type arguments", pos);
21693af6ab5fSopenharmony_ci}
21703af6ab5fSopenharmony_ci
21713af6ab5fSopenharmony_cibool ETSChecker::CheckNumberOfTypeArguments(ETSObjectType *const type, ir::TSTypeParameterInstantiation *const typeArgs,
21723af6ab5fSopenharmony_ci                                            const lexer::SourcePosition &pos)
21733af6ab5fSopenharmony_ci{
21743af6ab5fSopenharmony_ci    auto const &typeParams = type->TypeArguments();
21753af6ab5fSopenharmony_ci    if (typeParams.empty()) {
21763af6ab5fSopenharmony_ci        if (typeArgs != nullptr) {
21773af6ab5fSopenharmony_ci            LogTypeError({"Type '", type, "' is not generic."}, pos);
21783af6ab5fSopenharmony_ci            return false;
21793af6ab5fSopenharmony_ci        }
21803af6ab5fSopenharmony_ci        return true;
21813af6ab5fSopenharmony_ci    }
21823af6ab5fSopenharmony_ci
21833af6ab5fSopenharmony_ci    size_t minimumTypeArgs = std::count_if(typeParams.begin(), typeParams.end(), [](Type *param) {
21843af6ab5fSopenharmony_ci        return param->AsETSTypeParameter()->GetDefaultType() == nullptr;
21853af6ab5fSopenharmony_ci    });
21863af6ab5fSopenharmony_ci    if (typeArgs == nullptr && minimumTypeArgs > 0) {
21873af6ab5fSopenharmony_ci        LogTypeError({"Type '", type, "' is generic but type argument were not provided."}, pos);
21883af6ab5fSopenharmony_ci        return false;
21893af6ab5fSopenharmony_ci    }
21903af6ab5fSopenharmony_ci
21913af6ab5fSopenharmony_ci    if (typeArgs != nullptr &&
21923af6ab5fSopenharmony_ci        ((minimumTypeArgs > typeArgs->Params().size()) || (typeParams.size() < typeArgs->Params().size()))) {
21933af6ab5fSopenharmony_ci        LogTypeError({"Type '", type, "' has ", minimumTypeArgs, " number of type parameters, but ",
21943af6ab5fSopenharmony_ci                      typeArgs->Params().size(), " type arguments were provided."},
21953af6ab5fSopenharmony_ci                     pos);
21963af6ab5fSopenharmony_ci        return false;
21973af6ab5fSopenharmony_ci    }
21983af6ab5fSopenharmony_ci    return true;
21993af6ab5fSopenharmony_ci}
22003af6ab5fSopenharmony_ci
22013af6ab5fSopenharmony_cibool ETSChecker::NeedTypeInference(const ir::ScriptFunction *lambda)
22023af6ab5fSopenharmony_ci{
22033af6ab5fSopenharmony_ci    if (lambda->ReturnTypeAnnotation() == nullptr) {
22043af6ab5fSopenharmony_ci        return true;
22053af6ab5fSopenharmony_ci    }
22063af6ab5fSopenharmony_ci    for (auto *const param : lambda->Params()) {
22073af6ab5fSopenharmony_ci        const auto *const lambdaParam = param->AsETSParameterExpression()->Ident();
22083af6ab5fSopenharmony_ci        if (lambdaParam->TypeAnnotation() == nullptr) {
22093af6ab5fSopenharmony_ci            return true;
22103af6ab5fSopenharmony_ci        }
22113af6ab5fSopenharmony_ci    }
22123af6ab5fSopenharmony_ci    return false;
22133af6ab5fSopenharmony_ci}
22143af6ab5fSopenharmony_ci
22153af6ab5fSopenharmony_cistd::vector<bool> ETSChecker::FindTypeInferenceArguments(const ArenaVector<ir::Expression *> &arguments)
22163af6ab5fSopenharmony_ci{
22173af6ab5fSopenharmony_ci    std::vector<bool> argTypeInferenceRequired(arguments.size());
22183af6ab5fSopenharmony_ci    size_t index = 0;
22193af6ab5fSopenharmony_ci    for (ir::Expression *arg : arguments) {
22203af6ab5fSopenharmony_ci        if (arg->IsArrowFunctionExpression()) {
22213af6ab5fSopenharmony_ci            ir::ScriptFunction *const lambda = arg->AsArrowFunctionExpression()->Function();
22223af6ab5fSopenharmony_ci            if (NeedTypeInference(lambda)) {
22233af6ab5fSopenharmony_ci                argTypeInferenceRequired[index] = true;
22243af6ab5fSopenharmony_ci            }
22253af6ab5fSopenharmony_ci        }
22263af6ab5fSopenharmony_ci        ++index;
22273af6ab5fSopenharmony_ci    }
22283af6ab5fSopenharmony_ci    return argTypeInferenceRequired;
22293af6ab5fSopenharmony_ci}
22303af6ab5fSopenharmony_ci
22313af6ab5fSopenharmony_cibool ETSChecker::CheckLambdaAssignableUnion(ir::AstNode *typeAnn, ir::ScriptFunction *lambda)
22323af6ab5fSopenharmony_ci{
22333af6ab5fSopenharmony_ci    for (auto *type : typeAnn->AsETSUnionType()->Types()) {
22343af6ab5fSopenharmony_ci        if (type->IsETSFunctionType()) {
22353af6ab5fSopenharmony_ci            return lambda->Params().size() == type->AsETSFunctionType()->Params().size();
22363af6ab5fSopenharmony_ci        }
22373af6ab5fSopenharmony_ci    }
22383af6ab5fSopenharmony_ci
22393af6ab5fSopenharmony_ci    return false;
22403af6ab5fSopenharmony_ci}
22413af6ab5fSopenharmony_ci
22423af6ab5fSopenharmony_civoid ETSChecker::InferTypesForLambda(ir::ScriptFunction *lambda, ir::ETSFunctionType *calleeType,
22433af6ab5fSopenharmony_ci                                     Signature *maybeSubstitutedFunctionSig)
22443af6ab5fSopenharmony_ci{
22453af6ab5fSopenharmony_ci    for (size_t i = 0; i < calleeType->Params().size(); ++i) {
22463af6ab5fSopenharmony_ci        const auto *const calleeParam = calleeType->Params()[i]->AsETSParameterExpression()->Ident();
22473af6ab5fSopenharmony_ci        auto *const lambdaParam = lambda->Params()[i]->AsETSParameterExpression()->Ident();
22483af6ab5fSopenharmony_ci        if (lambdaParam->TypeAnnotation() == nullptr) {
22493af6ab5fSopenharmony_ci            auto *const typeAnnotation = calleeParam->TypeAnnotation()->Clone(Allocator(), lambdaParam);
22503af6ab5fSopenharmony_ci            if (maybeSubstitutedFunctionSig != nullptr) {
22513af6ab5fSopenharmony_ci                ASSERT(maybeSubstitutedFunctionSig->Params().size() == calleeType->Params().size());
22523af6ab5fSopenharmony_ci                typeAnnotation->SetTsType(maybeSubstitutedFunctionSig->Params()[i]->TsType());
22533af6ab5fSopenharmony_ci            }
22543af6ab5fSopenharmony_ci            lambdaParam->SetTsTypeAnnotation(typeAnnotation);
22553af6ab5fSopenharmony_ci            typeAnnotation->SetParent(lambdaParam);
22563af6ab5fSopenharmony_ci        }
22573af6ab5fSopenharmony_ci    }
22583af6ab5fSopenharmony_ci    if (lambda->ReturnTypeAnnotation() == nullptr) {
22593af6ab5fSopenharmony_ci        auto *const returnTypeAnnotation = calleeType->ReturnType()->Clone(Allocator(), lambda);
22603af6ab5fSopenharmony_ci        if (maybeSubstitutedFunctionSig != nullptr) {
22613af6ab5fSopenharmony_ci            returnTypeAnnotation->SetTsType(maybeSubstitutedFunctionSig->ReturnType());
22623af6ab5fSopenharmony_ci        }
22633af6ab5fSopenharmony_ci        lambda->SetReturnTypeAnnotation(returnTypeAnnotation);
22643af6ab5fSopenharmony_ci    }
22653af6ab5fSopenharmony_ci}
22663af6ab5fSopenharmony_ci
22673af6ab5fSopenharmony_civoid ETSChecker::ModifyPreferredType(ir::ArrayExpression *const arrayExpr, Type *const newPreferredType)
22683af6ab5fSopenharmony_ci{
22693af6ab5fSopenharmony_ci    // After modifying the preferred type of an array expression, it needs to be rechecked at the call site
22703af6ab5fSopenharmony_ci    arrayExpr->SetPreferredType(newPreferredType);
22713af6ab5fSopenharmony_ci    arrayExpr->SetTsType(nullptr);
22723af6ab5fSopenharmony_ci
22733af6ab5fSopenharmony_ci    for (auto *const element : arrayExpr->Elements()) {
22743af6ab5fSopenharmony_ci        if (element->IsArrayExpression()) {
22753af6ab5fSopenharmony_ci            ModifyPreferredType(element->AsArrayExpression(), nullptr);
22763af6ab5fSopenharmony_ci        }
22773af6ab5fSopenharmony_ci    }
22783af6ab5fSopenharmony_ci}
22793af6ab5fSopenharmony_ci
22803af6ab5fSopenharmony_cibool ETSChecker::IsInLocalClass(const ir::AstNode *node) const
22813af6ab5fSopenharmony_ci{
22823af6ab5fSopenharmony_ci    while (node != nullptr) {
22833af6ab5fSopenharmony_ci        if (node->Type() == ir::AstNodeType::CLASS_DEFINITION) {
22843af6ab5fSopenharmony_ci            return node->AsClassDefinition()->IsLocal();
22853af6ab5fSopenharmony_ci        }
22863af6ab5fSopenharmony_ci        node = node->Parent();
22873af6ab5fSopenharmony_ci    }
22883af6ab5fSopenharmony_ci
22893af6ab5fSopenharmony_ci    return false;
22903af6ab5fSopenharmony_ci}
22913af6ab5fSopenharmony_ci
22923af6ab5fSopenharmony_ciir::Expression *ETSChecker::GenerateImplicitInstantiateArg(varbinder::LocalVariable *instantiateMethod,
22933af6ab5fSopenharmony_ci                                                           const std::string &className)
22943af6ab5fSopenharmony_ci{
22953af6ab5fSopenharmony_ci    auto callSignatures = instantiateMethod->TsType()->AsETSFunctionType()->CallSignatures();
22963af6ab5fSopenharmony_ci    ASSERT(!callSignatures.empty());
22973af6ab5fSopenharmony_ci    auto methodOwner = std::string(callSignatures[0]->Owner()->Name());
22983af6ab5fSopenharmony_ci    std::string implicitInstantiateArgument = "()=>{return new " + className + "()";
22993af6ab5fSopenharmony_ci    if (methodOwner != className) {
23003af6ab5fSopenharmony_ci        implicitInstantiateArgument.append(" as " + methodOwner);
23013af6ab5fSopenharmony_ci    }
23023af6ab5fSopenharmony_ci    implicitInstantiateArgument.append("}");
23033af6ab5fSopenharmony_ci
23043af6ab5fSopenharmony_ci    parser::Program program(Allocator(), VarBinder());
23053af6ab5fSopenharmony_ci    es2panda::CompilerOptions options;
23063af6ab5fSopenharmony_ci    auto parser = parser::ETSParser(&program, options, parser::ParserStatus::NO_OPTS);
23073af6ab5fSopenharmony_ci    auto *argExpr = parser.CreateExpression(implicitInstantiateArgument);
23083af6ab5fSopenharmony_ci    compiler::InitScopesPhaseETS::RunExternalNode(argExpr, &program);
23093af6ab5fSopenharmony_ci
23103af6ab5fSopenharmony_ci    return argExpr;
23113af6ab5fSopenharmony_ci}
23123af6ab5fSopenharmony_ci
23133af6ab5fSopenharmony_ciir::ClassProperty *ETSChecker::ClassPropToImplementationProp(ir::ClassProperty *classProp, varbinder::ClassScope *scope)
23143af6ab5fSopenharmony_ci{
23153af6ab5fSopenharmony_ci    classProp->Key()->AsIdentifier()->SetName(
23163af6ab5fSopenharmony_ci        util::UString(std::string(compiler::Signatures::PROPERTY) + classProp->Key()->AsIdentifier()->Name().Mutf8(),
23173af6ab5fSopenharmony_ci                      Allocator())
23183af6ab5fSopenharmony_ci            .View());
23193af6ab5fSopenharmony_ci    classProp->AddModifier(ir::ModifierFlags::PRIVATE);
23203af6ab5fSopenharmony_ci
23213af6ab5fSopenharmony_ci    auto *fieldDecl = Allocator()->New<varbinder::LetDecl>(classProp->Key()->AsIdentifier()->Name());
23223af6ab5fSopenharmony_ci    fieldDecl->BindNode(classProp);
23233af6ab5fSopenharmony_ci
23243af6ab5fSopenharmony_ci    auto fieldVar = scope->InstanceFieldScope()->AddDecl(Allocator(), fieldDecl, ScriptExtension::ETS);
23253af6ab5fSopenharmony_ci    fieldVar->AddFlag(varbinder::VariableFlags::PROPERTY);
23263af6ab5fSopenharmony_ci
23273af6ab5fSopenharmony_ci    classProp->Key()->SetVariable(fieldVar);
23283af6ab5fSopenharmony_ci    classProp->Key()->AsIdentifier()->SetVariable(fieldVar);
23293af6ab5fSopenharmony_ci    fieldVar->SetTsType(classProp->TsType());
23303af6ab5fSopenharmony_ci
23313af6ab5fSopenharmony_ci    return classProp;
23323af6ab5fSopenharmony_ci}
23333af6ab5fSopenharmony_ci
23343af6ab5fSopenharmony_civoid ETSChecker::GenerateGetterSetterBody(ArenaVector<ir::Statement *> &stmts, ArenaVector<ir::Expression *> &params,
23353af6ab5fSopenharmony_ci                                          ir::ClassProperty *const field, varbinder::FunctionParamScope *paramScope,
23363af6ab5fSopenharmony_ci                                          bool isSetter)
23373af6ab5fSopenharmony_ci{
23383af6ab5fSopenharmony_ci    auto *classDef = field->Parent()->AsClassDefinition();
23393af6ab5fSopenharmony_ci
23403af6ab5fSopenharmony_ci    ir::Expression *baseExpression;
23413af6ab5fSopenharmony_ci    if ((field->Modifiers() & ir::ModifierFlags::SUPER_OWNER) != 0U) {
23423af6ab5fSopenharmony_ci        baseExpression = Allocator()->New<ir::SuperExpression>();
23433af6ab5fSopenharmony_ci    } else {
23443af6ab5fSopenharmony_ci        baseExpression = Allocator()->New<ir::ThisExpression>();
23453af6ab5fSopenharmony_ci    }
23463af6ab5fSopenharmony_ci    baseExpression->SetParent(classDef);
23473af6ab5fSopenharmony_ci    baseExpression->SetTsType(classDef->TsType());
23483af6ab5fSopenharmony_ci
23493af6ab5fSopenharmony_ci    auto *memberExpression =
23503af6ab5fSopenharmony_ci        AllocNode<ir::MemberExpression>(baseExpression, field->Key()->AsIdentifier()->Clone(Allocator(), nullptr),
23513af6ab5fSopenharmony_ci                                        ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
23523af6ab5fSopenharmony_ci    memberExpression->SetTsType(field->TsType());
23533af6ab5fSopenharmony_ci    memberExpression->SetPropVar(field->Key()->Variable()->AsLocalVariable());
23543af6ab5fSopenharmony_ci    memberExpression->SetRange(classDef->Range());
23553af6ab5fSopenharmony_ci    if (memberExpression->ObjType() == nullptr && classDef->TsType() != nullptr) {
23563af6ab5fSopenharmony_ci        memberExpression->SetObjectType(classDef->TsType()->AsETSObjectType());
23573af6ab5fSopenharmony_ci    }
23583af6ab5fSopenharmony_ci
23593af6ab5fSopenharmony_ci    if (!isSetter) {
23603af6ab5fSopenharmony_ci        stmts.push_back(AllocNode<ir::ReturnStatement>(memberExpression));
23613af6ab5fSopenharmony_ci        return;
23623af6ab5fSopenharmony_ci    }
23633af6ab5fSopenharmony_ci
23643af6ab5fSopenharmony_ci    auto *paramIdent = field->Key()->AsIdentifier()->Clone(Allocator(), nullptr);
23653af6ab5fSopenharmony_ci    if (field->TypeAnnotation() != nullptr) {
23663af6ab5fSopenharmony_ci        auto *const typeAnnotation = field->TypeAnnotation()->Clone(Allocator(), paramIdent);
23673af6ab5fSopenharmony_ci        paramIdent->SetTsTypeAnnotation(typeAnnotation);
23683af6ab5fSopenharmony_ci    } else {
23693af6ab5fSopenharmony_ci        paramIdent->SetTsType(field->TsType());
23703af6ab5fSopenharmony_ci    }
23713af6ab5fSopenharmony_ci
23723af6ab5fSopenharmony_ci    auto *paramExpression = AllocNode<ir::ETSParameterExpression>(paramIdent, nullptr);
23733af6ab5fSopenharmony_ci    paramExpression->SetRange(paramIdent->Range());
23743af6ab5fSopenharmony_ci    auto *const paramVar = std::get<2>(paramScope->AddParamDecl(Allocator(), paramExpression));
23753af6ab5fSopenharmony_ci    paramExpression->SetVariable(paramVar);
23763af6ab5fSopenharmony_ci
23773af6ab5fSopenharmony_ci    params.push_back(paramExpression);
23783af6ab5fSopenharmony_ci
23793af6ab5fSopenharmony_ci    auto *assignmentExpression = AllocNode<ir::AssignmentExpression>(
23803af6ab5fSopenharmony_ci        memberExpression, paramExpression->Clone(Allocator(), nullptr), lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
23813af6ab5fSopenharmony_ci    assignmentExpression->SetTsType(paramVar->TsType());
23823af6ab5fSopenharmony_ci
23833af6ab5fSopenharmony_ci    assignmentExpression->SetRange({field->Start(), field->End()});
23843af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
23853af6ab5fSopenharmony_ci    stmts.push_back(AllocNode<ir::ExpressionStatement>(assignmentExpression));
23863af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
23873af6ab5fSopenharmony_ci    stmts.push_back(Allocator()->New<ir::ReturnStatement>(nullptr));
23883af6ab5fSopenharmony_ci}
23893af6ab5fSopenharmony_ci
23903af6ab5fSopenharmony_ciir::MethodDefinition *ETSChecker::GenerateDefaultGetterSetter(ir::ClassProperty *const property,
23913af6ab5fSopenharmony_ci                                                              ir::ClassProperty *const field,
23923af6ab5fSopenharmony_ci                                                              varbinder::ClassScope *classScope, bool isSetter,
23933af6ab5fSopenharmony_ci                                                              ETSChecker *checker)
23943af6ab5fSopenharmony_ci{
23953af6ab5fSopenharmony_ci    auto *paramScope = checker->Allocator()->New<varbinder::FunctionParamScope>(checker->Allocator(), classScope);
23963af6ab5fSopenharmony_ci    auto *functionScope = checker->Allocator()->New<varbinder::FunctionScope>(checker->Allocator(), paramScope);
23973af6ab5fSopenharmony_ci
23983af6ab5fSopenharmony_ci    functionScope->BindParamScope(paramScope);
23993af6ab5fSopenharmony_ci    paramScope->BindFunctionScope(functionScope);
24003af6ab5fSopenharmony_ci
24013af6ab5fSopenharmony_ci    ArenaVector<ir::Expression *> params(checker->Allocator()->Adapter());
24023af6ab5fSopenharmony_ci    ArenaVector<ir::Statement *> stmts(checker->Allocator()->Adapter());
24033af6ab5fSopenharmony_ci    checker->GenerateGetterSetterBody(stmts, params, field, paramScope, isSetter);
24043af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
24053af6ab5fSopenharmony_ci    auto *body = checker->AllocNode<ir::BlockStatement>(checker->Allocator(), std::move(stmts));
24063af6ab5fSopenharmony_ci    auto funcFlags = isSetter ? ir::ScriptFunctionFlags::SETTER : ir::ScriptFunctionFlags::GETTER;
24073af6ab5fSopenharmony_ci    auto *const returnTypeAnn = isSetter || field->TypeAnnotation() == nullptr
24083af6ab5fSopenharmony_ci                                    ? nullptr
24093af6ab5fSopenharmony_ci                                    : field->TypeAnnotation()->Clone(checker->Allocator(), nullptr);
24103af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
24113af6ab5fSopenharmony_ci    auto *func = checker->AllocNode<ir::ScriptFunction>(
24123af6ab5fSopenharmony_ci        checker->Allocator(),
24133af6ab5fSopenharmony_ci        ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), returnTypeAnn),
24143af6ab5fSopenharmony_ci                                                funcFlags, ir::ModifierFlags::PUBLIC, true});
24153af6ab5fSopenharmony_ci
24163af6ab5fSopenharmony_ci    if (!isSetter) {
24173af6ab5fSopenharmony_ci        func->AddFlag(ir::ScriptFunctionFlags::HAS_RETURN);
24183af6ab5fSopenharmony_ci    }
24193af6ab5fSopenharmony_ci    func->SetRange(field->Range());
24203af6ab5fSopenharmony_ci    func->SetScope(functionScope);
24213af6ab5fSopenharmony_ci    body->SetScope(functionScope);
24223af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
24233af6ab5fSopenharmony_ci    auto *methodIdent = property->Key()->AsIdentifier()->Clone(checker->Allocator(), nullptr);
24243af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
24253af6ab5fSopenharmony_ci    auto *funcExpr = checker->AllocNode<ir::FunctionExpression>(func);
24263af6ab5fSopenharmony_ci    funcExpr->SetRange(func->Range());
24273af6ab5fSopenharmony_ci    func->AddFlag(ir::ScriptFunctionFlags::METHOD);
24283af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
24293af6ab5fSopenharmony_ci    auto *method = checker->AllocNode<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD, methodIdent, funcExpr,
24303af6ab5fSopenharmony_ci                                                            ir::ModifierFlags::PUBLIC, checker->Allocator(), false);
24313af6ab5fSopenharmony_ci
24323af6ab5fSopenharmony_ci    auto *decl = checker->Allocator()->New<varbinder::FunctionDecl>(checker->Allocator(),
24333af6ab5fSopenharmony_ci                                                                    property->Key()->AsIdentifier()->Name(), method);
24343af6ab5fSopenharmony_ci    auto *var = checker->Allocator()->New<varbinder::LocalVariable>(decl, varbinder::VariableFlags::VAR);
24353af6ab5fSopenharmony_ci    var->AddFlag(varbinder::VariableFlags::METHOD);
24363af6ab5fSopenharmony_ci
24373af6ab5fSopenharmony_ci    methodIdent->SetVariable(var);
24383af6ab5fSopenharmony_ci
24393af6ab5fSopenharmony_ci    method->Id()->SetMutator();
24403af6ab5fSopenharmony_ci    method->SetRange(field->Range());
24413af6ab5fSopenharmony_ci    method->Function()->SetIdent(method->Id()->Clone(checker->Allocator(), nullptr));
24423af6ab5fSopenharmony_ci    method->Function()->AddModifier(method->Modifiers());
24433af6ab5fSopenharmony_ci    method->SetVariable(var);
24443af6ab5fSopenharmony_ci    method->SetParent(field->Parent());
24453af6ab5fSopenharmony_ci
24463af6ab5fSopenharmony_ci    paramScope->BindNode(func);
24473af6ab5fSopenharmony_ci    functionScope->BindNode(func);
24483af6ab5fSopenharmony_ci
24493af6ab5fSopenharmony_ci    auto classCtx = varbinder::LexicalScope<varbinder::ClassScope>::Enter(checker->VarBinder(), classScope);
24503af6ab5fSopenharmony_ci    checker->VarBinder()->AsETSBinder()->ResolveMethodDefinition(method);
24513af6ab5fSopenharmony_ci
24523af6ab5fSopenharmony_ci    functionScope->BindName(classScope->Node()->AsClassDefinition()->InternalName());
24533af6ab5fSopenharmony_ci    method->Check(checker);
24543af6ab5fSopenharmony_ci
24553af6ab5fSopenharmony_ci    return method;
24563af6ab5fSopenharmony_ci}
24573af6ab5fSopenharmony_ci
24583af6ab5fSopenharmony_ciir::ClassProperty *GetImplementationClassProp(ETSChecker *checker, ir::ClassProperty *interfaceProp,
24593af6ab5fSopenharmony_ci                                              ir::ClassProperty *originalProp, ETSObjectType *classType)
24603af6ab5fSopenharmony_ci{
24613af6ab5fSopenharmony_ci    bool isSuperOwner = ((originalProp->Modifiers() & ir::ModifierFlags::SUPER_OWNER) != 0U);
24623af6ab5fSopenharmony_ci    if (!isSuperOwner) {
24633af6ab5fSopenharmony_ci        auto *const classDef = classType->GetDeclNode()->AsClassDefinition();
24643af6ab5fSopenharmony_ci        auto *const scope = checker->Scope()->AsClassScope();
24653af6ab5fSopenharmony_ci        auto *const classProp = checker->ClassPropToImplementationProp(
24663af6ab5fSopenharmony_ci            interfaceProp->Clone(checker->Allocator(), originalProp->Parent()), scope);
24673af6ab5fSopenharmony_ci        classType->AddProperty<PropertyType::INSTANCE_FIELD>(classProp->Key()->Variable()->AsLocalVariable());
24683af6ab5fSopenharmony_ci        classDef->Body().push_back(classProp);
24693af6ab5fSopenharmony_ci        return classProp;
24703af6ab5fSopenharmony_ci    }
24713af6ab5fSopenharmony_ci
24723af6ab5fSopenharmony_ci    auto *const classProp = classType
24733af6ab5fSopenharmony_ci                                ->GetProperty(interfaceProp->Key()->AsIdentifier()->Name(),
24743af6ab5fSopenharmony_ci                                              PropertySearchFlags::SEARCH_ALL | PropertySearchFlags::SEARCH_IN_BASE)
24753af6ab5fSopenharmony_ci                                ->Declaration()
24763af6ab5fSopenharmony_ci                                ->Node()
24773af6ab5fSopenharmony_ci                                ->AsClassProperty();
24783af6ab5fSopenharmony_ci    classProp->AddModifier(ir::ModifierFlags::SUPER_OWNER);
24793af6ab5fSopenharmony_ci    return classProp;
24803af6ab5fSopenharmony_ci}
24813af6ab5fSopenharmony_ci
24823af6ab5fSopenharmony_cistatic void SetupGetterSetterFlags(ir::ClassProperty *originalProp, ETSObjectType *classType,
24833af6ab5fSopenharmony_ci                                   ir::MethodDefinition *getter, ir::MethodDefinition *setter, const bool inExternal)
24843af6ab5fSopenharmony_ci{
24853af6ab5fSopenharmony_ci    auto *const classDef = classType->GetDeclNode()->AsClassDefinition();
24863af6ab5fSopenharmony_ci    for (auto &method : {getter, setter}) {
24873af6ab5fSopenharmony_ci        if (method == nullptr) {
24883af6ab5fSopenharmony_ci            continue;
24893af6ab5fSopenharmony_ci        }
24903af6ab5fSopenharmony_ci
24913af6ab5fSopenharmony_ci        const auto mflag = method == getter ? ir::ModifierFlags::GETTER : ir::ModifierFlags::SETTER;
24923af6ab5fSopenharmony_ci        const auto tflag = method == getter ? TypeFlag::GETTER : TypeFlag::SETTER;
24933af6ab5fSopenharmony_ci
24943af6ab5fSopenharmony_ci        method->TsType()->AddTypeFlag(tflag);
24953af6ab5fSopenharmony_ci        method->Variable()->SetTsType(method->TsType());
24963af6ab5fSopenharmony_ci        if (((originalProp->Modifiers() & mflag) != 0U)) {
24973af6ab5fSopenharmony_ci            method->Function()->AddModifier(ir::ModifierFlags::OVERRIDE);
24983af6ab5fSopenharmony_ci        }
24993af6ab5fSopenharmony_ci
25003af6ab5fSopenharmony_ci        if (inExternal) {
25013af6ab5fSopenharmony_ci            method->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL);
25023af6ab5fSopenharmony_ci        }
25033af6ab5fSopenharmony_ci        method->SetParent(classDef);
25043af6ab5fSopenharmony_ci        classType->AddProperty<checker::PropertyType::INSTANCE_METHOD>(method->Variable()->AsLocalVariable());
25053af6ab5fSopenharmony_ci    }
25063af6ab5fSopenharmony_ci}
25073af6ab5fSopenharmony_ci
25083af6ab5fSopenharmony_civoid ETSChecker::GenerateGetterSetterPropertyAndMethod(ir::ClassProperty *originalProp, ETSObjectType *classType)
25093af6ab5fSopenharmony_ci{
25103af6ab5fSopenharmony_ci    auto *const classDef = classType->GetDeclNode()->AsClassDefinition();
25113af6ab5fSopenharmony_ci    auto *interfaceProp = originalProp->Clone(Allocator(), originalProp->Parent());
25123af6ab5fSopenharmony_ci    interfaceProp->ClearModifier(ir::ModifierFlags::GETTER_SETTER);
25133af6ab5fSopenharmony_ci
25143af6ab5fSopenharmony_ci    auto *const scope = Scope()->AsClassScope();
25153af6ab5fSopenharmony_ci    scope->InstanceFieldScope()->EraseBinding(interfaceProp->Key()->AsIdentifier()->Name());
25163af6ab5fSopenharmony_ci    interfaceProp->SetRange(originalProp->Range());
25173af6ab5fSopenharmony_ci
25183af6ab5fSopenharmony_ci    auto *const classProp = GetImplementationClassProp(this, interfaceProp, originalProp, classType);
25193af6ab5fSopenharmony_ci
25203af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
25213af6ab5fSopenharmony_ci    ir::MethodDefinition *getter = GenerateDefaultGetterSetter(interfaceProp, classProp, scope, false, this);
25223af6ab5fSopenharmony_ci    classDef->Body().push_back(getter);
25233af6ab5fSopenharmony_ci
25243af6ab5fSopenharmony_ci    const auto &name = getter->Key()->AsIdentifier()->Name();
25253af6ab5fSopenharmony_ci
25263af6ab5fSopenharmony_ci    ir::MethodDefinition *setter =
25273af6ab5fSopenharmony_ci        !classProp->IsConst()
25283af6ab5fSopenharmony_ci            ? GenerateDefaultGetterSetter(interfaceProp, classProp, Scope()->AsClassScope(), true, this)
25293af6ab5fSopenharmony_ci            : nullptr;
25303af6ab5fSopenharmony_ci
25313af6ab5fSopenharmony_ci    auto *const methodScope = scope->InstanceMethodScope();
25323af6ab5fSopenharmony_ci    auto *const decl = Allocator()->New<varbinder::FunctionDecl>(Allocator(), name, getter);
25333af6ab5fSopenharmony_ci    auto *var = methodScope->AddDecl(Allocator(), decl, ScriptExtension::ETS);
25343af6ab5fSopenharmony_ci
25353af6ab5fSopenharmony_ci    if (var == nullptr) {
25363af6ab5fSopenharmony_ci        auto *const prevDecl = methodScope->FindDecl(name);
25373af6ab5fSopenharmony_ci        for (const auto &method : {getter, setter}) {
25383af6ab5fSopenharmony_ci            if (method != nullptr) {
25393af6ab5fSopenharmony_ci                prevDecl->Node()->AsMethodDefinition()->AddOverload(method);
25403af6ab5fSopenharmony_ci            }
25413af6ab5fSopenharmony_ci        }
25423af6ab5fSopenharmony_ci        var = methodScope->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS);
25433af6ab5fSopenharmony_ci    }
25443af6ab5fSopenharmony_ci    var->AddFlag(varbinder::VariableFlags::METHOD);
25453af6ab5fSopenharmony_ci
25463af6ab5fSopenharmony_ci    SetupGetterSetterFlags(originalProp, classType, getter, setter, HasStatus(CheckerStatus::IN_EXTERNAL));
25473af6ab5fSopenharmony_ci
25483af6ab5fSopenharmony_ci    if (setter != nullptr) {
25493af6ab5fSopenharmony_ci        getter->Variable()->TsType()->AsETSFunctionType()->AddCallSignature(
25503af6ab5fSopenharmony_ci            setter->TsType()->AsETSFunctionType()->CallSignatures()[0]);
25513af6ab5fSopenharmony_ci    }
25523af6ab5fSopenharmony_ci
25533af6ab5fSopenharmony_ci    getter->Function()->Id()->SetVariable(var);
25543af6ab5fSopenharmony_ci    if (setter != nullptr) {
25553af6ab5fSopenharmony_ci        getter->AddOverload(setter);
25563af6ab5fSopenharmony_ci    }
25573af6ab5fSopenharmony_ci}
25583af6ab5fSopenharmony_ci
25593af6ab5fSopenharmony_ciType *ETSChecker::TryGettingFunctionTypeFromInvokeFunction(Type *type)
25603af6ab5fSopenharmony_ci{
25613af6ab5fSopenharmony_ci    if (type->IsETSObjectType() && type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
25623af6ab5fSopenharmony_ci        auto const propInvoke = type->AsETSObjectType()->GetProperty(FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME,
25633af6ab5fSopenharmony_ci                                                                     PropertySearchFlags::SEARCH_INSTANCE_METHOD);
25643af6ab5fSopenharmony_ci        ASSERT(propInvoke != nullptr);
25653af6ab5fSopenharmony_ci
25663af6ab5fSopenharmony_ci        return propInvoke->TsType();
25673af6ab5fSopenharmony_ci    }
25683af6ab5fSopenharmony_ci
25693af6ab5fSopenharmony_ci    return type;
25703af6ab5fSopenharmony_ci}
25713af6ab5fSopenharmony_ci
25723af6ab5fSopenharmony_cibool ETSChecker::TryTransformingToStaticInvoke(ir::Identifier *const ident, const Type *resolvedType)
25733af6ab5fSopenharmony_ci{
25743af6ab5fSopenharmony_ci    ASSERT(ident->Parent()->IsCallExpression());
25753af6ab5fSopenharmony_ci    ASSERT(ident->Parent()->AsCallExpression()->Callee() == ident);
25763af6ab5fSopenharmony_ci
25773af6ab5fSopenharmony_ci    if (!resolvedType->IsETSObjectType()) {
25783af6ab5fSopenharmony_ci        return false;
25793af6ab5fSopenharmony_ci    }
25803af6ab5fSopenharmony_ci
25813af6ab5fSopenharmony_ci    auto className = ident->Name();
25823af6ab5fSopenharmony_ci    std::string_view propertyName;
25833af6ab5fSopenharmony_ci
25843af6ab5fSopenharmony_ci    PropertySearchFlags searchFlag = PropertySearchFlags::SEARCH_IN_INTERFACES | PropertySearchFlags::SEARCH_IN_BASE |
25853af6ab5fSopenharmony_ci                                     PropertySearchFlags::SEARCH_STATIC_METHOD;
25863af6ab5fSopenharmony_ci    auto *instantiateMethod =
25873af6ab5fSopenharmony_ci        resolvedType->AsETSObjectType()->GetProperty(compiler::Signatures::STATIC_INSTANTIATE_METHOD, searchFlag);
25883af6ab5fSopenharmony_ci    auto *invokeMethod =
25893af6ab5fSopenharmony_ci        resolvedType->AsETSObjectType()->GetProperty(compiler::Signatures::STATIC_INVOKE_METHOD, searchFlag);
25903af6ab5fSopenharmony_ci    if (instantiateMethod != nullptr) {
25913af6ab5fSopenharmony_ci        propertyName = compiler::Signatures::STATIC_INSTANTIATE_METHOD;
25923af6ab5fSopenharmony_ci    } else if (invokeMethod != nullptr) {
25933af6ab5fSopenharmony_ci        propertyName = compiler::Signatures::STATIC_INVOKE_METHOD;
25943af6ab5fSopenharmony_ci    } else {
25953af6ab5fSopenharmony_ci        LogTypeError({"No static ", compiler::Signatures::STATIC_INVOKE_METHOD, " method and static ",
25963af6ab5fSopenharmony_ci                      compiler::Signatures::STATIC_INSTANTIATE_METHOD, " method in ", className, ". ", className,
25973af6ab5fSopenharmony_ci                      "() is not allowed."},
25983af6ab5fSopenharmony_ci                     ident->Start());
25993af6ab5fSopenharmony_ci        return true;
26003af6ab5fSopenharmony_ci    }
26013af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
26023af6ab5fSopenharmony_ci    auto *classId = AllocNode<ir::Identifier>(className, Allocator());
26033af6ab5fSopenharmony_ci    // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
26043af6ab5fSopenharmony_ci    auto *methodId = AllocNode<ir::Identifier>(propertyName, Allocator());
26053af6ab5fSopenharmony_ci    if (propertyName == compiler::Signatures::STATIC_INSTANTIATE_METHOD) {
26063af6ab5fSopenharmony_ci        methodId->SetVariable(instantiateMethod);
26073af6ab5fSopenharmony_ci    } else if (propertyName == compiler::Signatures::STATIC_INVOKE_METHOD) {
26083af6ab5fSopenharmony_ci        methodId->SetVariable(invokeMethod);
26093af6ab5fSopenharmony_ci    }
26103af6ab5fSopenharmony_ci
26113af6ab5fSopenharmony_ci    auto *transformedCallee =
26123af6ab5fSopenharmony_ci        // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
26133af6ab5fSopenharmony_ci        AllocNode<ir::MemberExpression>(classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
26143af6ab5fSopenharmony_ci
26153af6ab5fSopenharmony_ci    classId->SetRange(ident->Range());
26163af6ab5fSopenharmony_ci    methodId->SetRange(ident->Range());
26173af6ab5fSopenharmony_ci    transformedCallee->SetRange(ident->Range());
26183af6ab5fSopenharmony_ci
26193af6ab5fSopenharmony_ci    auto *callExpr = ident->Parent()->AsCallExpression();
26203af6ab5fSopenharmony_ci    transformedCallee->SetParent(callExpr);
26213af6ab5fSopenharmony_ci    callExpr->SetCallee(transformedCallee);
26223af6ab5fSopenharmony_ci
26233af6ab5fSopenharmony_ci    if (instantiateMethod != nullptr) {
26243af6ab5fSopenharmony_ci        // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint)
26253af6ab5fSopenharmony_ci        auto *argExpr = GenerateImplicitInstantiateArg(instantiateMethod, std::string(className));
26263af6ab5fSopenharmony_ci
26273af6ab5fSopenharmony_ci        argExpr->SetParent(callExpr);
26283af6ab5fSopenharmony_ci        argExpr->SetRange(ident->Range());
26293af6ab5fSopenharmony_ci
26303af6ab5fSopenharmony_ci        VarBinder()->AsETSBinder()->HandleCustomNodes(argExpr);
26313af6ab5fSopenharmony_ci
26323af6ab5fSopenharmony_ci        auto &arguments = callExpr->Arguments();
26333af6ab5fSopenharmony_ci        arguments.insert(arguments.begin(), argExpr);
26343af6ab5fSopenharmony_ci    }
26353af6ab5fSopenharmony_ci
26363af6ab5fSopenharmony_ci    return true;
26373af6ab5fSopenharmony_ci}
26383af6ab5fSopenharmony_ci
26393af6ab5fSopenharmony_cichecker::ETSObjectType *ETSChecker::CreateSyntheticType(util::StringView const &syntheticName,
26403af6ab5fSopenharmony_ci                                                        checker::ETSObjectType *lastObjectType, ir::Identifier *id)
26413af6ab5fSopenharmony_ci{
26423af6ab5fSopenharmony_ci    auto *syntheticObjType = Allocator()->New<checker::ETSObjectType>(Allocator(), syntheticName, syntheticName, id,
26433af6ab5fSopenharmony_ci                                                                      checker::ETSObjectFlags::NO_OPTS);
26443af6ab5fSopenharmony_ci
26453af6ab5fSopenharmony_ci    auto *classDecl = Allocator()->New<varbinder::ClassDecl>(syntheticName);
26463af6ab5fSopenharmony_ci    varbinder::LocalVariable *var =
26473af6ab5fSopenharmony_ci        Allocator()->New<varbinder::LocalVariable>(classDecl, varbinder::VariableFlags::CLASS);
26483af6ab5fSopenharmony_ci    var->SetTsType(syntheticObjType);
26493af6ab5fSopenharmony_ci    lastObjectType->AddProperty<checker::PropertyType::STATIC_FIELD>(var);
26503af6ab5fSopenharmony_ci    syntheticObjType->SetEnclosingType(lastObjectType);
26513af6ab5fSopenharmony_ci    return syntheticObjType;
26523af6ab5fSopenharmony_ci}
26533af6ab5fSopenharmony_ci
26543af6ab5fSopenharmony_civoid ETSChecker::ImportNamespaceObjectTypeAddReExportType(ir::ETSImportDeclaration *importDecl,
26553af6ab5fSopenharmony_ci                                                          checker::ETSObjectType *lastObjectType, ir::Identifier *ident)
26563af6ab5fSopenharmony_ci{
26573af6ab5fSopenharmony_ci    for (auto item : VarBinder()->AsETSBinder()->ReExportImports()) {
26583af6ab5fSopenharmony_ci        if (!importDecl->ResolvedSource()->Str().Is(item->GetProgramPath().Mutf8())) {
26593af6ab5fSopenharmony_ci            continue;
26603af6ab5fSopenharmony_ci        }
26613af6ab5fSopenharmony_ci        auto *reExportType = GetImportSpecifierObjectType(item->GetETSImportDeclarations(), ident);
26623af6ab5fSopenharmony_ci        lastObjectType->AddReExports(reExportType);
26633af6ab5fSopenharmony_ci        for (auto node : importDecl->Specifiers()) {
26643af6ab5fSopenharmony_ci            if (node->IsImportSpecifier()) {
26653af6ab5fSopenharmony_ci                auto specifier = node->AsImportSpecifier();
26663af6ab5fSopenharmony_ci                lastObjectType->AddReExportAlias(specifier->Imported()->Name(), specifier->Local()->Name());
26673af6ab5fSopenharmony_ci            }
26683af6ab5fSopenharmony_ci        }
26693af6ab5fSopenharmony_ci    }
26703af6ab5fSopenharmony_ci}
26713af6ab5fSopenharmony_ci
26723af6ab5fSopenharmony_ciETSObjectType *ETSChecker::GetImportSpecifierObjectType(ir::ETSImportDeclaration *importDecl, ir::Identifier *ident)
26733af6ab5fSopenharmony_ci{
26743af6ab5fSopenharmony_ci    auto importPath = importDecl->ResolvedSource()->Str();
26753af6ab5fSopenharmony_ci    parser::Program *program =
26763af6ab5fSopenharmony_ci        SelectEntryOrExternalProgram(static_cast<varbinder::ETSBinder *>(VarBinder()), importPath);
26773af6ab5fSopenharmony_ci    std::vector<util::StringView> syntheticNames = GetNameForSynteticObjectType(program->ModuleName());
26783af6ab5fSopenharmony_ci    ASSERT(!syntheticNames.empty());
26793af6ab5fSopenharmony_ci    auto assemblerName = syntheticNames[0];
26803af6ab5fSopenharmony_ci
26813af6ab5fSopenharmony_ci    if (!program->OmitModuleName()) {
26823af6ab5fSopenharmony_ci        assemblerName = util::UString(assemblerName.Mutf8()
26833af6ab5fSopenharmony_ci                                          .append(compiler::Signatures::METHOD_SEPARATOR)
26843af6ab5fSopenharmony_ci                                          .append(compiler::Signatures::ETS_GLOBAL),
26853af6ab5fSopenharmony_ci                                      Allocator())
26863af6ab5fSopenharmony_ci                            .View();
26873af6ab5fSopenharmony_ci    }
26883af6ab5fSopenharmony_ci
26893af6ab5fSopenharmony_ci    auto *moduleObjectType =
26903af6ab5fSopenharmony_ci        Allocator()->New<checker::ETSObjectType>(Allocator(), syntheticNames[0], assemblerName,
26913af6ab5fSopenharmony_ci                                                 std::make_tuple(ident, checker::ETSObjectFlags::CLASS, Relation()));
26923af6ab5fSopenharmony_ci
26933af6ab5fSopenharmony_ci    auto *rootDecl = Allocator()->New<varbinder::ClassDecl>(syntheticNames[0]);
26943af6ab5fSopenharmony_ci    varbinder::LocalVariable *rootVar =
26953af6ab5fSopenharmony_ci        Allocator()->New<varbinder::LocalVariable>(rootDecl, varbinder::VariableFlags::NONE);
26963af6ab5fSopenharmony_ci    rootVar->SetTsType(moduleObjectType);
26973af6ab5fSopenharmony_ci
26983af6ab5fSopenharmony_ci    syntheticNames.erase(syntheticNames.begin());
26993af6ab5fSopenharmony_ci    checker::ETSObjectType *lastObjectType(moduleObjectType);
27003af6ab5fSopenharmony_ci
27013af6ab5fSopenharmony_ci    for (const auto &syntheticName : syntheticNames) {
27023af6ab5fSopenharmony_ci        lastObjectType = CreateSyntheticType(syntheticName, lastObjectType, ident);
27033af6ab5fSopenharmony_ci    }
27043af6ab5fSopenharmony_ci
27053af6ab5fSopenharmony_ci    ImportNamespaceObjectTypeAddReExportType(importDecl, lastObjectType, ident);
27063af6ab5fSopenharmony_ci    SetPropertiesForModuleObject(lastObjectType, importPath,
27073af6ab5fSopenharmony_ci                                 importDecl->Specifiers()[0]->IsImportNamespaceSpecifier() ? nullptr : importDecl);
27083af6ab5fSopenharmony_ci    SetrModuleObjectTsType(ident, lastObjectType);
27093af6ab5fSopenharmony_ci
27103af6ab5fSopenharmony_ci    return moduleObjectType;
27113af6ab5fSopenharmony_ci}
27123af6ab5fSopenharmony_ci}  // namespace ark::es2panda::checker
2713