13af6ab5fSopenharmony_ci/**
23af6ab5fSopenharmony_ci * Copyright (c) 2023-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 "tupleLowering.h"
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_ci#include "checker/ETSchecker.h"
193af6ab5fSopenharmony_ci#include "checker/types/ets/etsTupleType.h"
203af6ab5fSopenharmony_ci#include "compiler/lowering/util.h"
213af6ab5fSopenharmony_ci#include "ir/expressions/assignmentExpression.h"
223af6ab5fSopenharmony_ci#include "ir/expressions/identifier.h"
233af6ab5fSopenharmony_ci#include "ir/expressions/memberExpression.h"
243af6ab5fSopenharmony_ci#include "ir/expressions/sequenceExpression.h"
253af6ab5fSopenharmony_ci#include "ir/expressions/updateExpression.h"
263af6ab5fSopenharmony_ci#include "ir/opaqueTypeNode.h"
273af6ab5fSopenharmony_ci#include "ir/statements/blockStatement.h"
283af6ab5fSopenharmony_ci#include "ir/ts/tsAsExpression.h"
293af6ab5fSopenharmony_ci
303af6ab5fSopenharmony_cinamespace ark::es2panda::compiler {
313af6ab5fSopenharmony_ciclass TupleUpdateConverter {
323af6ab5fSopenharmony_cipublic:
333af6ab5fSopenharmony_ci    TupleUpdateConverter(checker::ETSChecker *const checker, ir::UpdateExpression *const update)
343af6ab5fSopenharmony_ci        : checker_(checker), update_(update)
353af6ab5fSopenharmony_ci    {
363af6ab5fSopenharmony_ci    }
373af6ab5fSopenharmony_ci
383af6ab5fSopenharmony_ci    std::optional<checker::Type *const> CheckUpdateArgument()
393af6ab5fSopenharmony_ci    {
403af6ab5fSopenharmony_ci        auto *const argument = update_->Argument();
413af6ab5fSopenharmony_ci        const bool isArgumentMemberExpression = argument->IsMemberExpression();
423af6ab5fSopenharmony_ci        auto *const argumentType =
433af6ab5fSopenharmony_ci            isArgumentMemberExpression ? argument->AsMemberExpression()->Object()->TsType() : nullptr;
443af6ab5fSopenharmony_ci
453af6ab5fSopenharmony_ci        if ((argumentType == nullptr) || (!argumentType->IsETSTupleType())) {
463af6ab5fSopenharmony_ci            return std::nullopt;
473af6ab5fSopenharmony_ci        }
483af6ab5fSopenharmony_ci        return {argumentType};
493af6ab5fSopenharmony_ci    }
503af6ab5fSopenharmony_ci
513af6ab5fSopenharmony_ci    checker::Type *SetArgumentType(checker::Type *const argumentType)
523af6ab5fSopenharmony_ci    {
533af6ab5fSopenharmony_ci        auto *const savedType = argument_->TsType();
543af6ab5fSopenharmony_ci        argument_->SetTsType(argumentType->AsETSTupleType()->ElementType());
553af6ab5fSopenharmony_ci        return savedType;
563af6ab5fSopenharmony_ci    }
573af6ab5fSopenharmony_ci
583af6ab5fSopenharmony_ci    void ComputeTypes(checker::Type *const argumentType)
593af6ab5fSopenharmony_ci    {
603af6ab5fSopenharmony_ci        tupleTypeAtIdx_ = argumentType->AsETSTupleType()->GetTypeAtIndex(
613af6ab5fSopenharmony_ci
623af6ab5fSopenharmony_ci            // After the checker, we are guranteed that the index is correct.
633af6ab5fSopenharmony_ci            *checker_->GetTupleElementAccessValue(argument_->AsMemberExpression()->Property()->TsType(),
643af6ab5fSopenharmony_ci                                                  argument_->AsMemberExpression()->Property()->Start()));
653af6ab5fSopenharmony_ci
663af6ab5fSopenharmony_ci        tupleElementTypeNode_ = checker_->AllocNode<ir::OpaqueTypeNode>(argumentType->AsETSTupleType()->ElementType());
673af6ab5fSopenharmony_ci        tupleTypeAtIdxNode_ = checker_->AllocNode<ir::OpaqueTypeNode>(tupleTypeAtIdx_);
683af6ab5fSopenharmony_ci    }
693af6ab5fSopenharmony_ci
703af6ab5fSopenharmony_ci    ArenaVector<ir::Expression *> GenerateExpressions()
713af6ab5fSopenharmony_ci    {
723af6ab5fSopenharmony_ci        // Clone argument of update expression (conversion flag might be added to it, so we need to duplicate it to not
733af6ab5fSopenharmony_ci        // make
743af6ab5fSopenharmony_ci        // conversions on 'line 3', that belongs to 'line 1' )
753af6ab5fSopenharmony_ci        auto [memberExpr, argumentClone] = CloneArgument(argument_);
763af6ab5fSopenharmony_ci        // --------------
773af6ab5fSopenharmony_ci
783af6ab5fSopenharmony_ci        // Generate temporary symbols
793af6ab5fSopenharmony_ci        auto [gensym, tmpVar] = GenerateSymbol(tupleTypeAtIdx_);
803af6ab5fSopenharmony_ci        auto [gensym2, tmpVar2] = GenerateSymbol(tupleTypeAtIdx_);
813af6ab5fSopenharmony_ci        // --------------
823af6ab5fSopenharmony_ci        // make node: let gensym = tuple[n] as <tuple type at index n>;
833af6ab5fSopenharmony_ci        auto *const gensymTsAs = checker_->AllocNode<ir::TSAsExpression>(argumentClone, tupleTypeAtIdxNode_, false);
843af6ab5fSopenharmony_ci        auto *const tupleAsType = checker_->AllocNode<ir::AssignmentExpression>(
853af6ab5fSopenharmony_ci            gensym, gensymTsAs, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
863af6ab5fSopenharmony_ci        // --------------
873af6ab5fSopenharmony_ci
883af6ab5fSopenharmony_ci        // make node: let gensym2 = (gensym)++;
893af6ab5fSopenharmony_ci        auto *identClone = gensym->Clone(checker_->Allocator(), nullptr);
903af6ab5fSopenharmony_ci        identClone->SetTsType(tmpVar->TsType());
913af6ab5fSopenharmony_ci        auto *gensymUpdate =
923af6ab5fSopenharmony_ci            checker_->AllocNode<ir::UpdateExpression>(identClone, update_->OperatorType(), update_->IsPrefix());
933af6ab5fSopenharmony_ci        auto *const gensym2Assignment = checker_->AllocNode<ir::AssignmentExpression>(
943af6ab5fSopenharmony_ci            gensym2, gensymUpdate, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
953af6ab5fSopenharmony_ci        // --------------
963af6ab5fSopenharmony_ci
973af6ab5fSopenharmony_ci        // make node: tuple[n] = (gensym as <tuple type at index n>) as <tuple element_type>;
983af6ab5fSopenharmony_ci        identClone = gensym->Clone(checker_->Allocator(), nullptr);
993af6ab5fSopenharmony_ci        identClone->SetTsType(tmpVar->TsType());
1003af6ab5fSopenharmony_ci        auto *gensymAs = checker_->AllocNode<ir::TSAsExpression>(
1013af6ab5fSopenharmony_ci            identClone, tupleTypeAtIdxNode_->Clone(checker_->Allocator(), nullptr), false);
1023af6ab5fSopenharmony_ci        auto *gensymAsTupleTypeAtIdx = checker_->AllocNode<ir::TSAsExpression>(gensymAs, tupleElementTypeNode_, false);
1033af6ab5fSopenharmony_ci        auto *const tupleAssignment = checker_->AllocNode<ir::AssignmentExpression>(
1043af6ab5fSopenharmony_ci            argument_, gensymAsTupleTypeAtIdx, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
1053af6ab5fSopenharmony_ci        // --------------
1063af6ab5fSopenharmony_ci
1073af6ab5fSopenharmony_ci        // make node: gensym2 as <tuple type at index n>;
1083af6ab5fSopenharmony_ci        identClone = gensym2->Clone(checker_->Allocator(), nullptr);
1093af6ab5fSopenharmony_ci        identClone->SetTsType(tmpVar2->TsType());
1103af6ab5fSopenharmony_ci        auto *const finalTupleNode = checker_->AllocNode<ir::TSAsExpression>(
1113af6ab5fSopenharmony_ci            identClone, tupleTypeAtIdxNode_->Clone(checker_->Allocator(), nullptr), false);
1123af6ab5fSopenharmony_ci        // --------------
1133af6ab5fSopenharmony_ci
1143af6ab5fSopenharmony_ci        // Construct sequence expression order
1153af6ab5fSopenharmony_ci        ArenaVector<ir::Expression *> expressionList(checker_->Allocator()->Adapter());
1163af6ab5fSopenharmony_ci        expressionList.push_back(tupleAsType);
1173af6ab5fSopenharmony_ci        expressionList.push_back(gensym2Assignment);
1183af6ab5fSopenharmony_ci        expressionList.push_back(tupleAssignment);
1193af6ab5fSopenharmony_ci        expressionList.push_back(finalTupleNode);
1203af6ab5fSopenharmony_ci        // --------------
1213af6ab5fSopenharmony_ci
1223af6ab5fSopenharmony_ci        return expressionList;
1233af6ab5fSopenharmony_ci    }
1243af6ab5fSopenharmony_ci
1253af6ab5fSopenharmony_ciprivate:
1263af6ab5fSopenharmony_ci    std::tuple<ir::Identifier *, varbinder::LocalVariable *const> GenerateSymbol(checker::Type *const type) const
1273af6ab5fSopenharmony_ci    {
1283af6ab5fSopenharmony_ci        auto *gensym = Gensym(checker_->Allocator());
1293af6ab5fSopenharmony_ci        auto *const tmpVar = NearestScope(update_)->AddDecl<varbinder::LetDecl, varbinder::LocalVariable>(
1303af6ab5fSopenharmony_ci            checker_->Allocator(), gensym->Name(), varbinder::VariableFlags::LOCAL);
1313af6ab5fSopenharmony_ci        tmpVar->SetTsType(type);
1323af6ab5fSopenharmony_ci        gensym->SetVariable(tmpVar);
1333af6ab5fSopenharmony_ci        gensym->SetTsType(tmpVar->TsType());
1343af6ab5fSopenharmony_ci        return std::make_tuple(gensym, tmpVar);
1353af6ab5fSopenharmony_ci    }
1363af6ab5fSopenharmony_ci
1373af6ab5fSopenharmony_ci    std::tuple<ir::MemberExpression *const, ir::MemberExpression *const> CloneArgument(
1383af6ab5fSopenharmony_ci        ir::Expression *const argument) const
1393af6ab5fSopenharmony_ci    {
1403af6ab5fSopenharmony_ci        auto *const memberExpr = argument->AsMemberExpression();
1413af6ab5fSopenharmony_ci        auto *const argumentClone = memberExpr->Clone(checker_->Allocator(), memberExpr->Parent());
1423af6ab5fSopenharmony_ci        argumentClone->Object()->SetTsType(memberExpr->Object()->TsType());
1433af6ab5fSopenharmony_ci        if (argumentClone->Object()->IsIdentifier()) {
1443af6ab5fSopenharmony_ci            argumentClone->Object()->AsIdentifier()->SetVariable(memberExpr->Object()->AsIdentifier()->Variable());
1453af6ab5fSopenharmony_ci        }
1463af6ab5fSopenharmony_ci        argumentClone->Property()->SetTsType(memberExpr->Property()->TsType());
1473af6ab5fSopenharmony_ci        if (argumentClone->Property()->IsIdentifier()) {
1483af6ab5fSopenharmony_ci            argumentClone->Property()->AsIdentifier()->SetVariable(memberExpr->Property()->AsIdentifier()->Variable());
1493af6ab5fSopenharmony_ci        }
1503af6ab5fSopenharmony_ci        argumentClone->SetTsType(memberExpr->TsType());
1513af6ab5fSopenharmony_ci        return std::make_tuple(memberExpr, argumentClone);
1523af6ab5fSopenharmony_ci    };
1533af6ab5fSopenharmony_ci
1543af6ab5fSopenharmony_ci    checker::ETSChecker *const checker_;
1553af6ab5fSopenharmony_ci    ir::UpdateExpression *const update_;
1563af6ab5fSopenharmony_ci    ir::Expression *const argument_ {nullptr};
1573af6ab5fSopenharmony_ci    checker::Type *tupleTypeAtIdx_ {nullptr};
1583af6ab5fSopenharmony_ci    ir::OpaqueTypeNode *tupleElementTypeNode_ {nullptr};
1593af6ab5fSopenharmony_ci    ir::OpaqueTypeNode *tupleTypeAtIdxNode_ {nullptr};
1603af6ab5fSopenharmony_ci};
1613af6ab5fSopenharmony_ci
1623af6ab5fSopenharmony_cistatic ir::Expression *ConvertTupleUpdate(checker::ETSChecker *const checker, ir::UpdateExpression *const update)
1633af6ab5fSopenharmony_ci{
1643af6ab5fSopenharmony_ci    // Converts `tuple[n]++` to
1653af6ab5fSopenharmony_ci    // ```
1663af6ab5fSopenharmony_ci    // let gensym = tuple[n] as <tuple type at index n>;                            // line 1
1673af6ab5fSopenharmony_ci    // let gensym2 = (gensym)++;                                                    // line 2
1683af6ab5fSopenharmony_ci    // tuple[n] = (gensym as <tuple type at index n>) as <tuple element_type>;      // line 3
1693af6ab5fSopenharmony_ci    // gensym2 as <tuple type at index n>;                                          // line 4
1703af6ab5fSopenharmony_ci    // ```
1713af6ab5fSopenharmony_ci    // Notes:
1723af6ab5fSopenharmony_ci    // ---
1733af6ab5fSopenharmony_ci    // Because we can modify only 1 expression in the lowering (we don't want to add statements to the enclosing block),
1743af6ab5fSopenharmony_ci    // the expressions will be in a wrapper SequenceExpression
1753af6ab5fSopenharmony_ci    // ---
1763af6ab5fSopenharmony_ci    // At line 3 the double as expression is needed. If we simply write `gensym as <tuple type at index n>`, then a
1773af6ab5fSopenharmony_ci    // boxing flag may be put on the `gensym` identifier node. It'll be boxed in 'line 2' instead of 'line 3', which
1783af6ab5fSopenharmony_ci    // cause error. If we put another as expression inside (which won't do any conversion, because the type of `gensym`
1793af6ab5fSopenharmony_ci    // is already <tuple type at index n>), the boxing flag will be on the as expression, instead of the identifier, so
1803af6ab5fSopenharmony_ci    // the identifier node won't be unboxed at 'line 2'.
1813af6ab5fSopenharmony_ci
1823af6ab5fSopenharmony_ci    auto converter = TupleUpdateConverter {checker, update};
1833af6ab5fSopenharmony_ci
1843af6ab5fSopenharmony_ci    // Check if argument of update expression is tuple
1853af6ab5fSopenharmony_ci    auto const argumentType = converter.CheckUpdateArgument();
1863af6ab5fSopenharmony_ci    if (!argumentType) {
1873af6ab5fSopenharmony_ci        return update;
1883af6ab5fSopenharmony_ci    }
1893af6ab5fSopenharmony_ci    // --------------
1903af6ab5fSopenharmony_ci
1913af6ab5fSopenharmony_ci    // Set tuple type to Object (because we'll need implicit boxing)
1923af6ab5fSopenharmony_ci    auto *const savedType = converter.SetArgumentType(*argumentType);
1933af6ab5fSopenharmony_ci    // --------------
1943af6ab5fSopenharmony_ci
1953af6ab5fSopenharmony_ci    // Compute necessary types and OpaqueTypeNodes
1963af6ab5fSopenharmony_ci    converter.ComputeTypes(*argumentType);
1973af6ab5fSopenharmony_ci    // --------------
1983af6ab5fSopenharmony_ci
1993af6ab5fSopenharmony_ci    auto expressions = converter.GenerateExpressions();
2003af6ab5fSopenharmony_ci
2013af6ab5fSopenharmony_ci    // Check the new sequence expression
2023af6ab5fSopenharmony_ci    auto *const sequenceExpr = checker->AllocNode<ir::SequenceExpression>(std::move(expressions));
2033af6ab5fSopenharmony_ci    sequenceExpr->SetParent(update->Parent());
2043af6ab5fSopenharmony_ci    sequenceExpr->Check(checker);
2053af6ab5fSopenharmony_ci    // --------------
2063af6ab5fSopenharmony_ci
2073af6ab5fSopenharmony_ci    // Set back TsType of argument (not necessarily needed now, but there can be a phase later, that need to get the
2083af6ab5fSopenharmony_ci    // right type of it)
2093af6ab5fSopenharmony_ci    [[maybe_unused]] auto _ = converter.SetArgumentType(savedType);
2103af6ab5fSopenharmony_ci    // --------------
2113af6ab5fSopenharmony_ci
2123af6ab5fSopenharmony_ci    return sequenceExpr;
2133af6ab5fSopenharmony_ci}
2143af6ab5fSopenharmony_ci
2153af6ab5fSopenharmony_cistatic ir::AssignmentExpression *ConvertTupleAssignment(checker::ETSChecker *const checker,
2163af6ab5fSopenharmony_ci                                                        ir::AssignmentExpression *const assignment)
2173af6ab5fSopenharmony_ci{
2183af6ab5fSopenharmony_ci    // Converts `tuple[n] = variable;` to
2193af6ab5fSopenharmony_ci    // `tuple[n] = ((variable as <tuple type at index n>) as <tuple element_type>)`
2203af6ab5fSopenharmony_ci    // This lowering is necessary to handle `an unboxing conversion followed by a widening primitive
2213af6ab5fSopenharmony_ci    // conversion`, eg. when `tuple[n]` has type of `int`, and assignment::right_ has type of `Short`. Because every
2223af6ab5fSopenharmony_ci    // type is stored as the LUB type in the tuple (which can be Object), then the following conversions need to be done
2233af6ab5fSopenharmony_ci    // for this case: Short->short->int->Int->Object which can't be made implicitly, hence lowering is needed
2243af6ab5fSopenharmony_ci
2253af6ab5fSopenharmony_ci    // Check if the left side of an assignment expression is a tuple element access
2263af6ab5fSopenharmony_ci    auto *const left = assignment->Left();
2273af6ab5fSopenharmony_ci    auto *const leftObjectType = left->AsMemberExpression()->Object()->TsType();
2283af6ab5fSopenharmony_ci
2293af6ab5fSopenharmony_ci    if ((leftObjectType == nullptr) || (!leftObjectType->IsETSTupleType())) {
2303af6ab5fSopenharmony_ci        return assignment;
2313af6ab5fSopenharmony_ci    }
2323af6ab5fSopenharmony_ci    // --------------
2333af6ab5fSopenharmony_ci
2343af6ab5fSopenharmony_ci    // Set tuple type to <tuple element_type> (because we may need implicit boxing)
2353af6ab5fSopenharmony_ci    auto *const savedLeftType = left->TsType();
2363af6ab5fSopenharmony_ci    left->SetTsType(leftObjectType->AsETSTupleType()->ElementType());
2373af6ab5fSopenharmony_ci    // --------------
2383af6ab5fSopenharmony_ci
2393af6ab5fSopenharmony_ci    // Compute necessary types and OpaqueTypeNodes
2403af6ab5fSopenharmony_ci    auto *const elementTypeTypeNode =
2413af6ab5fSopenharmony_ci        checker->AllocNode<ir::OpaqueTypeNode>(leftObjectType->AsETSTupleType()->ElementType());
2423af6ab5fSopenharmony_ci    auto *const tupleTypeAtIdxTypeNode = checker->AllocNode<ir::OpaqueTypeNode>(savedLeftType);
2433af6ab5fSopenharmony_ci    // --------------
2443af6ab5fSopenharmony_ci
2453af6ab5fSopenharmony_ci    // make node: tuple[n] = ((variable as <tuple type at index n>) as <tuple element_type>)
2463af6ab5fSopenharmony_ci    auto *const tsAsExpressionLeft =
2473af6ab5fSopenharmony_ci        checker->AllocNode<ir::TSAsExpression>(assignment->Right(), tupleTypeAtIdxTypeNode, false);
2483af6ab5fSopenharmony_ci
2493af6ab5fSopenharmony_ci    auto *const tsAsExpression = checker->AllocNode<ir::TSAsExpression>(tsAsExpressionLeft, elementTypeTypeNode, false);
2503af6ab5fSopenharmony_ci    auto *const newAssignment =
2513af6ab5fSopenharmony_ci        checker->AllocNode<ir::AssignmentExpression>(left, tsAsExpression, assignment->OperatorType());
2523af6ab5fSopenharmony_ci    // --------------
2533af6ab5fSopenharmony_ci
2543af6ab5fSopenharmony_ci    // Check the new assignment
2553af6ab5fSopenharmony_ci    newAssignment->SetParent(assignment->Parent());
2563af6ab5fSopenharmony_ci    newAssignment->Check(checker);
2573af6ab5fSopenharmony_ci    left->SetTsType(savedLeftType);
2583af6ab5fSopenharmony_ci    // --------------
2593af6ab5fSopenharmony_ci
2603af6ab5fSopenharmony_ci    return newAssignment;
2613af6ab5fSopenharmony_ci}
2623af6ab5fSopenharmony_ci
2633af6ab5fSopenharmony_cibool TupleLowering::Perform(public_lib::Context *const ctx, parser::Program *const program)
2643af6ab5fSopenharmony_ci{
2653af6ab5fSopenharmony_ci    for (const auto &[_, ext_programs] : program->ExternalSources()) {
2663af6ab5fSopenharmony_ci        (void)_;
2673af6ab5fSopenharmony_ci        for (auto *const extProg : ext_programs) {
2683af6ab5fSopenharmony_ci            Perform(ctx, extProg);
2693af6ab5fSopenharmony_ci        }
2703af6ab5fSopenharmony_ci    }
2713af6ab5fSopenharmony_ci
2723af6ab5fSopenharmony_ci    checker::ETSChecker *const checker = ctx->checker->AsETSChecker();
2733af6ab5fSopenharmony_ci
2743af6ab5fSopenharmony_ci    program->Ast()->TransformChildrenRecursively(
2753af6ab5fSopenharmony_ci        [checker](ir::AstNode *const ast) -> ir::AstNode * {
2763af6ab5fSopenharmony_ci            // Check if node is an 'assignment expression', with a member expression on the left (potentially tuple)
2773af6ab5fSopenharmony_ci            if (ast->IsAssignmentExpression() && ast->AsAssignmentExpression()->Left()->IsMemberExpression()) {
2783af6ab5fSopenharmony_ci                return ConvertTupleAssignment(checker, ast->AsAssignmentExpression());
2793af6ab5fSopenharmony_ci            }
2803af6ab5fSopenharmony_ci
2813af6ab5fSopenharmony_ci            // Check if node is an 'update expression', with a member expression as an argument (potentially tuple)
2823af6ab5fSopenharmony_ci            if (ast->IsUpdateExpression() && ast->AsUpdateExpression()->Argument()->IsMemberExpression()) {
2833af6ab5fSopenharmony_ci                return ConvertTupleUpdate(checker, ast->AsUpdateExpression());
2843af6ab5fSopenharmony_ci            }
2853af6ab5fSopenharmony_ci
2863af6ab5fSopenharmony_ci            return ast;
2873af6ab5fSopenharmony_ci        },
2883af6ab5fSopenharmony_ci        Name());
2893af6ab5fSopenharmony_ci
2903af6ab5fSopenharmony_ci    return true;
2913af6ab5fSopenharmony_ci}
2923af6ab5fSopenharmony_ci
2933af6ab5fSopenharmony_cibool TupleLowering::Postcondition(public_lib::Context *const ctx, const parser::Program *const program)
2943af6ab5fSopenharmony_ci{
2953af6ab5fSopenharmony_ci    for (const auto &[_, ext_programs] : program->ExternalSources()) {
2963af6ab5fSopenharmony_ci        (void)_;
2973af6ab5fSopenharmony_ci        for (const auto *const extProg : ext_programs) {
2983af6ab5fSopenharmony_ci            if (!Postcondition(ctx, extProg)) {
2993af6ab5fSopenharmony_ci                return false;
3003af6ab5fSopenharmony_ci            }
3013af6ab5fSopenharmony_ci        }
3023af6ab5fSopenharmony_ci    }
3033af6ab5fSopenharmony_ci
3043af6ab5fSopenharmony_ci    return !program->Ast()->IsAnyChild([](const ir::AstNode *const ast) {
3053af6ab5fSopenharmony_ci        const bool isLeftMemberExpr =
3063af6ab5fSopenharmony_ci            ast->IsAssignmentExpression() && ast->AsAssignmentExpression()->Left()->IsMemberExpression();
3073af6ab5fSopenharmony_ci        const bool isLeftTuple =
3083af6ab5fSopenharmony_ci            isLeftMemberExpr
3093af6ab5fSopenharmony_ci                ? (ast->AsAssignmentExpression()->Left()->AsMemberExpression()->TsType() != nullptr) &&
3103af6ab5fSopenharmony_ci                      ast->AsAssignmentExpression()->Left()->AsMemberExpression()->TsType()->IsETSTupleType()
3113af6ab5fSopenharmony_ci                : false;
3123af6ab5fSopenharmony_ci        // Check if there is an 'assignment expression' with a 'member expression' on it's left, which is a tuple. If
3133af6ab5fSopenharmony_ci        // yes, then the right hand side must be a type of the element type.
3143af6ab5fSopenharmony_ci        return isLeftMemberExpr && isLeftTuple &&
3153af6ab5fSopenharmony_ci               (ast->AsAssignmentExpression()->Right()->TsType() ==
3163af6ab5fSopenharmony_ci                ast->AsAssignmentExpression()->Left()->AsMemberExpression()->TsType()->AsETSTupleType()->ElementType());
3173af6ab5fSopenharmony_ci    });
3183af6ab5fSopenharmony_ci}
3193af6ab5fSopenharmony_ci
3203af6ab5fSopenharmony_ci}  // namespace ark::es2panda::compiler
321