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