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 "arithmetic.h"
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_cinamespace ark::es2panda::checker {
193af6ab5fSopenharmony_ci
203af6ab5fSopenharmony_cistatic inline void RepairTypeErrorsInOperands(Type **left, Type **right)
213af6ab5fSopenharmony_ci{
223af6ab5fSopenharmony_ci    if (IsTypeError(*left)) {
233af6ab5fSopenharmony_ci        *left = *right;
243af6ab5fSopenharmony_ci    }
253af6ab5fSopenharmony_ci    if (IsTypeError(*right)) {
263af6ab5fSopenharmony_ci        *right = *left;
273af6ab5fSopenharmony_ci    }
283af6ab5fSopenharmony_ci}
293af6ab5fSopenharmony_ci
303af6ab5fSopenharmony_cistatic inline void RepairTypeErrorWithDefault(Type **type, Type *dflt)
313af6ab5fSopenharmony_ci{
323af6ab5fSopenharmony_ci    if (IsTypeError(*type)) {
333af6ab5fSopenharmony_ci        *type = dflt;
343af6ab5fSopenharmony_ci    }
353af6ab5fSopenharmony_ci}
363af6ab5fSopenharmony_ci
373af6ab5fSopenharmony_ciType *ETSChecker::NegateNumericType(Type *type, ir::Expression *node)
383af6ab5fSopenharmony_ci{
393af6ab5fSopenharmony_ci    ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC));
403af6ab5fSopenharmony_ci
413af6ab5fSopenharmony_ci    TypeFlag typeKind = ETSType(type);
423af6ab5fSopenharmony_ci    Type *result = nullptr;
433af6ab5fSopenharmony_ci
443af6ab5fSopenharmony_ci    switch (typeKind) {
453af6ab5fSopenharmony_ci        case TypeFlag::BYTE: {
463af6ab5fSopenharmony_ci            result = CreateByteType(-(type->AsByteType()->GetValue()));
473af6ab5fSopenharmony_ci            break;
483af6ab5fSopenharmony_ci        }
493af6ab5fSopenharmony_ci        case TypeFlag::CHAR: {
503af6ab5fSopenharmony_ci            result = CreateCharType(-(type->AsCharType()->GetValue()));
513af6ab5fSopenharmony_ci            break;
523af6ab5fSopenharmony_ci        }
533af6ab5fSopenharmony_ci        case TypeFlag::SHORT: {
543af6ab5fSopenharmony_ci            result = CreateShortType(-(type->AsShortType()->GetValue()));
553af6ab5fSopenharmony_ci            break;
563af6ab5fSopenharmony_ci        }
573af6ab5fSopenharmony_ci        case TypeFlag::INT: {
583af6ab5fSopenharmony_ci            result = CreateIntType(-(type->AsIntType()->GetValue()));
593af6ab5fSopenharmony_ci            break;
603af6ab5fSopenharmony_ci        }
613af6ab5fSopenharmony_ci        case TypeFlag::LONG: {
623af6ab5fSopenharmony_ci            result = CreateLongType(-(type->AsLongType()->GetValue()));
633af6ab5fSopenharmony_ci            break;
643af6ab5fSopenharmony_ci        }
653af6ab5fSopenharmony_ci        case TypeFlag::FLOAT: {
663af6ab5fSopenharmony_ci            result = CreateFloatType(-(type->AsFloatType()->GetValue()));
673af6ab5fSopenharmony_ci            break;
683af6ab5fSopenharmony_ci        }
693af6ab5fSopenharmony_ci        case TypeFlag::DOUBLE: {
703af6ab5fSopenharmony_ci            result = CreateDoubleType(-(type->AsDoubleType()->GetValue()));
713af6ab5fSopenharmony_ci            break;
723af6ab5fSopenharmony_ci        }
733af6ab5fSopenharmony_ci        default: {
743af6ab5fSopenharmony_ci            UNREACHABLE();
753af6ab5fSopenharmony_ci        }
763af6ab5fSopenharmony_ci    }
773af6ab5fSopenharmony_ci
783af6ab5fSopenharmony_ci    node->SetTsType(result);
793af6ab5fSopenharmony_ci    return result;
803af6ab5fSopenharmony_ci}
813af6ab5fSopenharmony_ci
823af6ab5fSopenharmony_ciType *ETSChecker::BitwiseNegateNumericType(Type *type, ir::Expression *node)
833af6ab5fSopenharmony_ci{
843af6ab5fSopenharmony_ci    ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_INTEGRAL));
853af6ab5fSopenharmony_ci
863af6ab5fSopenharmony_ci    TypeFlag typeKind = ETSType(type);
873af6ab5fSopenharmony_ci
883af6ab5fSopenharmony_ci    Type *result = nullptr;
893af6ab5fSopenharmony_ci
903af6ab5fSopenharmony_ci    switch (typeKind) {
913af6ab5fSopenharmony_ci        case TypeFlag::BYTE: {
923af6ab5fSopenharmony_ci            result = CreateByteType(static_cast<int8_t>(~static_cast<uint8_t>(type->AsByteType()->GetValue())));
933af6ab5fSopenharmony_ci            break;
943af6ab5fSopenharmony_ci        }
953af6ab5fSopenharmony_ci        case TypeFlag::CHAR: {
963af6ab5fSopenharmony_ci            result = CreateCharType(~(type->AsCharType()->GetValue()));
973af6ab5fSopenharmony_ci            break;
983af6ab5fSopenharmony_ci        }
993af6ab5fSopenharmony_ci        case TypeFlag::SHORT: {
1003af6ab5fSopenharmony_ci            result = CreateShortType(static_cast<int16_t>(~static_cast<uint16_t>(type->AsShortType()->GetValue())));
1013af6ab5fSopenharmony_ci            break;
1023af6ab5fSopenharmony_ci        }
1033af6ab5fSopenharmony_ci        case TypeFlag::INT: {
1043af6ab5fSopenharmony_ci            result = CreateIntType(static_cast<int32_t>(~static_cast<uint32_t>(type->AsIntType()->GetValue())));
1053af6ab5fSopenharmony_ci            break;
1063af6ab5fSopenharmony_ci        }
1073af6ab5fSopenharmony_ci        case TypeFlag::LONG: {
1083af6ab5fSopenharmony_ci            result = CreateLongType(static_cast<int64_t>(~static_cast<uint64_t>(type->AsLongType()->GetValue())));
1093af6ab5fSopenharmony_ci            break;
1103af6ab5fSopenharmony_ci        }
1113af6ab5fSopenharmony_ci        case TypeFlag::FLOAT: {
1123af6ab5fSopenharmony_ci            result = CreateIntType(
1133af6ab5fSopenharmony_ci                ~static_cast<uint32_t>(CastFloatToInt<FloatType::UType, int32_t>(type->AsFloatType()->GetValue())));
1143af6ab5fSopenharmony_ci            break;
1153af6ab5fSopenharmony_ci        }
1163af6ab5fSopenharmony_ci        case TypeFlag::DOUBLE: {
1173af6ab5fSopenharmony_ci            result = CreateLongType(
1183af6ab5fSopenharmony_ci                ~static_cast<uint64_t>(CastFloatToInt<DoubleType::UType, int64_t>(type->AsDoubleType()->GetValue())));
1193af6ab5fSopenharmony_ci            break;
1203af6ab5fSopenharmony_ci        }
1213af6ab5fSopenharmony_ci        default: {
1223af6ab5fSopenharmony_ci            UNREACHABLE();
1233af6ab5fSopenharmony_ci        }
1243af6ab5fSopenharmony_ci    }
1253af6ab5fSopenharmony_ci
1263af6ab5fSopenharmony_ci    node->SetTsType(result);
1273af6ab5fSopenharmony_ci    return result;
1283af6ab5fSopenharmony_ci}
1293af6ab5fSopenharmony_ci
1303af6ab5fSopenharmony_ciType *ETSChecker::HandleRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
1313af6ab5fSopenharmony_ci{
1323af6ab5fSopenharmony_ci    ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) &&
1333af6ab5fSopenharmony_ci           right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC));
1343af6ab5fSopenharmony_ci
1353af6ab5fSopenharmony_ci    if (left->IsDoubleType() || right->IsDoubleType()) {
1363af6ab5fSopenharmony_ci        return PerformRelationOperationOnTypes<DoubleType>(left, right, operationType);
1373af6ab5fSopenharmony_ci    }
1383af6ab5fSopenharmony_ci
1393af6ab5fSopenharmony_ci    if (left->IsFloatType() || right->IsFloatType()) {
1403af6ab5fSopenharmony_ci        return PerformRelationOperationOnTypes<FloatType>(left, right, operationType);
1413af6ab5fSopenharmony_ci    }
1423af6ab5fSopenharmony_ci
1433af6ab5fSopenharmony_ci    if (left->IsLongType() || right->IsLongType()) {
1443af6ab5fSopenharmony_ci        return PerformRelationOperationOnTypes<LongType>(left, right, operationType);
1453af6ab5fSopenharmony_ci    }
1463af6ab5fSopenharmony_ci
1473af6ab5fSopenharmony_ci    return PerformRelationOperationOnTypes<IntType>(left, right, operationType);
1483af6ab5fSopenharmony_ci}
1493af6ab5fSopenharmony_ci
1503af6ab5fSopenharmony_cibool ETSChecker::CheckBinaryOperatorForBigInt(Type *left, Type *right, lexer::TokenType op)
1513af6ab5fSopenharmony_ci{
1523af6ab5fSopenharmony_ci    if ((left == nullptr) || (right == nullptr)) {
1533af6ab5fSopenharmony_ci        return false;
1543af6ab5fSopenharmony_ci    }
1553af6ab5fSopenharmony_ci
1563af6ab5fSopenharmony_ci    if (!left->IsETSBigIntType()) {
1573af6ab5fSopenharmony_ci        return false;
1583af6ab5fSopenharmony_ci    }
1593af6ab5fSopenharmony_ci
1603af6ab5fSopenharmony_ci    if (!right->IsETSBigIntType()) {
1613af6ab5fSopenharmony_ci        return false;
1623af6ab5fSopenharmony_ci    }
1633af6ab5fSopenharmony_ci
1643af6ab5fSopenharmony_ci    switch (op) {
1653af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_EQUAL:
1663af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_NOT_EQUAL:
1673af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
1683af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL:
1693af6ab5fSopenharmony_ci        case lexer::TokenType::KEYW_INSTANCEOF:
1703af6ab5fSopenharmony_ci            // This is handled in the main CheckBinaryOperator function
1713af6ab5fSopenharmony_ci            return false;
1723af6ab5fSopenharmony_ci        default:
1733af6ab5fSopenharmony_ci            break;
1743af6ab5fSopenharmony_ci    }
1753af6ab5fSopenharmony_ci
1763af6ab5fSopenharmony_ci    return true;
1773af6ab5fSopenharmony_ci}
1783af6ab5fSopenharmony_ci
1793af6ab5fSopenharmony_cibool ETSChecker::CheckBinaryPlusMultDivOperandsForUnionType(const Type *leftType, const Type *rightType,
1803af6ab5fSopenharmony_ci                                                            const ir::Expression *left, const ir::Expression *right)
1813af6ab5fSopenharmony_ci{
1823af6ab5fSopenharmony_ci    std::stringstream ss;
1833af6ab5fSopenharmony_ci    if (leftType->IsETSUnionType()) {
1843af6ab5fSopenharmony_ci        leftType->AsETSUnionType()->ToString(ss, false);
1853af6ab5fSopenharmony_ci        LogTypeError("Bad operand type: multiple types left in the normalized union type (" + ss.str() +
1863af6ab5fSopenharmony_ci                         "). Unions are not allowed in binary expressions except equality.",
1873af6ab5fSopenharmony_ci                     left->Start());
1883af6ab5fSopenharmony_ci        return false;
1893af6ab5fSopenharmony_ci    }
1903af6ab5fSopenharmony_ci    if (rightType->IsETSUnionType()) {
1913af6ab5fSopenharmony_ci        rightType->AsETSUnionType()->ToString(ss, false);
1923af6ab5fSopenharmony_ci        LogTypeError("Bad operand type: multiple types left in the normalized union type (" + ss.str() +
1933af6ab5fSopenharmony_ci                         "). Unions are not allowed in binary expressions except equality.",
1943af6ab5fSopenharmony_ci                     right->Start());
1953af6ab5fSopenharmony_ci        return false;
1963af6ab5fSopenharmony_ci    }
1973af6ab5fSopenharmony_ci    return true;
1983af6ab5fSopenharmony_ci}
1993af6ab5fSopenharmony_ci
2003af6ab5fSopenharmony_cichecker::Type *ETSChecker::CheckBinaryOperatorMulDivMod(
2013af6ab5fSopenharmony_ci    std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op, bool isEqualOp,
2023af6ab5fSopenharmony_ci    std::tuple<checker::Type *, checker::Type *, Type *, Type *> types)
2033af6ab5fSopenharmony_ci{
2043af6ab5fSopenharmony_ci    auto [left, right, operationType, pos] = op;
2053af6ab5fSopenharmony_ci    auto [leftType, rightType, unboxedL, unboxedR] = types;
2063af6ab5fSopenharmony_ci
2073af6ab5fSopenharmony_ci    // Try to handle errors on a lower level
2083af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&leftType, &rightType);
2093af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&unboxedL, &unboxedR);
2103af6ab5fSopenharmony_ci    if (leftType->IsTypeError()) {  // both are errors
2113af6ab5fSopenharmony_ci        return GlobalTypeError();
2123af6ab5fSopenharmony_ci    }
2133af6ab5fSopenharmony_ci
2143af6ab5fSopenharmony_ci    checker::Type *tsType {};
2153af6ab5fSopenharmony_ci    auto [promotedType, bothConst] =
2163af6ab5fSopenharmony_ci        ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC, !isEqualOp);
2173af6ab5fSopenharmony_ci
2183af6ab5fSopenharmony_ci    FlagExpressionWithUnboxing(leftType, unboxedL, left);
2193af6ab5fSopenharmony_ci    FlagExpressionWithUnboxing(rightType, unboxedR, right);
2203af6ab5fSopenharmony_ci
2213af6ab5fSopenharmony_ci    if (!CheckBinaryPlusMultDivOperandsForUnionType(leftType, rightType, left, right)) {
2223af6ab5fSopenharmony_ci        return GlobalTypeError();
2233af6ab5fSopenharmony_ci    }
2243af6ab5fSopenharmony_ci
2253af6ab5fSopenharmony_ci    if (promotedType == nullptr && !bothConst) {
2263af6ab5fSopenharmony_ci        LogTypeError("Bad operand type, the types of the operands must be numeric type.", pos);
2273af6ab5fSopenharmony_ci        return GlobalTypeError();
2283af6ab5fSopenharmony_ci    }
2293af6ab5fSopenharmony_ci
2303af6ab5fSopenharmony_ci    if (bothConst) {
2313af6ab5fSopenharmony_ci        tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType);
2323af6ab5fSopenharmony_ci    }
2333af6ab5fSopenharmony_ci
2343af6ab5fSopenharmony_ci    tsType = (tsType != nullptr) ? tsType : promotedType;
2353af6ab5fSopenharmony_ci    return tsType;
2363af6ab5fSopenharmony_ci}
2373af6ab5fSopenharmony_ci
2383af6ab5fSopenharmony_cichecker::Type *ETSChecker::CheckBinaryOperatorPlusForEnums(const checker::Type *const leftType,
2393af6ab5fSopenharmony_ci                                                           const checker::Type *const rightType)
2403af6ab5fSopenharmony_ci{
2413af6ab5fSopenharmony_ci    if (leftType->HasTypeFlag(TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) &&
2423af6ab5fSopenharmony_ci        rightType->HasTypeFlag(TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) {
2433af6ab5fSopenharmony_ci        if (leftType->IsETSIntEnumType() && rightType->IsETSIntEnumType()) {
2443af6ab5fSopenharmony_ci            return GlobalIntType();
2453af6ab5fSopenharmony_ci        }
2463af6ab5fSopenharmony_ci        if (leftType->IsFloatType() || rightType->IsFloatType()) {
2473af6ab5fSopenharmony_ci            return GlobalFloatType();
2483af6ab5fSopenharmony_ci        }
2493af6ab5fSopenharmony_ci        if (leftType->IsLongType() || rightType->IsLongType()) {
2503af6ab5fSopenharmony_ci            return GlobalLongType();
2513af6ab5fSopenharmony_ci        }
2523af6ab5fSopenharmony_ci        return GlobalIntType();
2533af6ab5fSopenharmony_ci    }
2543af6ab5fSopenharmony_ci    if ((leftType->IsETSStringEnumType() && (rightType->IsETSStringType() || rightType->IsETSStringEnumType())) ||
2553af6ab5fSopenharmony_ci        (rightType->IsETSStringEnumType() && (leftType->IsETSStringType() || leftType->IsETSStringEnumType()))) {
2563af6ab5fSopenharmony_ci        return GlobalETSStringLiteralType();
2573af6ab5fSopenharmony_ci    }
2583af6ab5fSopenharmony_ci    return nullptr;
2593af6ab5fSopenharmony_ci}
2603af6ab5fSopenharmony_ci
2613af6ab5fSopenharmony_cichecker::Type *ETSChecker::CheckBinaryOperatorPlus(
2623af6ab5fSopenharmony_ci    std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op, bool isEqualOp,
2633af6ab5fSopenharmony_ci    std::tuple<checker::Type *, checker::Type *, Type *, Type *> types)
2643af6ab5fSopenharmony_ci{
2653af6ab5fSopenharmony_ci    auto [left, right, operationType, pos] = op;
2663af6ab5fSopenharmony_ci    auto [leftType, rightType, unboxedL, unboxedR] = types;
2673af6ab5fSopenharmony_ci
2683af6ab5fSopenharmony_ci    // Try to handle errors on a lower level
2693af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&leftType, &rightType);
2703af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&unboxedL, &unboxedR);
2713af6ab5fSopenharmony_ci    if (leftType->IsTypeError()) {  // both are errors
2723af6ab5fSopenharmony_ci        return GlobalTypeError();
2733af6ab5fSopenharmony_ci    }
2743af6ab5fSopenharmony_ci
2753af6ab5fSopenharmony_ci    if (leftType->IsETSStringType() || rightType->IsETSStringType()) {
2763af6ab5fSopenharmony_ci        if (operationType == lexer::TokenType::PUNCTUATOR_MINUS ||
2773af6ab5fSopenharmony_ci            operationType == lexer::TokenType::PUNCTUATOR_MINUS_EQUAL) {
2783af6ab5fSopenharmony_ci            LogTypeError("Bad operand type, the types of the operands must be numeric type.", pos);
2793af6ab5fSopenharmony_ci            return GlobalTypeError();
2803af6ab5fSopenharmony_ci        }
2813af6ab5fSopenharmony_ci
2823af6ab5fSopenharmony_ci        return HandleStringConcatenation(leftType, rightType);
2833af6ab5fSopenharmony_ci    }
2843af6ab5fSopenharmony_ci
2853af6ab5fSopenharmony_ci    if (!CheckBinaryPlusMultDivOperandsForUnionType(leftType, rightType, left, right)) {
2863af6ab5fSopenharmony_ci        return GlobalTypeError();
2873af6ab5fSopenharmony_ci    }
2883af6ab5fSopenharmony_ci
2893af6ab5fSopenharmony_ci    auto [promotedType, bothConst] =
2903af6ab5fSopenharmony_ci        ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC, !isEqualOp);
2913af6ab5fSopenharmony_ci
2923af6ab5fSopenharmony_ci    FlagExpressionWithUnboxing(leftType, unboxedL, left);
2933af6ab5fSopenharmony_ci    FlagExpressionWithUnboxing(rightType, unboxedR, right);
2943af6ab5fSopenharmony_ci
2953af6ab5fSopenharmony_ci    if (promotedType == nullptr && !bothConst) {
2963af6ab5fSopenharmony_ci        auto type = CheckBinaryOperatorPlusForEnums(leftType, rightType);
2973af6ab5fSopenharmony_ci        if (type != nullptr) {
2983af6ab5fSopenharmony_ci            return type;
2993af6ab5fSopenharmony_ci        }
3003af6ab5fSopenharmony_ci        LogTypeError("Bad operand type, the types of the operands must be numeric type, enum or String.", pos);
3013af6ab5fSopenharmony_ci        return GlobalTypeError();
3023af6ab5fSopenharmony_ci    }
3033af6ab5fSopenharmony_ci
3043af6ab5fSopenharmony_ci    if (bothConst) {
3053af6ab5fSopenharmony_ci        return HandleArithmeticOperationOnTypes(leftType, rightType, operationType);
3063af6ab5fSopenharmony_ci    }
3073af6ab5fSopenharmony_ci
3083af6ab5fSopenharmony_ci    return promotedType;
3093af6ab5fSopenharmony_ci}
3103af6ab5fSopenharmony_ci
3113af6ab5fSopenharmony_cichecker::Type *ETSChecker::CheckBinaryOperatorShift(
3123af6ab5fSopenharmony_ci    std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op, bool isEqualOp,
3133af6ab5fSopenharmony_ci    std::tuple<checker::Type *, checker::Type *, Type *, Type *> types)
3143af6ab5fSopenharmony_ci{
3153af6ab5fSopenharmony_ci    auto [left, right, operationType, pos] = op;
3163af6ab5fSopenharmony_ci    auto [leftType, rightType, unboxedL, unboxedR] = types;
3173af6ab5fSopenharmony_ci
3183af6ab5fSopenharmony_ci    RepairTypeErrorWithDefault(&leftType, GlobalIntType());
3193af6ab5fSopenharmony_ci    RepairTypeErrorWithDefault(&rightType, GlobalIntType());
3203af6ab5fSopenharmony_ci    RepairTypeErrorWithDefault(&unboxedL, GlobalIntType());
3213af6ab5fSopenharmony_ci    RepairTypeErrorWithDefault(&unboxedR, GlobalIntType());
3223af6ab5fSopenharmony_ci
3233af6ab5fSopenharmony_ci    if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) {
3243af6ab5fSopenharmony_ci        LogTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos);
3253af6ab5fSopenharmony_ci        return GlobalTypeError();
3263af6ab5fSopenharmony_ci    }
3273af6ab5fSopenharmony_ci
3283af6ab5fSopenharmony_ci    auto promotedLeftType = ApplyUnaryOperatorPromotion(unboxedL, false, !isEqualOp);
3293af6ab5fSopenharmony_ci    auto promotedRightType = ApplyUnaryOperatorPromotion(unboxedR, false, !isEqualOp);
3303af6ab5fSopenharmony_ci
3313af6ab5fSopenharmony_ci    FlagExpressionWithUnboxing(leftType, unboxedL, left);
3323af6ab5fSopenharmony_ci    FlagExpressionWithUnboxing(rightType, unboxedR, right);
3333af6ab5fSopenharmony_ci
3343af6ab5fSopenharmony_ci    if (promotedLeftType == nullptr || !promotedLeftType->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) ||
3353af6ab5fSopenharmony_ci        promotedRightType == nullptr ||
3363af6ab5fSopenharmony_ci        !promotedRightType->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) {
3373af6ab5fSopenharmony_ci        LogTypeError("Bad operand type, the types of the operands must be numeric type.", pos);
3383af6ab5fSopenharmony_ci        return GlobalTypeError();
3393af6ab5fSopenharmony_ci    }
3403af6ab5fSopenharmony_ci
3413af6ab5fSopenharmony_ci    if (promotedLeftType->HasTypeFlag(TypeFlag::CONSTANT) && promotedRightType->HasTypeFlag(TypeFlag::CONSTANT)) {
3423af6ab5fSopenharmony_ci        return HandleBitwiseOperationOnTypes(promotedLeftType, promotedRightType, operationType);
3433af6ab5fSopenharmony_ci    }
3443af6ab5fSopenharmony_ci
3453af6ab5fSopenharmony_ci    switch (ETSType(promotedLeftType)) {
3463af6ab5fSopenharmony_ci        case TypeFlag::BYTE: {
3473af6ab5fSopenharmony_ci            return GlobalByteType();
3483af6ab5fSopenharmony_ci        }
3493af6ab5fSopenharmony_ci        case TypeFlag::SHORT: {
3503af6ab5fSopenharmony_ci            return GlobalShortType();
3513af6ab5fSopenharmony_ci        }
3523af6ab5fSopenharmony_ci        case TypeFlag::CHAR: {
3533af6ab5fSopenharmony_ci            return GlobalCharType();
3543af6ab5fSopenharmony_ci        }
3553af6ab5fSopenharmony_ci        case TypeFlag::INT:
3563af6ab5fSopenharmony_ci        case TypeFlag::FLOAT: {
3573af6ab5fSopenharmony_ci            return GlobalIntType();
3583af6ab5fSopenharmony_ci        }
3593af6ab5fSopenharmony_ci        case TypeFlag::LONG:
3603af6ab5fSopenharmony_ci        case TypeFlag::DOUBLE: {
3613af6ab5fSopenharmony_ci            return GlobalLongType();
3623af6ab5fSopenharmony_ci        }
3633af6ab5fSopenharmony_ci        default: {
3643af6ab5fSopenharmony_ci            UNREACHABLE();
3653af6ab5fSopenharmony_ci        }
3663af6ab5fSopenharmony_ci    }
3673af6ab5fSopenharmony_ci    return nullptr;
3683af6ab5fSopenharmony_ci}
3693af6ab5fSopenharmony_ci
3703af6ab5fSopenharmony_cichecker::Type *ETSChecker::CheckBinaryOperatorBitwise(
3713af6ab5fSopenharmony_ci    std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op, bool isEqualOp,
3723af6ab5fSopenharmony_ci    std::tuple<checker::Type *, checker::Type *, Type *, Type *> types)
3733af6ab5fSopenharmony_ci{
3743af6ab5fSopenharmony_ci    auto [left, right, operationType, pos] = op;
3753af6ab5fSopenharmony_ci    auto [leftType, rightType, unboxedL, unboxedR] = types;
3763af6ab5fSopenharmony_ci
3773af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&leftType, &rightType);
3783af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&unboxedL, &unboxedR);
3793af6ab5fSopenharmony_ci    if (leftType->IsTypeError()) {  // both are errors
3803af6ab5fSopenharmony_ci        return GlobalTypeError();
3813af6ab5fSopenharmony_ci    }
3823af6ab5fSopenharmony_ci
3833af6ab5fSopenharmony_ci    if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) {
3843af6ab5fSopenharmony_ci        LogTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos);
3853af6ab5fSopenharmony_ci        return GlobalTypeError();
3863af6ab5fSopenharmony_ci    }
3873af6ab5fSopenharmony_ci
3883af6ab5fSopenharmony_ci    if (unboxedL != nullptr && unboxedL->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) && unboxedR != nullptr &&
3893af6ab5fSopenharmony_ci        unboxedR->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN)) {
3903af6ab5fSopenharmony_ci        FlagExpressionWithUnboxing(leftType, unboxedL, left);
3913af6ab5fSopenharmony_ci        FlagExpressionWithUnboxing(rightType, unboxedR, right);
3923af6ab5fSopenharmony_ci        return HandleBooleanLogicalOperators(unboxedL, unboxedR, operationType);
3933af6ab5fSopenharmony_ci    }
3943af6ab5fSopenharmony_ci
3953af6ab5fSopenharmony_ci    auto [promotedType, bothConst] =
3963af6ab5fSopenharmony_ci        ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC, !isEqualOp);
3973af6ab5fSopenharmony_ci
3983af6ab5fSopenharmony_ci    FlagExpressionWithUnboxing(leftType, unboxedL, left);
3993af6ab5fSopenharmony_ci    FlagExpressionWithUnboxing(rightType, unboxedR, right);
4003af6ab5fSopenharmony_ci
4013af6ab5fSopenharmony_ci    if (promotedType == nullptr && !bothConst) {
4023af6ab5fSopenharmony_ci        LogTypeError("Bad operand type, the types of the operands must be numeric type.", pos);
4033af6ab5fSopenharmony_ci        return GlobalTypeError();
4043af6ab5fSopenharmony_ci    }
4053af6ab5fSopenharmony_ci
4063af6ab5fSopenharmony_ci    if (bothConst) {
4073af6ab5fSopenharmony_ci        return HandleBitwiseOperationOnTypes(leftType, rightType, operationType);
4083af6ab5fSopenharmony_ci    }
4093af6ab5fSopenharmony_ci
4103af6ab5fSopenharmony_ci    return SelectGlobalIntegerTypeForNumeric(promotedType);
4113af6ab5fSopenharmony_ci}
4123af6ab5fSopenharmony_ci
4133af6ab5fSopenharmony_cichecker::Type *ETSChecker::CheckBinaryOperatorLogical(ir::Expression *left, ir::Expression *right, ir::Expression *expr,
4143af6ab5fSopenharmony_ci                                                      lexer::SourcePosition pos, checker::Type *leftType,
4153af6ab5fSopenharmony_ci                                                      checker::Type *rightType, Type *unboxedL, Type *unboxedR)
4163af6ab5fSopenharmony_ci{
4173af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&leftType, &rightType);
4183af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&unboxedL, &unboxedR);
4193af6ab5fSopenharmony_ci    if (leftType->IsTypeError()) {  // both are errors
4203af6ab5fSopenharmony_ci        return GlobalTypeError();
4213af6ab5fSopenharmony_ci    }
4223af6ab5fSopenharmony_ci
4233af6ab5fSopenharmony_ci    if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) {
4243af6ab5fSopenharmony_ci        LogTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos);
4253af6ab5fSopenharmony_ci        return GlobalTypeError();
4263af6ab5fSopenharmony_ci    }
4273af6ab5fSopenharmony_ci
4283af6ab5fSopenharmony_ci    if (unboxedL == nullptr || !unboxedL->IsConditionalExprType() || unboxedR == nullptr ||
4293af6ab5fSopenharmony_ci        !unboxedR->IsConditionalExprType()) {
4303af6ab5fSopenharmony_ci        LogTypeError("Bad operand type, the types of the operands must be of possible condition type.", pos);
4313af6ab5fSopenharmony_ci        return GlobalTypeError();
4323af6ab5fSopenharmony_ci    }
4333af6ab5fSopenharmony_ci
4343af6ab5fSopenharmony_ci    if (unboxedL->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
4353af6ab5fSopenharmony_ci        FlagExpressionWithUnboxing(leftType, unboxedL, left);
4363af6ab5fSopenharmony_ci    }
4373af6ab5fSopenharmony_ci
4383af6ab5fSopenharmony_ci    if (unboxedR->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
4393af6ab5fSopenharmony_ci        FlagExpressionWithUnboxing(rightType, unboxedR, right);
4403af6ab5fSopenharmony_ci    }
4413af6ab5fSopenharmony_ci
4423af6ab5fSopenharmony_ci    if (expr->IsBinaryExpression()) {
4433af6ab5fSopenharmony_ci        return HandleBooleanLogicalOperatorsExtended(unboxedL, unboxedR, expr->AsBinaryExpression());
4443af6ab5fSopenharmony_ci    }
4453af6ab5fSopenharmony_ci
4463af6ab5fSopenharmony_ci    UNREACHABLE();
4473af6ab5fSopenharmony_ci}
4483af6ab5fSopenharmony_ci
4493af6ab5fSopenharmony_civoid ETSChecker::LogOperatorCannotBeApplied(lexer::TokenType operationType, checker::Type *const leftType,
4503af6ab5fSopenharmony_ci                                            checker::Type *const rightType, lexer::SourcePosition pos)
4513af6ab5fSopenharmony_ci{
4523af6ab5fSopenharmony_ci    LogTypeError({"Operator '", operationType, "' cannot be applied to types '", leftType, "' and '", rightType, "'."},
4533af6ab5fSopenharmony_ci                 pos);
4543af6ab5fSopenharmony_ci}
4553af6ab5fSopenharmony_ci
4563af6ab5fSopenharmony_cibool ETSChecker::CheckValidEqualReferenceType(checker::Type *const leftType, checker::Type *const rightType)
4573af6ab5fSopenharmony_ci{
4583af6ab5fSopenharmony_ci    auto isGlobalObjectType {[](checker::Type *const type) -> bool {
4593af6ab5fSopenharmony_ci        return type->IsETSObjectType() && type->AsETSObjectType()->IsGlobalETSObjectType();
4603af6ab5fSopenharmony_ci    }};
4613af6ab5fSopenharmony_ci
4623af6ab5fSopenharmony_ci    // Equality expression is always allowed for Object, undefined and null
4633af6ab5fSopenharmony_ci    if (isGlobalObjectType(leftType) || isGlobalObjectType(rightType) || leftType->IsETSUndefinedType() ||
4643af6ab5fSopenharmony_ci        rightType->IsETSUndefinedType() || leftType->IsETSNullType() || rightType->IsETSNullType()) {
4653af6ab5fSopenharmony_ci        return true;
4663af6ab5fSopenharmony_ci    }
4673af6ab5fSopenharmony_ci
4683af6ab5fSopenharmony_ci    // NOTE (mxlgv): Skip for unions. Required implementation of the specification section:
4693af6ab5fSopenharmony_ci    // 7.25.6 Reference Equality Based on Actual Type (Union Equality Operators)
4703af6ab5fSopenharmony_ci    if (leftType->IsETSUnionType()) {
4713af6ab5fSopenharmony_ci        return leftType->AsETSUnionType()->IsOverlapWith(Relation(), rightType);
4723af6ab5fSopenharmony_ci    }
4733af6ab5fSopenharmony_ci    if (rightType->IsETSUnionType()) {
4743af6ab5fSopenharmony_ci        return rightType->AsETSUnionType()->IsOverlapWith(Relation(), leftType);
4753af6ab5fSopenharmony_ci    }
4763af6ab5fSopenharmony_ci
4773af6ab5fSopenharmony_ci    // NOTE (mxlgv): Skip for generic. Required implementation of the specification section:
4783af6ab5fSopenharmony_ci    // 7.25.6 Reference Equality Based on Actual Type (Type Parameter Equality Operators)
4793af6ab5fSopenharmony_ci    if (leftType->HasTypeFlag(TypeFlag::GENERIC) || rightType->HasTypeFlag(TypeFlag::GENERIC)) {
4803af6ab5fSopenharmony_ci        return true;
4813af6ab5fSopenharmony_ci    }
4823af6ab5fSopenharmony_ci
4833af6ab5fSopenharmony_ci    // Equality expression can only be applied to String and String, and BigInt and BigInt
4843af6ab5fSopenharmony_ci    if (leftType->IsETSStringType() || rightType->IsETSStringType() || leftType->IsETSBigIntType() ||
4853af6ab5fSopenharmony_ci        rightType->IsETSBigIntType()) {
4863af6ab5fSopenharmony_ci        auto *const nonConstLhs = GetNonConstantType(leftType);
4873af6ab5fSopenharmony_ci        auto *const nonConstRhs = GetNonConstantType(rightType);
4883af6ab5fSopenharmony_ci        if (!Relation()->IsIdenticalTo(nonConstLhs, nonConstRhs) &&
4893af6ab5fSopenharmony_ci            !Relation()->IsIdenticalTo(nonConstRhs, nonConstLhs)) {
4903af6ab5fSopenharmony_ci            return false;
4913af6ab5fSopenharmony_ci        }
4923af6ab5fSopenharmony_ci    }
4933af6ab5fSopenharmony_ci
4943af6ab5fSopenharmony_ci    return true;
4953af6ab5fSopenharmony_ci}
4963af6ab5fSopenharmony_ci
4973af6ab5fSopenharmony_cistd::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorStrictEqual(ir::Expression *left,
4983af6ab5fSopenharmony_ci                                                                      lexer::TokenType operationType,
4993af6ab5fSopenharmony_ci                                                                      lexer::SourcePosition pos,
5003af6ab5fSopenharmony_ci                                                                      checker::Type *leftType, checker::Type *rightType)
5013af6ab5fSopenharmony_ci{
5023af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&leftType, &rightType);
5033af6ab5fSopenharmony_ci    if (leftType->IsTypeError()) {  // both are errors
5043af6ab5fSopenharmony_ci        // We still know that operation result should be boolean, so recover.
5053af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), GlobalETSObjectType()};
5063af6ab5fSopenharmony_ci    }
5073af6ab5fSopenharmony_ci
5083af6ab5fSopenharmony_ci    checker::Type *tsType {};
5093af6ab5fSopenharmony_ci    if (!IsReferenceType(leftType) || !IsReferenceType(rightType)) {
5103af6ab5fSopenharmony_ci        LogTypeError("Both operands have to be reference types", pos);
5113af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), GlobalETSObjectType()};
5123af6ab5fSopenharmony_ci    }
5133af6ab5fSopenharmony_ci
5143af6ab5fSopenharmony_ci    Relation()->SetNode(left);
5153af6ab5fSopenharmony_ci    if (!CheckValidEqualReferenceType(leftType, rightType)) {
5163af6ab5fSopenharmony_ci        LogOperatorCannotBeApplied(operationType, leftType, rightType, pos);
5173af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), GlobalETSObjectType()};
5183af6ab5fSopenharmony_ci    }
5193af6ab5fSopenharmony_ci
5203af6ab5fSopenharmony_ci    if (!Relation()->IsCastableTo(leftType, rightType) && !Relation()->IsCastableTo(rightType, leftType)) {
5213af6ab5fSopenharmony_ci        LogOperatorCannotBeApplied(operationType, leftType, rightType, pos);
5223af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), GlobalETSObjectType()};
5233af6ab5fSopenharmony_ci    }
5243af6ab5fSopenharmony_ci
5253af6ab5fSopenharmony_ci    tsType = GlobalETSBooleanType();
5263af6ab5fSopenharmony_ci    if (rightType->IsETSDynamicType() && leftType->IsETSDynamicType()) {
5273af6ab5fSopenharmony_ci        return {tsType, GlobalBuiltinJSValueType()};
5283af6ab5fSopenharmony_ci    }
5293af6ab5fSopenharmony_ci
5303af6ab5fSopenharmony_ci    return {tsType, GlobalETSObjectType()};
5313af6ab5fSopenharmony_ci}
5323af6ab5fSopenharmony_ci
5333af6ab5fSopenharmony_cistd::optional<std::tuple<Type *, Type *>> ETSChecker::CheckBinaryOperatorEqualError(checker::Type *const leftType,
5343af6ab5fSopenharmony_ci                                                                                    checker::Type *const rightType,
5353af6ab5fSopenharmony_ci                                                                                    checker::Type *tsType,
5363af6ab5fSopenharmony_ci                                                                                    lexer::SourcePosition pos)
5373af6ab5fSopenharmony_ci{
5383af6ab5fSopenharmony_ci    if (leftType->IsETSIntEnumType() && rightType->IsETSIntEnumType()) {
5393af6ab5fSopenharmony_ci        if (!leftType->AsETSIntEnumType()->IsSameEnumType(rightType->AsETSIntEnumType())) {
5403af6ab5fSopenharmony_ci            // We still know that operation result should be boolean, so recover.
5413af6ab5fSopenharmony_ci            LogTypeError("Bad operand type, the types of the operands must be the same enum type.", pos);
5423af6ab5fSopenharmony_ci            return {{GlobalETSBooleanType(), leftType}};
5433af6ab5fSopenharmony_ci        }
5443af6ab5fSopenharmony_ci
5453af6ab5fSopenharmony_ci        tsType = GlobalETSBooleanType();
5463af6ab5fSopenharmony_ci        return std::make_tuple(tsType, leftType);
5473af6ab5fSopenharmony_ci    }
5483af6ab5fSopenharmony_ci
5493af6ab5fSopenharmony_ci    if (leftType->IsETSStringEnumType() && rightType->IsETSStringEnumType()) {
5503af6ab5fSopenharmony_ci        if (!leftType->AsETSStringEnumType()->IsSameEnumType(rightType->AsETSStringEnumType())) {
5513af6ab5fSopenharmony_ci            LogTypeError("Bad operand type, the types of the operands must be the same enum type.", pos);
5523af6ab5fSopenharmony_ci            return {{GlobalETSBooleanType(), leftType}};
5533af6ab5fSopenharmony_ci        }
5543af6ab5fSopenharmony_ci
5553af6ab5fSopenharmony_ci        tsType = GlobalETSBooleanType();
5563af6ab5fSopenharmony_ci        return std::make_tuple(tsType, leftType);
5573af6ab5fSopenharmony_ci    }
5583af6ab5fSopenharmony_ci    return std::nullopt;
5593af6ab5fSopenharmony_ci}
5603af6ab5fSopenharmony_ci
5613af6ab5fSopenharmony_cistd::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorEqual(ir::Expression *left, ir::Expression *right,
5623af6ab5fSopenharmony_ci                                                                lexer::TokenType operationType,
5633af6ab5fSopenharmony_ci                                                                lexer::SourcePosition pos, checker::Type *leftType,
5643af6ab5fSopenharmony_ci                                                                checker::Type *rightType, Type *unboxedL,
5653af6ab5fSopenharmony_ci                                                                Type *unboxedR)
5663af6ab5fSopenharmony_ci{
5673af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&leftType, &rightType);
5683af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&unboxedL, &unboxedR);
5693af6ab5fSopenharmony_ci    if (leftType->IsTypeError()) {  // both are errors
5703af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), GlobalTypeError()};
5713af6ab5fSopenharmony_ci    }
5723af6ab5fSopenharmony_ci
5733af6ab5fSopenharmony_ci    checker::Type *tsType {};
5743af6ab5fSopenharmony_ci
5753af6ab5fSopenharmony_ci    auto checkError = CheckBinaryOperatorEqualError(leftType, rightType, tsType, pos);
5763af6ab5fSopenharmony_ci    if (checkError.has_value()) {
5773af6ab5fSopenharmony_ci        return checkError.value();
5783af6ab5fSopenharmony_ci    }
5793af6ab5fSopenharmony_ci    if (leftType->IsETSDynamicType() || rightType->IsETSDynamicType()) {
5803af6ab5fSopenharmony_ci        return CheckBinaryOperatorEqualDynamic(left, right, pos);
5813af6ab5fSopenharmony_ci    }
5823af6ab5fSopenharmony_ci
5833af6ab5fSopenharmony_ci    if (IsReferenceType(leftType) && IsReferenceType(rightType)) {
5843af6ab5fSopenharmony_ci        Relation()->SetNode(left);
5853af6ab5fSopenharmony_ci        if (!CheckValidEqualReferenceType(leftType, rightType)) {
5863af6ab5fSopenharmony_ci            LogOperatorCannotBeApplied(operationType, leftType, rightType, pos);
5873af6ab5fSopenharmony_ci            return {GlobalETSBooleanType(), leftType};
5883af6ab5fSopenharmony_ci        }
5893af6ab5fSopenharmony_ci
5903af6ab5fSopenharmony_ci        tsType = GlobalETSBooleanType();
5913af6ab5fSopenharmony_ci        return {tsType, CreateETSUnionType({leftType, rightType})};
5923af6ab5fSopenharmony_ci    }
5933af6ab5fSopenharmony_ci
5943af6ab5fSopenharmony_ci    if (unboxedL != nullptr && unboxedL->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) && unboxedR != nullptr &&
5953af6ab5fSopenharmony_ci        unboxedR->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN)) {
5963af6ab5fSopenharmony_ci        if (unboxedL->HasTypeFlag(checker::TypeFlag::CONSTANT) && unboxedR->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
5973af6ab5fSopenharmony_ci            bool res = unboxedL->AsETSBooleanType()->GetValue() == unboxedR->AsETSBooleanType()->GetValue();
5983af6ab5fSopenharmony_ci
5993af6ab5fSopenharmony_ci            tsType = CreateETSBooleanType(operationType == lexer::TokenType::PUNCTUATOR_EQUAL ? res : !res);
6003af6ab5fSopenharmony_ci            return {tsType, tsType};
6013af6ab5fSopenharmony_ci        }
6023af6ab5fSopenharmony_ci
6033af6ab5fSopenharmony_ci        FlagExpressionWithUnboxing(leftType, unboxedL, left);
6043af6ab5fSopenharmony_ci        FlagExpressionWithUnboxing(rightType, unboxedR, right);
6053af6ab5fSopenharmony_ci
6063af6ab5fSopenharmony_ci        tsType = GlobalETSBooleanType();
6073af6ab5fSopenharmony_ci        return {tsType, tsType};
6083af6ab5fSopenharmony_ci    }
6093af6ab5fSopenharmony_ci
6103af6ab5fSopenharmony_ci    // Temporary workaround before == and === refactoring
6113af6ab5fSopenharmony_ci    if ((rightType->IsETSNullType() && leftType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) ||
6123af6ab5fSopenharmony_ci        (leftType->IsETSNullType() && rightType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE))) {
6133af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), CreateETSUnionType({leftType, rightType})};
6143af6ab5fSopenharmony_ci    }
6153af6ab5fSopenharmony_ci
6163af6ab5fSopenharmony_ci    return {nullptr, nullptr};
6173af6ab5fSopenharmony_ci}
6183af6ab5fSopenharmony_ci
6193af6ab5fSopenharmony_cistd::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorEqualDynamic(ir::Expression *left, ir::Expression *right,
6203af6ab5fSopenharmony_ci                                                                       lexer::SourcePosition pos)
6213af6ab5fSopenharmony_ci{
6223af6ab5fSopenharmony_ci    // NOTE: vpukhov. enforce intrinsic call in any case?
6233af6ab5fSopenharmony_ci    // canonicalize
6243af6ab5fSopenharmony_ci    auto *const dynExp = left->TsType()->IsETSDynamicType() ? left : right;
6253af6ab5fSopenharmony_ci    auto *const otherExp = dynExp == left ? right : left;
6263af6ab5fSopenharmony_ci
6273af6ab5fSopenharmony_ci    if (otherExp->TsType()->IsETSDynamicType()) {
6283af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), GlobalBuiltinJSValueType()};
6293af6ab5fSopenharmony_ci    }
6303af6ab5fSopenharmony_ci    if (dynExp->TsType()->AsETSDynamicType()->IsConvertible(otherExp->TsType())) {
6313af6ab5fSopenharmony_ci        // NOTE: vpukhov. boxing flags are not set in dynamic values
6323af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), otherExp->TsType()};
6333af6ab5fSopenharmony_ci    }
6343af6ab5fSopenharmony_ci    if (IsReferenceType(otherExp->TsType())) {
6353af6ab5fSopenharmony_ci        // have to prevent casting dyn_exp via ApplyCast without nullish flag
6363af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), GlobalETSNullishObjectType()};
6373af6ab5fSopenharmony_ci    }
6383af6ab5fSopenharmony_ci    LogTypeError("Unimplemented case in dynamic type comparison.", pos);
6393af6ab5fSopenharmony_ci    return {GlobalETSBooleanType(), GlobalETSNullishObjectType()};
6403af6ab5fSopenharmony_ci}
6413af6ab5fSopenharmony_ci
6423af6ab5fSopenharmony_ci// Satisfying the Chinese checker
6433af6ab5fSopenharmony_cistatic bool NonNumericTypesAreAppropriateForComparison(Type *leftType, Type *rightType)
6443af6ab5fSopenharmony_ci{
6453af6ab5fSopenharmony_ci    return (rightType->IsETSStringType() && leftType->IsETSStringType()) ||
6463af6ab5fSopenharmony_ci           (((leftType->IsETSIntEnumType() && rightType->IsETSIntEnumType()) ||
6473af6ab5fSopenharmony_ci             (leftType->IsETSStringEnumType() && rightType->IsETSStringEnumType())) &&
6483af6ab5fSopenharmony_ci            leftType->AsETSEnumType()->IsSameEnumType(rightType->AsETSEnumType()));
6493af6ab5fSopenharmony_ci}
6503af6ab5fSopenharmony_ci
6513af6ab5fSopenharmony_cistd::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorLessGreater(ir::Expression *left, ir::Expression *right,
6523af6ab5fSopenharmony_ci                                                                      lexer::TokenType operationType,
6533af6ab5fSopenharmony_ci                                                                      lexer::SourcePosition pos, bool isEqualOp,
6543af6ab5fSopenharmony_ci                                                                      checker::Type *leftType, checker::Type *rightType,
6553af6ab5fSopenharmony_ci                                                                      Type *unboxedL, Type *unboxedR)
6563af6ab5fSopenharmony_ci{
6573af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&leftType, &rightType);
6583af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&unboxedL, &unboxedR);
6593af6ab5fSopenharmony_ci    if (leftType->IsTypeError()) {  // both are errors
6603af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), GlobalTypeError()};
6613af6ab5fSopenharmony_ci    }
6623af6ab5fSopenharmony_ci
6633af6ab5fSopenharmony_ci    if ((leftType->IsETSUnionType() || rightType->IsETSUnionType()) &&
6643af6ab5fSopenharmony_ci        operationType != lexer::TokenType::PUNCTUATOR_EQUAL &&
6653af6ab5fSopenharmony_ci        operationType != lexer::TokenType::PUNCTUATOR_NOT_EQUAL) {
6663af6ab5fSopenharmony_ci        LogTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos);
6673af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), leftType};
6683af6ab5fSopenharmony_ci    }
6693af6ab5fSopenharmony_ci
6703af6ab5fSopenharmony_ci    checker::Type *tsType {};
6713af6ab5fSopenharmony_ci    auto [promotedType, bothConst] =
6723af6ab5fSopenharmony_ci        ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_PRIMITIVE, !isEqualOp);
6733af6ab5fSopenharmony_ci
6743af6ab5fSopenharmony_ci    FlagExpressionWithUnboxing(leftType, unboxedL, left);
6753af6ab5fSopenharmony_ci    FlagExpressionWithUnboxing(rightType, unboxedR, right);
6763af6ab5fSopenharmony_ci
6773af6ab5fSopenharmony_ci    if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) {
6783af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), CreateETSUnionType({MaybeBoxExpression(left), MaybeBoxExpression(right)})};
6793af6ab5fSopenharmony_ci    }
6803af6ab5fSopenharmony_ci
6813af6ab5fSopenharmony_ci    if ((unboxedL != nullptr) && (unboxedR != nullptr) &&
6823af6ab5fSopenharmony_ci        (unboxedL->IsETSBooleanType() != unboxedR->IsETSBooleanType())) {
6833af6ab5fSopenharmony_ci        LogOperatorCannotBeApplied(operationType, leftType, rightType, pos);
6843af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), leftType};
6853af6ab5fSopenharmony_ci    }
6863af6ab5fSopenharmony_ci
6873af6ab5fSopenharmony_ci    if (promotedType == nullptr && !bothConst) {
6883af6ab5fSopenharmony_ci        if (NonNumericTypesAreAppropriateForComparison(leftType, rightType)) {
6893af6ab5fSopenharmony_ci            return {GlobalETSBooleanType(), GlobalETSBooleanType()};
6903af6ab5fSopenharmony_ci        }
6913af6ab5fSopenharmony_ci        if (((leftType->IsETSIntEnumType() && rightType->IsETSIntEnumType()) ||
6923af6ab5fSopenharmony_ci             (leftType->IsETSStringEnumType() && rightType->IsETSStringEnumType())) &&
6933af6ab5fSopenharmony_ci            leftType->AsETSEnumType()->IsSameEnumType(rightType->AsETSEnumType())) {
6943af6ab5fSopenharmony_ci            return {GlobalETSBooleanType(), GlobalETSBooleanType()};
6953af6ab5fSopenharmony_ci        }
6963af6ab5fSopenharmony_ci
6973af6ab5fSopenharmony_ci        LogTypeError("Bad operand type, the types of the operands must be numeric, same enumeration, or boolean type.",
6983af6ab5fSopenharmony_ci                     pos);
6993af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), GlobalETSBooleanType()};
7003af6ab5fSopenharmony_ci    }
7013af6ab5fSopenharmony_ci
7023af6ab5fSopenharmony_ci    if (bothConst) {
7033af6ab5fSopenharmony_ci        tsType = HandleRelationOperationOnTypes(leftType, rightType, operationType);
7043af6ab5fSopenharmony_ci        return {tsType, tsType};
7053af6ab5fSopenharmony_ci    }
7063af6ab5fSopenharmony_ci
7073af6ab5fSopenharmony_ci    tsType = GlobalETSBooleanType();
7083af6ab5fSopenharmony_ci    auto *opType = promotedType;
7093af6ab5fSopenharmony_ci    return {tsType, opType};
7103af6ab5fSopenharmony_ci}
7113af6ab5fSopenharmony_ci
7123af6ab5fSopenharmony_cistd::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorInstanceOf(lexer::SourcePosition pos, checker::Type *leftType,
7133af6ab5fSopenharmony_ci                                                                     checker::Type *rightType)
7143af6ab5fSopenharmony_ci{
7153af6ab5fSopenharmony_ci    RepairTypeErrorsInOperands(&leftType, &rightType);
7163af6ab5fSopenharmony_ci    if (leftType->IsTypeError()) {  // both are errors
7173af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), GlobalTypeError()};
7183af6ab5fSopenharmony_ci    }
7193af6ab5fSopenharmony_ci
7203af6ab5fSopenharmony_ci    checker::Type *tsType {};
7213af6ab5fSopenharmony_ci    if (!IsReferenceType(leftType) || (!IsReferenceType(rightType) && !rightType->IsETSEnumType())) {
7223af6ab5fSopenharmony_ci        LogTypeError("Bad operand type, the types of the operands must be same type.", pos);
7233af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), leftType};
7243af6ab5fSopenharmony_ci    }
7253af6ab5fSopenharmony_ci
7263af6ab5fSopenharmony_ci    if (rightType->IsETSDynamicType() && !rightType->AsETSDynamicType()->HasDecl()) {
7273af6ab5fSopenharmony_ci        LogTypeError("Right-hand side of instanceof expression must represent a type.", pos);
7283af6ab5fSopenharmony_ci        return {GlobalETSBooleanType(), leftType};
7293af6ab5fSopenharmony_ci    }
7303af6ab5fSopenharmony_ci
7313af6ab5fSopenharmony_ci    tsType = GlobalETSBooleanType();
7323af6ab5fSopenharmony_ci    checker::Type *opType = rightType->IsETSDynamicType() ? GlobalBuiltinJSValueType() : GlobalETSObjectType();
7333af6ab5fSopenharmony_ci    ComputeApparentType(rightType);
7343af6ab5fSopenharmony_ci    RemoveStatus(checker::CheckerStatus::IN_INSTANCEOF_CONTEXT);
7353af6ab5fSopenharmony_ci
7363af6ab5fSopenharmony_ci    return {tsType, opType};
7373af6ab5fSopenharmony_ci}
7383af6ab5fSopenharmony_ci
7393af6ab5fSopenharmony_cibool ETSChecker::AdjustNumberLiteralType(ir::NumberLiteral *const literal, Type *literalType, Type *const otherType)
7403af6ab5fSopenharmony_ci{
7413af6ab5fSopenharmony_ci    if (otherType->IsETSObjectType()) {
7423af6ab5fSopenharmony_ci        auto *const objectType = otherType->AsETSObjectType();
7433af6ab5fSopenharmony_ci        if (objectType->HasObjectFlag(ETSObjectFlags::BUILTIN_TYPE) && !objectType->IsETSStringType()) {
7443af6ab5fSopenharmony_ci            literal->RemoveBoxingUnboxingFlags(GetBoxingFlag(literalType));
7453af6ab5fSopenharmony_ci            literalType = ETSBuiltinTypeAsPrimitiveType(objectType);
7463af6ab5fSopenharmony_ci            literal->SetTsType(literalType);
7473af6ab5fSopenharmony_ci            literal->AddBoxingUnboxingFlags(GetBoxingFlag(literalType));
7483af6ab5fSopenharmony_ci            return true;
7493af6ab5fSopenharmony_ci        }
7503af6ab5fSopenharmony_ci    }
7513af6ab5fSopenharmony_ci    return false;
7523af6ab5fSopenharmony_ci}
7533af6ab5fSopenharmony_ci
7543af6ab5fSopenharmony_ciType *ETSChecker::CheckBinaryOperatorNullishCoalescing(ir::Expression *left, ir::Expression *right,
7553af6ab5fSopenharmony_ci                                                       lexer::SourcePosition pos)
7563af6ab5fSopenharmony_ci{
7573af6ab5fSopenharmony_ci    auto *leftType = left->TsType();
7583af6ab5fSopenharmony_ci    if (!IsReferenceType(leftType) && !leftType->IsETSEnumType()) {
7593af6ab5fSopenharmony_ci        LogTypeError("Left-hand side of nullish-coalescing expression must be a reference or enum type.", pos);
7603af6ab5fSopenharmony_ci        return leftType;
7613af6ab5fSopenharmony_ci    }
7623af6ab5fSopenharmony_ci
7633af6ab5fSopenharmony_ci    auto *rightType = right->TsType();
7643af6ab5fSopenharmony_ci
7653af6ab5fSopenharmony_ci    if (leftType->IsETSEnumType()) {
7663af6ab5fSopenharmony_ci        left->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::BOX_TO_ENUM);
7673af6ab5fSopenharmony_ci        leftType = leftType->AsETSEnumType()->GetDecl()->BoxedClass()->TsType();
7683af6ab5fSopenharmony_ci    } else {
7693af6ab5fSopenharmony_ci        leftType = GetNonNullishType(leftType);
7703af6ab5fSopenharmony_ci    }
7713af6ab5fSopenharmony_ci
7723af6ab5fSopenharmony_ci    if (rightType->IsETSEnumType()) {
7733af6ab5fSopenharmony_ci        right->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::BOX_TO_ENUM);
7743af6ab5fSopenharmony_ci        rightType = rightType->AsETSEnumType()->GetDecl()->BoxedClass()->TsType();
7753af6ab5fSopenharmony_ci    } else {
7763af6ab5fSopenharmony_ci        rightType = MaybeBoxExpression(right);
7773af6ab5fSopenharmony_ci    }
7783af6ab5fSopenharmony_ci
7793af6ab5fSopenharmony_ci    if (IsTypeIdenticalTo(leftType, rightType)) {
7803af6ab5fSopenharmony_ci        return leftType;
7813af6ab5fSopenharmony_ci    }
7823af6ab5fSopenharmony_ci
7833af6ab5fSopenharmony_ci    //  If possible and required update number literal type to the proper value (identical to left-side type)
7843af6ab5fSopenharmony_ci    if (right->IsNumberLiteral() && AdjustNumberLiteralType(right->AsNumberLiteral(), rightType, leftType)) {
7853af6ab5fSopenharmony_ci        return leftType;
7863af6ab5fSopenharmony_ci    }
7873af6ab5fSopenharmony_ci
7883af6ab5fSopenharmony_ci    return CreateETSUnionType({leftType, rightType});
7893af6ab5fSopenharmony_ci}
7903af6ab5fSopenharmony_ci
7913af6ab5fSopenharmony_ciusing CheckBinaryFunction = std::function<checker::Type *(
7923af6ab5fSopenharmony_ci    ETSChecker *, std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op,
7933af6ab5fSopenharmony_ci    bool isEqualOp, std::tuple<checker::Type *, checker::Type *, Type *, Type *> types)>;
7943af6ab5fSopenharmony_ci
7953af6ab5fSopenharmony_cistd::map<lexer::TokenType, CheckBinaryFunction> &GetCheckMap()
7963af6ab5fSopenharmony_ci{
7973af6ab5fSopenharmony_ci    static std::map<lexer::TokenType, CheckBinaryFunction> checkMap = {
7983af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_MULTIPLY, &ETSChecker::CheckBinaryOperatorMulDivMod},
7993af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod},
8003af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_DIVIDE, &ETSChecker::CheckBinaryOperatorMulDivMod},
8013af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod},
8023af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_MOD, &ETSChecker::CheckBinaryOperatorMulDivMod},
8033af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_MOD_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod},
8043af6ab5fSopenharmony_ci
8053af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_MINUS, &ETSChecker::CheckBinaryOperatorPlus},
8063af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_MINUS_EQUAL, &ETSChecker::CheckBinaryOperatorPlus},
8073af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_PLUS, &ETSChecker::CheckBinaryOperatorPlus},
8083af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_PLUS_EQUAL, &ETSChecker::CheckBinaryOperatorPlus},
8093af6ab5fSopenharmony_ci
8103af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT, &ETSChecker::CheckBinaryOperatorShift},
8113af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift},
8123af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT, &ETSChecker::CheckBinaryOperatorShift},
8133af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift},
8143af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT, &ETSChecker::CheckBinaryOperatorShift},
8153af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift},
8163af6ab5fSopenharmony_ci
8173af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_BITWISE_OR, &ETSChecker::CheckBinaryOperatorBitwise},
8183af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise},
8193af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_BITWISE_AND, &ETSChecker::CheckBinaryOperatorBitwise},
8203af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise},
8213af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_BITWISE_XOR, &ETSChecker::CheckBinaryOperatorBitwise},
8223af6ab5fSopenharmony_ci        {lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise},
8233af6ab5fSopenharmony_ci    };
8243af6ab5fSopenharmony_ci
8253af6ab5fSopenharmony_ci    return checkMap;
8263af6ab5fSopenharmony_ci}
8273af6ab5fSopenharmony_ci
8283af6ab5fSopenharmony_cistruct BinaryOperatorParams {
8293af6ab5fSopenharmony_ci    ir::Expression *left;
8303af6ab5fSopenharmony_ci    ir::Expression *right;
8313af6ab5fSopenharmony_ci    ir::Expression *expr;
8323af6ab5fSopenharmony_ci    lexer::TokenType operationType;
8333af6ab5fSopenharmony_ci    lexer::SourcePosition pos;
8343af6ab5fSopenharmony_ci    bool isEqualOp;
8353af6ab5fSopenharmony_ci};
8363af6ab5fSopenharmony_ci
8373af6ab5fSopenharmony_cistruct TypeParams {
8383af6ab5fSopenharmony_ci    checker::Type *leftType;
8393af6ab5fSopenharmony_ci    checker::Type *rightType;
8403af6ab5fSopenharmony_ci    Type *unboxedL;
8413af6ab5fSopenharmony_ci    Type *unboxedR;
8423af6ab5fSopenharmony_ci};
8433af6ab5fSopenharmony_ci
8443af6ab5fSopenharmony_cistatic std::tuple<Type *, Type *> CheckBinaryOperatorHelper(ETSChecker *checker,
8453af6ab5fSopenharmony_ci                                                            const BinaryOperatorParams &binaryParams,
8463af6ab5fSopenharmony_ci                                                            const TypeParams &typeParams)
8473af6ab5fSopenharmony_ci{
8483af6ab5fSopenharmony_ci    ir::Expression *left = binaryParams.left;
8493af6ab5fSopenharmony_ci    ir::Expression *right = binaryParams.right;
8503af6ab5fSopenharmony_ci    lexer::SourcePosition pos = binaryParams.pos;
8513af6ab5fSopenharmony_ci    checker::Type *const leftType = typeParams.leftType;
8523af6ab5fSopenharmony_ci    checker::Type *const rightType = typeParams.rightType;
8533af6ab5fSopenharmony_ci    checker::Type *tsType {};
8543af6ab5fSopenharmony_ci    switch (binaryParams.operationType) {
8553af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LOGICAL_AND:
8563af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
8573af6ab5fSopenharmony_ci            tsType = checker->CheckBinaryOperatorLogical(left, right, binaryParams.expr, pos, leftType, rightType,
8583af6ab5fSopenharmony_ci                                                         typeParams.unboxedL, typeParams.unboxedR);
8593af6ab5fSopenharmony_ci            break;
8603af6ab5fSopenharmony_ci        }
8613af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
8623af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: {
8633af6ab5fSopenharmony_ci            return checker->CheckBinaryOperatorStrictEqual(left, binaryParams.operationType, pos, leftType, rightType);
8643af6ab5fSopenharmony_ci        }
8653af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_EQUAL:
8663af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: {
8673af6ab5fSopenharmony_ci            std::tuple<Type *, Type *> res =
8683af6ab5fSopenharmony_ci                checker->CheckBinaryOperatorEqual(left, right, binaryParams.operationType, pos, leftType, rightType,
8693af6ab5fSopenharmony_ci                                                  typeParams.unboxedL, typeParams.unboxedR);
8703af6ab5fSopenharmony_ci            if (!(std::get<0>(res) == nullptr && std::get<1>(res) == nullptr)) {
8713af6ab5fSopenharmony_ci                return res;
8723af6ab5fSopenharmony_ci            }
8733af6ab5fSopenharmony_ci            [[fallthrough]];
8743af6ab5fSopenharmony_ci        }
8753af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LESS_THAN:
8763af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
8773af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
8783af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
8793af6ab5fSopenharmony_ci            return checker->CheckBinaryOperatorLessGreater(left, right, binaryParams.operationType, pos,
8803af6ab5fSopenharmony_ci                                                           binaryParams.isEqualOp, leftType, rightType,
8813af6ab5fSopenharmony_ci                                                           typeParams.unboxedL, typeParams.unboxedR);
8823af6ab5fSopenharmony_ci        }
8833af6ab5fSopenharmony_ci        case lexer::TokenType::KEYW_INSTANCEOF: {
8843af6ab5fSopenharmony_ci            return checker->CheckBinaryOperatorInstanceOf(pos, leftType, rightType);
8853af6ab5fSopenharmony_ci        }
8863af6ab5fSopenharmony_ci        case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: {
8873af6ab5fSopenharmony_ci            tsType = checker->CheckBinaryOperatorNullishCoalescing(left, right, pos);
8883af6ab5fSopenharmony_ci            break;
8893af6ab5fSopenharmony_ci        }
8903af6ab5fSopenharmony_ci        default: {
8913af6ab5fSopenharmony_ci            UNREACHABLE();
8923af6ab5fSopenharmony_ci            break;
8933af6ab5fSopenharmony_ci        }
8943af6ab5fSopenharmony_ci    }
8953af6ab5fSopenharmony_ci
8963af6ab5fSopenharmony_ci    return {tsType, tsType};
8973af6ab5fSopenharmony_ci}
8983af6ab5fSopenharmony_ci
8993af6ab5fSopenharmony_cinamespace {
9003af6ab5fSopenharmony_cibool IsStringEnum(const ir::Expression *expr)
9013af6ab5fSopenharmony_ci{
9023af6ab5fSopenharmony_ci    if (expr == nullptr) {
9033af6ab5fSopenharmony_ci        return false;
9043af6ab5fSopenharmony_ci    }
9053af6ab5fSopenharmony_ci    if (expr->TsTypeOrError()->IsTypeError()) {
9063af6ab5fSopenharmony_ci        return false;
9073af6ab5fSopenharmony_ci    }
9083af6ab5fSopenharmony_ci
9093af6ab5fSopenharmony_ci    auto type = expr->TsType();
9103af6ab5fSopenharmony_ci    if (type == nullptr) {
9113af6ab5fSopenharmony_ci        return false;
9123af6ab5fSopenharmony_ci    }
9133af6ab5fSopenharmony_ci
9143af6ab5fSopenharmony_ci    return type->IsETSStringEnumType();
9153af6ab5fSopenharmony_ci}
9163af6ab5fSopenharmony_ci
9173af6ab5fSopenharmony_cibool IsIntEnum(const ir::Expression *expr)
9183af6ab5fSopenharmony_ci{
9193af6ab5fSopenharmony_ci    if (expr == nullptr) {
9203af6ab5fSopenharmony_ci        return false;
9213af6ab5fSopenharmony_ci    }
9223af6ab5fSopenharmony_ci    if (expr->TsTypeOrError()->IsTypeError()) {
9233af6ab5fSopenharmony_ci        return false;
9243af6ab5fSopenharmony_ci    }
9253af6ab5fSopenharmony_ci
9263af6ab5fSopenharmony_ci    auto type = expr->TsType();
9273af6ab5fSopenharmony_ci    if (type == nullptr) {
9283af6ab5fSopenharmony_ci        return false;
9293af6ab5fSopenharmony_ci    }
9303af6ab5fSopenharmony_ci
9313af6ab5fSopenharmony_ci    return type->IsETSIntEnumType();
9323af6ab5fSopenharmony_ci}
9333af6ab5fSopenharmony_ci
9343af6ab5fSopenharmony_cibool CheckNumericOperatorContext(ir::Expression *expression, lexer::TokenType op)
9353af6ab5fSopenharmony_ci{
9363af6ab5fSopenharmony_ci    const bool isMultiplicative = op == lexer::TokenType::PUNCTUATOR_MULTIPLY ||
9373af6ab5fSopenharmony_ci                                  op == lexer::TokenType::PUNCTUATOR_DIVIDE || op == lexer::TokenType::PUNCTUATOR_MOD;
9383af6ab5fSopenharmony_ci    const bool isAdditive = op == lexer::TokenType::PUNCTUATOR_PLUS || op == lexer::TokenType::PUNCTUATOR_MINUS;
9393af6ab5fSopenharmony_ci    const bool isShift = op == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT ||
9403af6ab5fSopenharmony_ci                         op == lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT ||
9413af6ab5fSopenharmony_ci                         op == lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT;
9423af6ab5fSopenharmony_ci    const bool isRelational =
9433af6ab5fSopenharmony_ci        op == lexer::TokenType::PUNCTUATOR_GREATER_THAN || op == lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL ||
9443af6ab5fSopenharmony_ci        op == lexer::TokenType::PUNCTUATOR_LESS_THAN || op == lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL;
9453af6ab5fSopenharmony_ci    const bool isEquality = op == lexer::TokenType::PUNCTUATOR_EQUAL || op == lexer::TokenType::PUNCTUATOR_NOT_EQUAL;
9463af6ab5fSopenharmony_ci    const bool isBitwise = op == lexer::TokenType::PUNCTUATOR_BITWISE_AND ||
9473af6ab5fSopenharmony_ci                           op == lexer::TokenType::PUNCTUATOR_BITWISE_OR ||
9483af6ab5fSopenharmony_ci                           op == lexer::TokenType::PUNCTUATOR_BITWISE_XOR;
9493af6ab5fSopenharmony_ci    const bool isConditionalAndOr =
9503af6ab5fSopenharmony_ci        op == lexer::TokenType::PUNCTUATOR_LOGICAL_AND || op == lexer::TokenType::PUNCTUATOR_LOGICAL_OR;
9513af6ab5fSopenharmony_ci
9523af6ab5fSopenharmony_ci    if (IsIntEnum(expression)) {
9533af6ab5fSopenharmony_ci        if (isMultiplicative || isAdditive || isShift || isRelational || isEquality || isBitwise ||
9543af6ab5fSopenharmony_ci            isConditionalAndOr) {
9553af6ab5fSopenharmony_ci            expression->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF);
9563af6ab5fSopenharmony_ci        }
9573af6ab5fSopenharmony_ci        return true;
9583af6ab5fSopenharmony_ci    }
9593af6ab5fSopenharmony_ci    return false;
9603af6ab5fSopenharmony_ci}
9613af6ab5fSopenharmony_ci
9623af6ab5fSopenharmony_civoid CheckStringOperatorContext(ir::Expression *expression, checker::Type *otherType, lexer::TokenType op)
9633af6ab5fSopenharmony_ci{
9643af6ab5fSopenharmony_ci    if (IsStringEnum(expression) && (otherType->IsETSStringType() || otherType->IsETSStringEnumType())) {
9653af6ab5fSopenharmony_ci        if (op == lexer::TokenType::PUNCTUATOR_PLUS) {
9663af6ab5fSopenharmony_ci            expression->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF);
9673af6ab5fSopenharmony_ci        }
9683af6ab5fSopenharmony_ci    }
9693af6ab5fSopenharmony_ci}
9703af6ab5fSopenharmony_ci
9713af6ab5fSopenharmony_cibool CheckRelationalOperatorsBetweenEnums(ir::Expression *left, ir::Expression *right, lexer::TokenType op)
9723af6ab5fSopenharmony_ci{
9733af6ab5fSopenharmony_ci    const bool isRelational =
9743af6ab5fSopenharmony_ci        op == lexer::TokenType::PUNCTUATOR_GREATER_THAN || op == lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL ||
9753af6ab5fSopenharmony_ci        op == lexer::TokenType::PUNCTUATOR_LESS_THAN || op == lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL;
9763af6ab5fSopenharmony_ci    const bool isEquality = op == lexer::TokenType::PUNCTUATOR_EQUAL || op == lexer::TokenType::PUNCTUATOR_NOT_EQUAL;
9773af6ab5fSopenharmony_ci
9783af6ab5fSopenharmony_ci    if (((IsStringEnum(left) && IsStringEnum(right)) ||
9793af6ab5fSopenharmony_ci         (IsIntEnum(left) && IsIntEnum(right)))) {  // NOTE(psiket) In case of int enums it has been already checked in
9803af6ab5fSopenharmony_ci                                                    // the CheckNumericOperatorContext function
9813af6ab5fSopenharmony_ci        if (isRelational || isEquality) {
9823af6ab5fSopenharmony_ci            left->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF);
9833af6ab5fSopenharmony_ci            right->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF);
9843af6ab5fSopenharmony_ci            return true;
9853af6ab5fSopenharmony_ci        }
9863af6ab5fSopenharmony_ci    }
9873af6ab5fSopenharmony_ci    return false;
9883af6ab5fSopenharmony_ci}
9893af6ab5fSopenharmony_ci
9903af6ab5fSopenharmony_civoid CheckNeedToGenerateGetValueForBinaryExpression(ir::Expression *expression)
9913af6ab5fSopenharmony_ci{
9923af6ab5fSopenharmony_ci    if (!expression->IsBinaryExpression()) {
9933af6ab5fSopenharmony_ci        return;
9943af6ab5fSopenharmony_ci    }
9953af6ab5fSopenharmony_ci
9963af6ab5fSopenharmony_ci    auto binaryExpression = expression->AsBinaryExpression();
9973af6ab5fSopenharmony_ci    auto op = binaryExpression->OperatorType();
9983af6ab5fSopenharmony_ci    auto leftExp = binaryExpression->Left();
9993af6ab5fSopenharmony_ci    auto rightExp = binaryExpression->Right();
10003af6ab5fSopenharmony_ci
10013af6ab5fSopenharmony_ci    // Numeric Operator Context
10023af6ab5fSopenharmony_ci    auto leftIsIntEnum = CheckNumericOperatorContext(leftExp, op);
10033af6ab5fSopenharmony_ci    auto rightIsIntEnum = CheckNumericOperatorContext(rightExp, op);
10043af6ab5fSopenharmony_ci    if (leftIsIntEnum || rightIsIntEnum) {
10053af6ab5fSopenharmony_ci        return;
10063af6ab5fSopenharmony_ci    }
10073af6ab5fSopenharmony_ci
10083af6ab5fSopenharmony_ci    // String Operator Context
10093af6ab5fSopenharmony_ci    CheckStringOperatorContext(leftExp, rightExp->TsTypeOrError(), op);
10103af6ab5fSopenharmony_ci    CheckStringOperatorContext(rightExp, leftExp->TsTypeOrError(), op);
10113af6ab5fSopenharmony_ci
10123af6ab5fSopenharmony_ci    // Relational operators if both are enumeration Types
10133af6ab5fSopenharmony_ci    if (CheckRelationalOperatorsBetweenEnums(leftExp, rightExp, op)) {
10143af6ab5fSopenharmony_ci        return;
10153af6ab5fSopenharmony_ci    }
10163af6ab5fSopenharmony_ci}
10173af6ab5fSopenharmony_ci}  // namespace
10183af6ab5fSopenharmony_ci
10193af6ab5fSopenharmony_cistd::tuple<Type *, Type *> ETSChecker::CheckArithmeticOperations(
10203af6ab5fSopenharmony_ci    ir::Expression *expr, std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op,
10213af6ab5fSopenharmony_ci    bool isEqualOp, std::tuple<checker::Type *, checker::Type *, Type *, Type *> types)
10223af6ab5fSopenharmony_ci{
10233af6ab5fSopenharmony_ci    auto [left, right, operationType, pos] = op;
10243af6ab5fSopenharmony_ci    auto [leftType, rightType, unboxedL, unboxedR] = types;
10253af6ab5fSopenharmony_ci
10263af6ab5fSopenharmony_ci    if (leftType->IsETSUnionType()) {
10273af6ab5fSopenharmony_ci        leftType = GetNonConstantType(leftType);
10283af6ab5fSopenharmony_ci    }
10293af6ab5fSopenharmony_ci
10303af6ab5fSopenharmony_ci    if (rightType->IsETSUnionType()) {
10313af6ab5fSopenharmony_ci        rightType = GetNonConstantType(rightType);
10323af6ab5fSopenharmony_ci    }
10333af6ab5fSopenharmony_ci
10343af6ab5fSopenharmony_ci    auto checkMap = GetCheckMap();
10353af6ab5fSopenharmony_ci    if (checkMap.find(operationType) != checkMap.end()) {
10363af6ab5fSopenharmony_ci        auto check = checkMap[operationType];
10373af6ab5fSopenharmony_ci        auto tsType = check(this, std::make_tuple(left, right, operationType, pos), isEqualOp,
10383af6ab5fSopenharmony_ci                            std::make_tuple(leftType, rightType, unboxedL, unboxedR));
10393af6ab5fSopenharmony_ci        return {tsType, tsType};
10403af6ab5fSopenharmony_ci    }
10413af6ab5fSopenharmony_ci
10423af6ab5fSopenharmony_ci    return CheckBinaryOperatorHelper(this, {left, right, expr, operationType, pos, isEqualOp},
10433af6ab5fSopenharmony_ci                                     {leftType, rightType, unboxedL, unboxedR});
10443af6ab5fSopenharmony_ci}
10453af6ab5fSopenharmony_ci
10463af6ab5fSopenharmony_cistd::tuple<Type *, Type *> ETSChecker::CheckBinaryOperator(ir::Expression *left, ir::Expression *right,
10473af6ab5fSopenharmony_ci                                                           ir::Expression *expr, lexer::TokenType operationType,
10483af6ab5fSopenharmony_ci                                                           lexer::SourcePosition pos, bool forcePromotion)
10493af6ab5fSopenharmony_ci{
10503af6ab5fSopenharmony_ci    checker::Type *leftType = left->Check(this);
10513af6ab5fSopenharmony_ci
10523af6ab5fSopenharmony_ci    if (leftType == nullptr) {
10533af6ab5fSopenharmony_ci        LogTypeError("Unexpected type error in binary expression", left->Start());
10543af6ab5fSopenharmony_ci        auto rightType = right->Check(this);
10553af6ab5fSopenharmony_ci        return {rightType, rightType};
10563af6ab5fSopenharmony_ci    }
10573af6ab5fSopenharmony_ci
10583af6ab5fSopenharmony_ci    if (operationType == lexer::TokenType::KEYW_INSTANCEOF) {
10593af6ab5fSopenharmony_ci        AddStatus(checker::CheckerStatus::IN_INSTANCEOF_CONTEXT);
10603af6ab5fSopenharmony_ci    }
10613af6ab5fSopenharmony_ci
10623af6ab5fSopenharmony_ci    Context().CheckTestSmartCastCondition(operationType);
10633af6ab5fSopenharmony_ci
10643af6ab5fSopenharmony_ci    checker::Type *rightType = right->Check(this);
10653af6ab5fSopenharmony_ci    if (right->IsTypeNode()) {
10663af6ab5fSopenharmony_ci        rightType = right->AsTypeNode()->GetType(this);
10673af6ab5fSopenharmony_ci    }
10683af6ab5fSopenharmony_ci
10693af6ab5fSopenharmony_ci    if (rightType == nullptr) {
10703af6ab5fSopenharmony_ci        LogTypeError("Unexpected type error in binary expression", pos);
10713af6ab5fSopenharmony_ci        return {leftType, leftType};
10723af6ab5fSopenharmony_ci    }
10733af6ab5fSopenharmony_ci
10743af6ab5fSopenharmony_ci    CheckNeedToGenerateGetValueForBinaryExpression(expr);
10753af6ab5fSopenharmony_ci
10763af6ab5fSopenharmony_ci    const bool isLogicalExtendedOperator = (operationType == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) ||
10773af6ab5fSopenharmony_ci                                           (operationType == lexer::TokenType::PUNCTUATOR_LOGICAL_OR);
10783af6ab5fSopenharmony_ci    Type *unboxedL =
10793af6ab5fSopenharmony_ci        isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(leftType) : ETSBuiltinTypeAsPrimitiveType(leftType);
10803af6ab5fSopenharmony_ci    Type *unboxedR = isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(rightType)
10813af6ab5fSopenharmony_ci                                               : ETSBuiltinTypeAsPrimitiveType(rightType);
10823af6ab5fSopenharmony_ci
10833af6ab5fSopenharmony_ci    bool isEqualOp = (operationType > lexer::TokenType::PUNCTUATOR_SUBSTITUTION &&
10843af6ab5fSopenharmony_ci                      operationType < lexer::TokenType::PUNCTUATOR_ARROW) &&
10853af6ab5fSopenharmony_ci                     !forcePromotion;
10863af6ab5fSopenharmony_ci
10873af6ab5fSopenharmony_ci    if (CheckBinaryOperatorForBigInt(leftType, rightType, operationType)) {
10883af6ab5fSopenharmony_ci        switch (operationType) {
10893af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
10903af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_LESS_THAN:
10913af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL:
10923af6ab5fSopenharmony_ci            case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
10933af6ab5fSopenharmony_ci                return {GlobalETSBooleanType(), GlobalETSBooleanType()};
10943af6ab5fSopenharmony_ci            default:
10953af6ab5fSopenharmony_ci                return {leftType, rightType};
10963af6ab5fSopenharmony_ci        }
10973af6ab5fSopenharmony_ci    }
10983af6ab5fSopenharmony_ci
10993af6ab5fSopenharmony_ci    return CheckArithmeticOperations(expr, std::make_tuple(left, right, operationType, pos), isEqualOp,
11003af6ab5fSopenharmony_ci                                     std::make_tuple(leftType, rightType, unboxedL, unboxedR));
11013af6ab5fSopenharmony_ci}
11023af6ab5fSopenharmony_ci
11033af6ab5fSopenharmony_ciType *ETSChecker::HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
11043af6ab5fSopenharmony_ci{
11053af6ab5fSopenharmony_ci    ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) &&
11063af6ab5fSopenharmony_ci           right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC));
11073af6ab5fSopenharmony_ci
11083af6ab5fSopenharmony_ci    if (left->IsDoubleType() || right->IsDoubleType()) {
11093af6ab5fSopenharmony_ci        return PerformArithmeticOperationOnTypes<DoubleType>(left, right, operationType);
11103af6ab5fSopenharmony_ci    }
11113af6ab5fSopenharmony_ci
11123af6ab5fSopenharmony_ci    if (left->IsFloatType() || right->IsFloatType()) {
11133af6ab5fSopenharmony_ci        return PerformArithmeticOperationOnTypes<FloatType>(left, right, operationType);
11143af6ab5fSopenharmony_ci    }
11153af6ab5fSopenharmony_ci
11163af6ab5fSopenharmony_ci    if (left->IsLongType() || right->IsLongType()) {
11173af6ab5fSopenharmony_ci        return PerformArithmeticOperationOnTypes<LongType>(left, right, operationType);
11183af6ab5fSopenharmony_ci    }
11193af6ab5fSopenharmony_ci
11203af6ab5fSopenharmony_ci    return PerformArithmeticOperationOnTypes<IntType>(left, right, operationType);
11213af6ab5fSopenharmony_ci}
11223af6ab5fSopenharmony_ci
11233af6ab5fSopenharmony_ciType *ETSChecker::HandleBitwiseOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
11243af6ab5fSopenharmony_ci{
11253af6ab5fSopenharmony_ci    ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) &&
11263af6ab5fSopenharmony_ci           right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC));
11273af6ab5fSopenharmony_ci
11283af6ab5fSopenharmony_ci    if (left->IsDoubleType() || right->IsDoubleType()) {
11293af6ab5fSopenharmony_ci        return HandleBitWiseArithmetic<DoubleType, LongType>(left, right, operationType);
11303af6ab5fSopenharmony_ci    }
11313af6ab5fSopenharmony_ci
11323af6ab5fSopenharmony_ci    if (left->IsFloatType() || right->IsFloatType()) {
11333af6ab5fSopenharmony_ci        return HandleBitWiseArithmetic<FloatType, IntType>(left, right, operationType);
11343af6ab5fSopenharmony_ci    }
11353af6ab5fSopenharmony_ci
11363af6ab5fSopenharmony_ci    if (left->IsLongType() || right->IsLongType()) {
11373af6ab5fSopenharmony_ci        return HandleBitWiseArithmetic<LongType>(left, right, operationType);
11383af6ab5fSopenharmony_ci    }
11393af6ab5fSopenharmony_ci
11403af6ab5fSopenharmony_ci    return HandleBitWiseArithmetic<IntType>(left, right, operationType);
11413af6ab5fSopenharmony_ci}
11423af6ab5fSopenharmony_ci
11433af6ab5fSopenharmony_civoid ETSChecker::FlagExpressionWithUnboxing(Type *type, Type *unboxedType, ir::Expression *typeExpression)
11443af6ab5fSopenharmony_ci{
11453af6ab5fSopenharmony_ci    if (type->IsETSObjectType() && (unboxedType != nullptr)) {
11463af6ab5fSopenharmony_ci        typeExpression->AddBoxingUnboxingFlags(GetUnboxingFlag(unboxedType));
11473af6ab5fSopenharmony_ci    }
11483af6ab5fSopenharmony_ci}
11493af6ab5fSopenharmony_ci
11503af6ab5fSopenharmony_ci}  // namespace ark::es2panda::checker
1151