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 "memberExpression.h"
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_ci#include "checker/TSchecker.h"
193af6ab5fSopenharmony_ci#include "checker/ets/castingContext.h"
203af6ab5fSopenharmony_ci#include "checker/types/ets/etsTupleType.h"
213af6ab5fSopenharmony_ci#include "compiler/core/ETSGen.h"
223af6ab5fSopenharmony_ci#include "compiler/core/pandagen.h"
233af6ab5fSopenharmony_ci#include "ir/astDump.h"
243af6ab5fSopenharmony_ci#include "ir/srcDump.h"
253af6ab5fSopenharmony_ci
263af6ab5fSopenharmony_cinamespace ark::es2panda::ir {
273af6ab5fSopenharmony_ciMemberExpression::MemberExpression([[maybe_unused]] Tag const tag, MemberExpression const &other,
283af6ab5fSopenharmony_ci                                   ArenaAllocator *allocator)
293af6ab5fSopenharmony_ci    : MemberExpression(other)
303af6ab5fSopenharmony_ci{
313af6ab5fSopenharmony_ci    object_ = other.object_ != nullptr ? other.object_->Clone(allocator, this)->AsExpression() : nullptr;
323af6ab5fSopenharmony_ci    property_ = other.property_ != nullptr ? other.property_->Clone(allocator, this)->AsExpression() : nullptr;
333af6ab5fSopenharmony_ci}
343af6ab5fSopenharmony_ci
353af6ab5fSopenharmony_cibool MemberExpression::IsPrivateReference() const noexcept
363af6ab5fSopenharmony_ci{
373af6ab5fSopenharmony_ci    return property_->IsIdentifier() && property_->AsIdentifier()->IsPrivateIdent();
383af6ab5fSopenharmony_ci}
393af6ab5fSopenharmony_ci
403af6ab5fSopenharmony_civoid MemberExpression::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName)
413af6ab5fSopenharmony_ci{
423af6ab5fSopenharmony_ci    if (auto *transformedNode = cb(object_); object_ != transformedNode) {
433af6ab5fSopenharmony_ci        object_->SetTransformedNode(transformationName, transformedNode);
443af6ab5fSopenharmony_ci        object_ = transformedNode->AsExpression();
453af6ab5fSopenharmony_ci    }
463af6ab5fSopenharmony_ci
473af6ab5fSopenharmony_ci    if (auto *transformedNode = cb(property_); property_ != transformedNode) {
483af6ab5fSopenharmony_ci        property_->SetTransformedNode(transformationName, transformedNode);
493af6ab5fSopenharmony_ci        property_ = transformedNode->AsExpression();
503af6ab5fSopenharmony_ci    }
513af6ab5fSopenharmony_ci}
523af6ab5fSopenharmony_ci
533af6ab5fSopenharmony_civoid MemberExpression::Iterate(const NodeTraverser &cb) const
543af6ab5fSopenharmony_ci{
553af6ab5fSopenharmony_ci    cb(object_);
563af6ab5fSopenharmony_ci    cb(property_);
573af6ab5fSopenharmony_ci}
583af6ab5fSopenharmony_ci
593af6ab5fSopenharmony_civoid MemberExpression::Dump(ir::AstDumper *dumper) const
603af6ab5fSopenharmony_ci{
613af6ab5fSopenharmony_ci    dumper->Add({{"type", "MemberExpression"},
623af6ab5fSopenharmony_ci                 {"object", object_},
633af6ab5fSopenharmony_ci                 {"property", property_},
643af6ab5fSopenharmony_ci                 {"computed", computed_},
653af6ab5fSopenharmony_ci                 {"optional", IsOptional()}});
663af6ab5fSopenharmony_ci}
673af6ab5fSopenharmony_ci
683af6ab5fSopenharmony_civoid MemberExpression::Dump(ir::SrcDumper *dumper) const
693af6ab5fSopenharmony_ci{
703af6ab5fSopenharmony_ci    ASSERT(object_ != nullptr);
713af6ab5fSopenharmony_ci    ASSERT(property_ != nullptr);
723af6ab5fSopenharmony_ci
733af6ab5fSopenharmony_ci    object_->Dump(dumper);
743af6ab5fSopenharmony_ci    if (IsOptional()) {
753af6ab5fSopenharmony_ci        dumper->Add("?");
763af6ab5fSopenharmony_ci        if ((MemberExpressionKind::ELEMENT_ACCESS & kind_) != 0U) {
773af6ab5fSopenharmony_ci            dumper->Add(".");
783af6ab5fSopenharmony_ci        }
793af6ab5fSopenharmony_ci    }
803af6ab5fSopenharmony_ci    if ((MemberExpressionKind::ELEMENT_ACCESS & kind_) != 0U) {
813af6ab5fSopenharmony_ci        dumper->Add("[");
823af6ab5fSopenharmony_ci        property_->Dump(dumper);
833af6ab5fSopenharmony_ci        dumper->Add("]");
843af6ab5fSopenharmony_ci    } else {
853af6ab5fSopenharmony_ci        dumper->Add(".");
863af6ab5fSopenharmony_ci        property_->Dump(dumper);
873af6ab5fSopenharmony_ci    }
883af6ab5fSopenharmony_ci    if ((parent_ != nullptr) && (parent_->IsBlockStatement() || parent_->IsBlockExpression())) {
893af6ab5fSopenharmony_ci        dumper->Add(";");
903af6ab5fSopenharmony_ci        dumper->Endl();
913af6ab5fSopenharmony_ci    }
923af6ab5fSopenharmony_ci}
933af6ab5fSopenharmony_ci
943af6ab5fSopenharmony_civoid MemberExpression::LoadRhs(compiler::PandaGen *pg) const
953af6ab5fSopenharmony_ci{
963af6ab5fSopenharmony_ci    compiler::RegScope rs(pg);
973af6ab5fSopenharmony_ci    bool isSuper = object_->IsSuperExpression();
983af6ab5fSopenharmony_ci    compiler::Operand prop = pg->ToPropertyKey(property_, computed_, isSuper);
993af6ab5fSopenharmony_ci
1003af6ab5fSopenharmony_ci    if (isSuper) {
1013af6ab5fSopenharmony_ci        pg->LoadSuperProperty(this, prop);
1023af6ab5fSopenharmony_ci    } else if (IsPrivateReference()) {
1033af6ab5fSopenharmony_ci        const auto &name = property_->AsIdentifier()->Name();
1043af6ab5fSopenharmony_ci        compiler::VReg objReg = pg->AllocReg();
1053af6ab5fSopenharmony_ci        pg->StoreAccumulator(this, objReg);
1063af6ab5fSopenharmony_ci        compiler::VReg ctor = pg->AllocReg();
1073af6ab5fSopenharmony_ci        compiler::Function::LoadClassContexts(this, pg, ctor, name);
1083af6ab5fSopenharmony_ci        pg->ClassPrivateFieldGet(this, ctor, objReg, name);
1093af6ab5fSopenharmony_ci    } else {
1103af6ab5fSopenharmony_ci        pg->LoadObjProperty(this, prop);
1113af6ab5fSopenharmony_ci    }
1123af6ab5fSopenharmony_ci}
1133af6ab5fSopenharmony_ci
1143af6ab5fSopenharmony_civoid MemberExpression::CompileToRegs(compiler::PandaGen *pg, compiler::VReg object, compiler::VReg property) const
1153af6ab5fSopenharmony_ci{
1163af6ab5fSopenharmony_ci    object_->Compile(pg);
1173af6ab5fSopenharmony_ci    pg->StoreAccumulator(this, object);
1183af6ab5fSopenharmony_ci
1193af6ab5fSopenharmony_ci    pg->OptionalChainCheck(IsOptional(), object);
1203af6ab5fSopenharmony_ci
1213af6ab5fSopenharmony_ci    if (!computed_) {
1223af6ab5fSopenharmony_ci        pg->LoadAccumulatorString(this, property_->AsIdentifier()->Name());
1233af6ab5fSopenharmony_ci    } else {
1243af6ab5fSopenharmony_ci        property_->Compile(pg);
1253af6ab5fSopenharmony_ci    }
1263af6ab5fSopenharmony_ci
1273af6ab5fSopenharmony_ci    pg->StoreAccumulator(this, property);
1283af6ab5fSopenharmony_ci}
1293af6ab5fSopenharmony_ci
1303af6ab5fSopenharmony_civoid MemberExpression::Compile(compiler::PandaGen *pg) const
1313af6ab5fSopenharmony_ci{
1323af6ab5fSopenharmony_ci    pg->GetAstCompiler()->Compile(this);
1333af6ab5fSopenharmony_ci}
1343af6ab5fSopenharmony_ci
1353af6ab5fSopenharmony_civoid MemberExpression::CompileToReg(compiler::PandaGen *pg, compiler::VReg objReg) const
1363af6ab5fSopenharmony_ci{
1373af6ab5fSopenharmony_ci    object_->Compile(pg);
1383af6ab5fSopenharmony_ci    pg->StoreAccumulator(this, objReg);
1393af6ab5fSopenharmony_ci    pg->OptionalChainCheck(IsOptional(), objReg);
1403af6ab5fSopenharmony_ci    LoadRhs(pg);
1413af6ab5fSopenharmony_ci}
1423af6ab5fSopenharmony_ci
1433af6ab5fSopenharmony_civoid MemberExpression::Compile(compiler::ETSGen *etsg) const
1443af6ab5fSopenharmony_ci{
1453af6ab5fSopenharmony_ci    etsg->GetAstCompiler()->Compile(this);
1463af6ab5fSopenharmony_ci}
1473af6ab5fSopenharmony_ci
1483af6ab5fSopenharmony_cichecker::Type *MemberExpression::Check(checker::TSChecker *checker)
1493af6ab5fSopenharmony_ci{
1503af6ab5fSopenharmony_ci    return checker->GetAnalyzer()->Check(this);
1513af6ab5fSopenharmony_ci}
1523af6ab5fSopenharmony_ci
1533af6ab5fSopenharmony_cistd::pair<checker::Type *, varbinder::LocalVariable *> MemberExpression::ResolveEnumMember(checker::ETSChecker *checker,
1543af6ab5fSopenharmony_ci                                                                                           checker::Type *type) const
1553af6ab5fSopenharmony_ci{
1563af6ab5fSopenharmony_ci    auto const *const enumInterface = [type]() -> checker::ETSEnumType const * {
1573af6ab5fSopenharmony_ci        if (type->IsETSIntEnumType()) {
1583af6ab5fSopenharmony_ci            return type->AsETSIntEnumType();
1593af6ab5fSopenharmony_ci        }
1603af6ab5fSopenharmony_ci        return type->AsETSStringEnumType();
1613af6ab5fSopenharmony_ci    }();
1623af6ab5fSopenharmony_ci
1633af6ab5fSopenharmony_ci    if (parent_->Type() == ir::AstNodeType::CALL_EXPRESSION && parent_->AsCallExpression()->Callee() == this) {
1643af6ab5fSopenharmony_ci        return {enumInterface->LookupMethod(checker, object_, property_->AsIdentifier()), nullptr};
1653af6ab5fSopenharmony_ci    }
1663af6ab5fSopenharmony_ci
1673af6ab5fSopenharmony_ci    auto *const literalType = enumInterface->LookupConstant(checker, object_, property_->AsIdentifier());
1683af6ab5fSopenharmony_ci    if (literalType == nullptr) {
1693af6ab5fSopenharmony_ci        return {nullptr, nullptr};
1703af6ab5fSopenharmony_ci    }
1713af6ab5fSopenharmony_ci    return {literalType, literalType->GetMemberVar()};
1723af6ab5fSopenharmony_ci}
1733af6ab5fSopenharmony_ci
1743af6ab5fSopenharmony_cistd::pair<checker::Type *, varbinder::LocalVariable *> MemberExpression::ResolveObjectMember(
1753af6ab5fSopenharmony_ci    checker::ETSChecker *checker) const
1763af6ab5fSopenharmony_ci{
1773af6ab5fSopenharmony_ci    auto resolveRes = checker->ResolveMemberReference(this, objType_);
1783af6ab5fSopenharmony_ci    switch (resolveRes.size()) {
1793af6ab5fSopenharmony_ci        case 0U: {
1803af6ab5fSopenharmony_ci            /* resolution failed, error already reported */
1813af6ab5fSopenharmony_ci            return {nullptr, nullptr};
1823af6ab5fSopenharmony_ci        }
1833af6ab5fSopenharmony_ci        case 1U: {
1843af6ab5fSopenharmony_ci            if (resolveRes[0]->Kind() == checker::ResolvedKind::PROPERTY) {
1853af6ab5fSopenharmony_ci                auto var = resolveRes[0]->Variable()->AsLocalVariable();
1863af6ab5fSopenharmony_ci                checker->ValidatePropertyAccess(var, objType_, property_->Start());
1873af6ab5fSopenharmony_ci                return {checker->GetTypeOfVariable(var), var};
1883af6ab5fSopenharmony_ci            }
1893af6ab5fSopenharmony_ci            return {checker->GetTypeOfVariable(resolveRes[0]->Variable()), nullptr};
1903af6ab5fSopenharmony_ci        }
1913af6ab5fSopenharmony_ci        case 2U: {
1923af6ab5fSopenharmony_ci            auto classMethodType = checker->GetTypeOfVariable(resolveRes[1]->Variable());
1933af6ab5fSopenharmony_ci            auto extensionMethodType = checker->GetTypeOfVariable(resolveRes[0]->Variable());
1943af6ab5fSopenharmony_ci            auto *resolvedType = extensionMethodType;
1953af6ab5fSopenharmony_ci            if (classMethodType->IsETSFunctionType()) {
1963af6ab5fSopenharmony_ci                ASSERT(extensionMethodType->IsETSFunctionType());
1973af6ab5fSopenharmony_ci                resolvedType = checker->CreateETSExtensionFuncHelperType(classMethodType->AsETSFunctionType(),
1983af6ab5fSopenharmony_ci                                                                         extensionMethodType->AsETSFunctionType());
1993af6ab5fSopenharmony_ci            }
2003af6ab5fSopenharmony_ci            return {resolvedType, nullptr};
2013af6ab5fSopenharmony_ci        }
2023af6ab5fSopenharmony_ci        default: {
2033af6ab5fSopenharmony_ci            UNREACHABLE();
2043af6ab5fSopenharmony_ci        }
2053af6ab5fSopenharmony_ci    }
2063af6ab5fSopenharmony_ci}
2073af6ab5fSopenharmony_ci
2083af6ab5fSopenharmony_cichecker::Type *MemberExpression::TraverseUnionMember(checker::ETSChecker *checker, checker::ETSUnionType *unionType,
2093af6ab5fSopenharmony_ci                                                     checker::Type *commonPropType)
2103af6ab5fSopenharmony_ci
2113af6ab5fSopenharmony_ci{
2123af6ab5fSopenharmony_ci    auto const addPropType = [this, checker, &commonPropType](checker::Type *memberType) {
2133af6ab5fSopenharmony_ci        if (commonPropType != nullptr && commonPropType != memberType) {
2143af6ab5fSopenharmony_ci            checker->LogTypeError("Member type must be the same for all union objects.", Start());
2153af6ab5fSopenharmony_ci        } else {
2163af6ab5fSopenharmony_ci            commonPropType = memberType;
2173af6ab5fSopenharmony_ci        }
2183af6ab5fSopenharmony_ci    };
2193af6ab5fSopenharmony_ci    for (auto *const type : unionType->ConstituentTypes()) {
2203af6ab5fSopenharmony_ci        auto *const apparent = checker->GetApparentType(type);
2213af6ab5fSopenharmony_ci        if (apparent->IsETSObjectType()) {
2223af6ab5fSopenharmony_ci            SetObjectType(apparent->AsETSObjectType());
2233af6ab5fSopenharmony_ci            addPropType(ResolveObjectMember(checker).first);
2243af6ab5fSopenharmony_ci        } else if (apparent->IsETSEnumType()) {
2253af6ab5fSopenharmony_ci            addPropType(ResolveEnumMember(checker, apparent).first);
2263af6ab5fSopenharmony_ci        } else {
2273af6ab5fSopenharmony_ci            checker->LogTypeError({"Type ", unionType, " is illegal in union member expression."}, Start());
2283af6ab5fSopenharmony_ci        }
2293af6ab5fSopenharmony_ci    }
2303af6ab5fSopenharmony_ci    return commonPropType;
2313af6ab5fSopenharmony_ci}
2323af6ab5fSopenharmony_ci
2333af6ab5fSopenharmony_cichecker::Type *MemberExpression::CheckUnionMember(checker::ETSChecker *checker, checker::Type *baseType)
2343af6ab5fSopenharmony_ci{
2353af6ab5fSopenharmony_ci    auto *const unionType = baseType->AsETSUnionType();
2363af6ab5fSopenharmony_ci    auto *const commonPropType = TraverseUnionMember(checker, unionType, nullptr);
2373af6ab5fSopenharmony_ci    SetObjectType(checker->GlobalETSObjectType());
2383af6ab5fSopenharmony_ci    return commonPropType;
2393af6ab5fSopenharmony_ci}
2403af6ab5fSopenharmony_ci
2413af6ab5fSopenharmony_cichecker::Type *MemberExpression::AdjustType(checker::ETSChecker *checker, checker::Type *type)
2423af6ab5fSopenharmony_ci{
2433af6ab5fSopenharmony_ci    auto *const objType = checker->GetApparentType(Object()->TsType());
2443af6ab5fSopenharmony_ci    if (PropVar() != nullptr) {  // access erased property type
2453af6ab5fSopenharmony_ci        uncheckedType_ = checker->GuaranteedTypeForUncheckedPropertyAccess(PropVar());
2463af6ab5fSopenharmony_ci    } else if (IsComputed() && objType->IsETSArrayType()) {  // access erased array or tuple type
2473af6ab5fSopenharmony_ci        uncheckedType_ = checker->GuaranteedTypeForUncheckedCast(objType->AsETSArrayType()->ElementType(), type);
2483af6ab5fSopenharmony_ci    }
2493af6ab5fSopenharmony_ci    SetTsType(type == nullptr ? checker->GlobalTypeError() : type);
2503af6ab5fSopenharmony_ci    return TsTypeOrError();
2513af6ab5fSopenharmony_ci}
2523af6ab5fSopenharmony_ci
2533af6ab5fSopenharmony_cichecker::Type *MemberExpression::SetAndAdjustType(checker::ETSChecker *checker, checker::ETSObjectType *objectType)
2543af6ab5fSopenharmony_ci{
2553af6ab5fSopenharmony_ci    SetObjectType(objectType);
2563af6ab5fSopenharmony_ci    auto [resType, resVar] = ResolveObjectMember(checker);
2573af6ab5fSopenharmony_ci    if (resType == nullptr) {
2583af6ab5fSopenharmony_ci        SetTsType(checker->GlobalTypeError());
2593af6ab5fSopenharmony_ci        return checker->GlobalTypeError();
2603af6ab5fSopenharmony_ci    }
2613af6ab5fSopenharmony_ci    SetPropVar(resVar);
2623af6ab5fSopenharmony_ci    return AdjustType(checker, resType);
2633af6ab5fSopenharmony_ci}
2643af6ab5fSopenharmony_ci
2653af6ab5fSopenharmony_cibool MemberExpression::CheckArrayIndexValue(checker::ETSChecker *checker) const
2663af6ab5fSopenharmony_ci{
2673af6ab5fSopenharmony_ci    std::size_t index;
2683af6ab5fSopenharmony_ci
2693af6ab5fSopenharmony_ci    auto const &number = property_->AsNumberLiteral()->Number();
2703af6ab5fSopenharmony_ci
2713af6ab5fSopenharmony_ci    if (number.IsInteger()) {
2723af6ab5fSopenharmony_ci        auto const value = number.GetLong();
2733af6ab5fSopenharmony_ci        if (value < 0) {
2743af6ab5fSopenharmony_ci            checker->LogTypeError("Index value cannot be less than zero.", property_->Start());
2753af6ab5fSopenharmony_ci            return false;
2763af6ab5fSopenharmony_ci        }
2773af6ab5fSopenharmony_ci        index = static_cast<std::size_t>(value);
2783af6ab5fSopenharmony_ci    } else if (number.IsReal()) {
2793af6ab5fSopenharmony_ci        double value = number.GetDouble();
2803af6ab5fSopenharmony_ci        double fraction = std::modf(value, &value);
2813af6ab5fSopenharmony_ci        if (value < 0.0 || fraction >= std::numeric_limits<double>::epsilon()) {
2823af6ab5fSopenharmony_ci            checker->LogTypeError("Index value cannot be less than zero or fractional.", property_->Start());
2833af6ab5fSopenharmony_ci            return false;
2843af6ab5fSopenharmony_ci        }
2853af6ab5fSopenharmony_ci        index = static_cast<std::size_t>(value);
2863af6ab5fSopenharmony_ci    } else {
2873af6ab5fSopenharmony_ci        UNREACHABLE();
2883af6ab5fSopenharmony_ci    }
2893af6ab5fSopenharmony_ci
2903af6ab5fSopenharmony_ci    if (object_->IsArrayExpression() && object_->AsArrayExpression()->Elements().size() <= index) {
2913af6ab5fSopenharmony_ci        checker->LogTypeError("Index value cannot be greater than or equal to the array size.", property_->Start());
2923af6ab5fSopenharmony_ci        return false;
2933af6ab5fSopenharmony_ci    }
2943af6ab5fSopenharmony_ci
2953af6ab5fSopenharmony_ci    return true;
2963af6ab5fSopenharmony_ci}
2973af6ab5fSopenharmony_ci
2983af6ab5fSopenharmony_cichecker::Type *MemberExpression::CheckIndexAccessMethod(checker::ETSChecker *checker)
2993af6ab5fSopenharmony_ci{
3003af6ab5fSopenharmony_ci    checker::PropertySearchFlags searchFlag =
3013af6ab5fSopenharmony_ci        checker::PropertySearchFlags::SEARCH_METHOD | checker::PropertySearchFlags::IS_FUNCTIONAL;
3023af6ab5fSopenharmony_ci    searchFlag |= checker::PropertySearchFlags::SEARCH_IN_BASE | checker::PropertySearchFlags::SEARCH_IN_INTERFACES;
3033af6ab5fSopenharmony_ci    // NOTE(DZ) maybe we need to exclude static methods: search_flag &= ~(checker::PropertySearchFlags::SEARCH_STATIC);
3043af6ab5fSopenharmony_ci
3053af6ab5fSopenharmony_ci    if (objType_->HasTypeFlag(checker::TypeFlag::GENERIC)) {
3063af6ab5fSopenharmony_ci        searchFlag |= checker::PropertySearchFlags::SEARCH_ALL;
3073af6ab5fSopenharmony_ci    }
3083af6ab5fSopenharmony_ci
3093af6ab5fSopenharmony_ci    bool const isSetter = Parent()->IsAssignmentExpression() && Parent()->AsAssignmentExpression()->Left() == this;
3103af6ab5fSopenharmony_ci    std::string_view const methodName =
3113af6ab5fSopenharmony_ci        isSetter ? compiler::Signatures::SET_INDEX_METHOD : compiler::Signatures::GET_INDEX_METHOD;
3123af6ab5fSopenharmony_ci
3133af6ab5fSopenharmony_ci    auto *const method = objType_->GetProperty(methodName, searchFlag);
3143af6ab5fSopenharmony_ci    if (method == nullptr || !method->HasFlag(varbinder::VariableFlags::METHOD)) {
3153af6ab5fSopenharmony_ci        checker->LogTypeError("Object type doesn't have proper index access method.", Start());
3163af6ab5fSopenharmony_ci        return nullptr;
3173af6ab5fSopenharmony_ci    }
3183af6ab5fSopenharmony_ci
3193af6ab5fSopenharmony_ci    ArenaVector<Expression *> arguments {checker->Allocator()->Adapter()};
3203af6ab5fSopenharmony_ci    arguments.emplace_back(property_);
3213af6ab5fSopenharmony_ci    if (isSetter) {
3223af6ab5fSopenharmony_ci        //  Temporary change the parent of right assignment node to check if correct "$_set" function presents.
3233af6ab5fSopenharmony_ci        //  later on in lowering the entire assignment expression will be replace top the call to that method.
3243af6ab5fSopenharmony_ci        auto *value = Parent()->AsAssignmentExpression()->Right();
3253af6ab5fSopenharmony_ci        value->SetParent(this);
3263af6ab5fSopenharmony_ci        arguments.emplace_back(value);
3273af6ab5fSopenharmony_ci    }
3283af6ab5fSopenharmony_ci
3293af6ab5fSopenharmony_ci    auto &signatures = checker->GetTypeOfVariable(method)->AsETSFunctionType()->CallSignatures();
3303af6ab5fSopenharmony_ci
3313af6ab5fSopenharmony_ci    checker::Signature *signature = checker->ValidateSignatures(signatures, nullptr, arguments, Start(), "indexing",
3323af6ab5fSopenharmony_ci                                                                checker::TypeRelationFlag::NO_THROW);
3333af6ab5fSopenharmony_ci    if (signature == nullptr) {
3343af6ab5fSopenharmony_ci        checker->LogTypeError("Cannot find index access method with the required signature.", Property()->Start());
3353af6ab5fSopenharmony_ci        return nullptr;
3363af6ab5fSopenharmony_ci    }
3373af6ab5fSopenharmony_ci    checker->ValidateSignatureAccessibility(objType_, nullptr, signature, Start(),
3383af6ab5fSopenharmony_ci                                            "Index access method is not visible here.");
3393af6ab5fSopenharmony_ci
3403af6ab5fSopenharmony_ci    ASSERT(signature->Function() != nullptr);
3413af6ab5fSopenharmony_ci
3423af6ab5fSopenharmony_ci    if (signature->Function()->IsThrowing() || signature->Function()->IsRethrowing()) {
3433af6ab5fSopenharmony_ci        checker->CheckThrowingStatements(this);
3443af6ab5fSopenharmony_ci    }
3453af6ab5fSopenharmony_ci
3463af6ab5fSopenharmony_ci    if (isSetter) {
3473af6ab5fSopenharmony_ci        //  Restore the right assignment node's parent to keep AST invariant valid.
3483af6ab5fSopenharmony_ci        Parent()->AsAssignmentExpression()->Right()->SetParent(Parent());
3493af6ab5fSopenharmony_ci        return signature->Params()[1]->TsType();
3503af6ab5fSopenharmony_ci    }
3513af6ab5fSopenharmony_ci
3523af6ab5fSopenharmony_ci    return signature->ReturnType();
3533af6ab5fSopenharmony_ci}
3543af6ab5fSopenharmony_ci
3553af6ab5fSopenharmony_cichecker::Type *MemberExpression::CheckTupleAccessMethod(checker::ETSChecker *checker, checker::Type *baseType)
3563af6ab5fSopenharmony_ci{
3573af6ab5fSopenharmony_ci    ASSERT(baseType->IsETSTupleType());
3583af6ab5fSopenharmony_ci
3593af6ab5fSopenharmony_ci    auto idxIfAny = checker->GetTupleElementAccessValue(Property()->TsType(), Property()->Start());
3603af6ab5fSopenharmony_ci    if (!idxIfAny.has_value()) {
3613af6ab5fSopenharmony_ci        return nullptr;
3623af6ab5fSopenharmony_ci    }
3633af6ab5fSopenharmony_ci    auto *const tupleTypeAtIdx = baseType->AsETSTupleType()->GetTypeAtIndex(*idxIfAny);
3643af6ab5fSopenharmony_ci
3653af6ab5fSopenharmony_ci    if ((!Parent()->IsAssignmentExpression() || Parent()->AsAssignmentExpression()->Left() != this) &&
3663af6ab5fSopenharmony_ci        (!Parent()->IsUpdateExpression())) {
3673af6ab5fSopenharmony_ci        // Error never should be thrown by this call, because LUB of types can be converted to any type which
3683af6ab5fSopenharmony_ci        // LUB was calculated by casting
3693af6ab5fSopenharmony_ci        const checker::CastingContext cast(
3703af6ab5fSopenharmony_ci            checker->Relation(), {"Tuple type couldn't be converted "},
3713af6ab5fSopenharmony_ci            checker::CastingContext::ConstructorData {this, baseType->AsETSArrayType()->ElementType(), tupleTypeAtIdx,
3723af6ab5fSopenharmony_ci                                                      Start()});
3733af6ab5fSopenharmony_ci    }
3743af6ab5fSopenharmony_ci
3753af6ab5fSopenharmony_ci    return tupleTypeAtIdx;
3763af6ab5fSopenharmony_ci}
3773af6ab5fSopenharmony_ci
3783af6ab5fSopenharmony_cichecker::Type *MemberExpression::CheckComputed(checker::ETSChecker *checker, checker::Type *baseType)
3793af6ab5fSopenharmony_ci{
3803af6ab5fSopenharmony_ci    if (baseType->IsETSDynamicType()) {
3813af6ab5fSopenharmony_ci        checker->ValidateArrayIndex(property_);
3823af6ab5fSopenharmony_ci        return checker->GlobalBuiltinDynamicType(baseType->AsETSDynamicType()->Language());
3833af6ab5fSopenharmony_ci    }
3843af6ab5fSopenharmony_ci
3853af6ab5fSopenharmony_ci    if (baseType->IsETSArrayType()) {
3863af6ab5fSopenharmony_ci        auto *dflt = baseType->AsETSArrayType()->ElementType();
3873af6ab5fSopenharmony_ci        if (!baseType->IsETSTupleType() && !checker->ValidateArrayIndex(property_)) {
3883af6ab5fSopenharmony_ci            // error already reported to log
3893af6ab5fSopenharmony_ci            return dflt;
3903af6ab5fSopenharmony_ci        }
3913af6ab5fSopenharmony_ci
3923af6ab5fSopenharmony_ci        if (baseType->IsETSTupleType() && !checker->ValidateTupleIndex(baseType->AsETSTupleType(), this)) {
3933af6ab5fSopenharmony_ci            // error reported to log
3943af6ab5fSopenharmony_ci            return dflt;
3953af6ab5fSopenharmony_ci        }
3963af6ab5fSopenharmony_ci
3973af6ab5fSopenharmony_ci        // Check if the index value is inside array bounds if it is defined explicitly
3983af6ab5fSopenharmony_ci        if (property_->IsNumberLiteral() && !CheckArrayIndexValue(checker)) {
3993af6ab5fSopenharmony_ci            // error reported to log
4003af6ab5fSopenharmony_ci            return dflt;
4013af6ab5fSopenharmony_ci        }
4023af6ab5fSopenharmony_ci
4033af6ab5fSopenharmony_ci        // NOTE: apply capture conversion on this type
4043af6ab5fSopenharmony_ci        if (baseType->IsETSTupleType()) {
4053af6ab5fSopenharmony_ci            auto *res = CheckTupleAccessMethod(checker, baseType);
4063af6ab5fSopenharmony_ci            return (res == nullptr) ? dflt : res;
4073af6ab5fSopenharmony_ci        }
4083af6ab5fSopenharmony_ci
4093af6ab5fSopenharmony_ci        return dflt;
4103af6ab5fSopenharmony_ci    }
4113af6ab5fSopenharmony_ci
4123af6ab5fSopenharmony_ci    if (baseType->IsETSObjectType()) {
4133af6ab5fSopenharmony_ci        SetObjectType(baseType->AsETSObjectType());
4143af6ab5fSopenharmony_ci        return CheckIndexAccessMethod(checker);
4153af6ab5fSopenharmony_ci    }
4163af6ab5fSopenharmony_ci    if ((baseType->IsETSEnumType()) && (kind_ == MemberExpressionKind::ELEMENT_ACCESS)) {
4173af6ab5fSopenharmony_ci        property_->Check(checker);
4183af6ab5fSopenharmony_ci        if (property_->TsType()->IsETSEnumType()) {
4193af6ab5fSopenharmony_ci            AddAstNodeFlags(ir::AstNodeFlags::GENERATE_GET_NAME);
4203af6ab5fSopenharmony_ci            return checker->GlobalBuiltinETSStringType();
4213af6ab5fSopenharmony_ci        }
4223af6ab5fSopenharmony_ci    }
4233af6ab5fSopenharmony_ci    checker->LogTypeError("Indexed access is not supported for such expression type.", Object()->Start());
4243af6ab5fSopenharmony_ci    return nullptr;
4253af6ab5fSopenharmony_ci}
4263af6ab5fSopenharmony_ci
4273af6ab5fSopenharmony_cichecker::Type *MemberExpression::Check(checker::ETSChecker *checker)
4283af6ab5fSopenharmony_ci{
4293af6ab5fSopenharmony_ci    return checker->GetAnalyzer()->Check(this);
4303af6ab5fSopenharmony_ci}
4313af6ab5fSopenharmony_ci
4323af6ab5fSopenharmony_ciMemberExpression *MemberExpression::Clone(ArenaAllocator *const allocator, AstNode *const parent)
4333af6ab5fSopenharmony_ci{
4343af6ab5fSopenharmony_ci    if (auto *const clone = allocator->New<MemberExpression>(Tag {}, *this, allocator); clone != nullptr) {
4353af6ab5fSopenharmony_ci        if (parent != nullptr) {
4363af6ab5fSopenharmony_ci            clone->SetParent(parent);
4373af6ab5fSopenharmony_ci        }
4383af6ab5fSopenharmony_ci
4393af6ab5fSopenharmony_ci        clone->SetRange(Range());
4403af6ab5fSopenharmony_ci        return clone;
4413af6ab5fSopenharmony_ci    }
4423af6ab5fSopenharmony_ci
4433af6ab5fSopenharmony_ci    throw Error(ErrorType::GENERIC, "", CLONE_ALLOCATION_ERROR);
4443af6ab5fSopenharmony_ci}
4453af6ab5fSopenharmony_ci
4463af6ab5fSopenharmony_ci}  // namespace ark::es2panda::ir
447