1/* 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "arithmetic.h" 17 18namespace ark::es2panda::checker { 19 20static inline void RepairTypeErrorsInOperands(Type **left, Type **right) 21{ 22 if (IsTypeError(*left)) { 23 *left = *right; 24 } 25 if (IsTypeError(*right)) { 26 *right = *left; 27 } 28} 29 30static inline void RepairTypeErrorWithDefault(Type **type, Type *dflt) 31{ 32 if (IsTypeError(*type)) { 33 *type = dflt; 34 } 35} 36 37Type *ETSChecker::NegateNumericType(Type *type, ir::Expression *node) 38{ 39 ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)); 40 41 TypeFlag typeKind = ETSType(type); 42 Type *result = nullptr; 43 44 switch (typeKind) { 45 case TypeFlag::BYTE: { 46 result = CreateByteType(-(type->AsByteType()->GetValue())); 47 break; 48 } 49 case TypeFlag::CHAR: { 50 result = CreateCharType(-(type->AsCharType()->GetValue())); 51 break; 52 } 53 case TypeFlag::SHORT: { 54 result = CreateShortType(-(type->AsShortType()->GetValue())); 55 break; 56 } 57 case TypeFlag::INT: { 58 result = CreateIntType(-(type->AsIntType()->GetValue())); 59 break; 60 } 61 case TypeFlag::LONG: { 62 result = CreateLongType(-(type->AsLongType()->GetValue())); 63 break; 64 } 65 case TypeFlag::FLOAT: { 66 result = CreateFloatType(-(type->AsFloatType()->GetValue())); 67 break; 68 } 69 case TypeFlag::DOUBLE: { 70 result = CreateDoubleType(-(type->AsDoubleType()->GetValue())); 71 break; 72 } 73 default: { 74 UNREACHABLE(); 75 } 76 } 77 78 node->SetTsType(result); 79 return result; 80} 81 82Type *ETSChecker::BitwiseNegateNumericType(Type *type, ir::Expression *node) 83{ 84 ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_INTEGRAL)); 85 86 TypeFlag typeKind = ETSType(type); 87 88 Type *result = nullptr; 89 90 switch (typeKind) { 91 case TypeFlag::BYTE: { 92 result = CreateByteType(static_cast<int8_t>(~static_cast<uint8_t>(type->AsByteType()->GetValue()))); 93 break; 94 } 95 case TypeFlag::CHAR: { 96 result = CreateCharType(~(type->AsCharType()->GetValue())); 97 break; 98 } 99 case TypeFlag::SHORT: { 100 result = CreateShortType(static_cast<int16_t>(~static_cast<uint16_t>(type->AsShortType()->GetValue()))); 101 break; 102 } 103 case TypeFlag::INT: { 104 result = CreateIntType(static_cast<int32_t>(~static_cast<uint32_t>(type->AsIntType()->GetValue()))); 105 break; 106 } 107 case TypeFlag::LONG: { 108 result = CreateLongType(static_cast<int64_t>(~static_cast<uint64_t>(type->AsLongType()->GetValue()))); 109 break; 110 } 111 case TypeFlag::FLOAT: { 112 result = CreateIntType( 113 ~static_cast<uint32_t>(CastFloatToInt<FloatType::UType, int32_t>(type->AsFloatType()->GetValue()))); 114 break; 115 } 116 case TypeFlag::DOUBLE: { 117 result = CreateLongType( 118 ~static_cast<uint64_t>(CastFloatToInt<DoubleType::UType, int64_t>(type->AsDoubleType()->GetValue()))); 119 break; 120 } 121 default: { 122 UNREACHABLE(); 123 } 124 } 125 126 node->SetTsType(result); 127 return result; 128} 129 130Type *ETSChecker::HandleRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) 131{ 132 ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) && 133 right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)); 134 135 if (left->IsDoubleType() || right->IsDoubleType()) { 136 return PerformRelationOperationOnTypes<DoubleType>(left, right, operationType); 137 } 138 139 if (left->IsFloatType() || right->IsFloatType()) { 140 return PerformRelationOperationOnTypes<FloatType>(left, right, operationType); 141 } 142 143 if (left->IsLongType() || right->IsLongType()) { 144 return PerformRelationOperationOnTypes<LongType>(left, right, operationType); 145 } 146 147 return PerformRelationOperationOnTypes<IntType>(left, right, operationType); 148} 149 150bool ETSChecker::CheckBinaryOperatorForBigInt(Type *left, Type *right, lexer::TokenType op) 151{ 152 if ((left == nullptr) || (right == nullptr)) { 153 return false; 154 } 155 156 if (!left->IsETSBigIntType()) { 157 return false; 158 } 159 160 if (!right->IsETSBigIntType()) { 161 return false; 162 } 163 164 switch (op) { 165 case lexer::TokenType::PUNCTUATOR_EQUAL: 166 case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: 167 case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: 168 case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: 169 case lexer::TokenType::KEYW_INSTANCEOF: 170 // This is handled in the main CheckBinaryOperator function 171 return false; 172 default: 173 break; 174 } 175 176 return true; 177} 178 179bool ETSChecker::CheckBinaryPlusMultDivOperandsForUnionType(const Type *leftType, const Type *rightType, 180 const ir::Expression *left, const ir::Expression *right) 181{ 182 std::stringstream ss; 183 if (leftType->IsETSUnionType()) { 184 leftType->AsETSUnionType()->ToString(ss, false); 185 LogTypeError("Bad operand type: multiple types left in the normalized union type (" + ss.str() + 186 "). Unions are not allowed in binary expressions except equality.", 187 left->Start()); 188 return false; 189 } 190 if (rightType->IsETSUnionType()) { 191 rightType->AsETSUnionType()->ToString(ss, false); 192 LogTypeError("Bad operand type: multiple types left in the normalized union type (" + ss.str() + 193 "). Unions are not allowed in binary expressions except equality.", 194 right->Start()); 195 return false; 196 } 197 return true; 198} 199 200checker::Type *ETSChecker::CheckBinaryOperatorMulDivMod( 201 std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op, bool isEqualOp, 202 std::tuple<checker::Type *, checker::Type *, Type *, Type *> types) 203{ 204 auto [left, right, operationType, pos] = op; 205 auto [leftType, rightType, unboxedL, unboxedR] = types; 206 207 // Try to handle errors on a lower level 208 RepairTypeErrorsInOperands(&leftType, &rightType); 209 RepairTypeErrorsInOperands(&unboxedL, &unboxedR); 210 if (leftType->IsTypeError()) { // both are errors 211 return GlobalTypeError(); 212 } 213 214 checker::Type *tsType {}; 215 auto [promotedType, bothConst] = 216 ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC, !isEqualOp); 217 218 FlagExpressionWithUnboxing(leftType, unboxedL, left); 219 FlagExpressionWithUnboxing(rightType, unboxedR, right); 220 221 if (!CheckBinaryPlusMultDivOperandsForUnionType(leftType, rightType, left, right)) { 222 return GlobalTypeError(); 223 } 224 225 if (promotedType == nullptr && !bothConst) { 226 LogTypeError("Bad operand type, the types of the operands must be numeric type.", pos); 227 return GlobalTypeError(); 228 } 229 230 if (bothConst) { 231 tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); 232 } 233 234 tsType = (tsType != nullptr) ? tsType : promotedType; 235 return tsType; 236} 237 238checker::Type *ETSChecker::CheckBinaryOperatorPlusForEnums(const checker::Type *const leftType, 239 const checker::Type *const rightType) 240{ 241 if (leftType->HasTypeFlag(TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) && 242 rightType->HasTypeFlag(TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) { 243 if (leftType->IsETSIntEnumType() && rightType->IsETSIntEnumType()) { 244 return GlobalIntType(); 245 } 246 if (leftType->IsFloatType() || rightType->IsFloatType()) { 247 return GlobalFloatType(); 248 } 249 if (leftType->IsLongType() || rightType->IsLongType()) { 250 return GlobalLongType(); 251 } 252 return GlobalIntType(); 253 } 254 if ((leftType->IsETSStringEnumType() && (rightType->IsETSStringType() || rightType->IsETSStringEnumType())) || 255 (rightType->IsETSStringEnumType() && (leftType->IsETSStringType() || leftType->IsETSStringEnumType()))) { 256 return GlobalETSStringLiteralType(); 257 } 258 return nullptr; 259} 260 261checker::Type *ETSChecker::CheckBinaryOperatorPlus( 262 std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op, bool isEqualOp, 263 std::tuple<checker::Type *, checker::Type *, Type *, Type *> types) 264{ 265 auto [left, right, operationType, pos] = op; 266 auto [leftType, rightType, unboxedL, unboxedR] = types; 267 268 // Try to handle errors on a lower level 269 RepairTypeErrorsInOperands(&leftType, &rightType); 270 RepairTypeErrorsInOperands(&unboxedL, &unboxedR); 271 if (leftType->IsTypeError()) { // both are errors 272 return GlobalTypeError(); 273 } 274 275 if (leftType->IsETSStringType() || rightType->IsETSStringType()) { 276 if (operationType == lexer::TokenType::PUNCTUATOR_MINUS || 277 operationType == lexer::TokenType::PUNCTUATOR_MINUS_EQUAL) { 278 LogTypeError("Bad operand type, the types of the operands must be numeric type.", pos); 279 return GlobalTypeError(); 280 } 281 282 return HandleStringConcatenation(leftType, rightType); 283 } 284 285 if (!CheckBinaryPlusMultDivOperandsForUnionType(leftType, rightType, left, right)) { 286 return GlobalTypeError(); 287 } 288 289 auto [promotedType, bothConst] = 290 ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC, !isEqualOp); 291 292 FlagExpressionWithUnboxing(leftType, unboxedL, left); 293 FlagExpressionWithUnboxing(rightType, unboxedR, right); 294 295 if (promotedType == nullptr && !bothConst) { 296 auto type = CheckBinaryOperatorPlusForEnums(leftType, rightType); 297 if (type != nullptr) { 298 return type; 299 } 300 LogTypeError("Bad operand type, the types of the operands must be numeric type, enum or String.", pos); 301 return GlobalTypeError(); 302 } 303 304 if (bothConst) { 305 return HandleArithmeticOperationOnTypes(leftType, rightType, operationType); 306 } 307 308 return promotedType; 309} 310 311checker::Type *ETSChecker::CheckBinaryOperatorShift( 312 std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op, bool isEqualOp, 313 std::tuple<checker::Type *, checker::Type *, Type *, Type *> types) 314{ 315 auto [left, right, operationType, pos] = op; 316 auto [leftType, rightType, unboxedL, unboxedR] = types; 317 318 RepairTypeErrorWithDefault(&leftType, GlobalIntType()); 319 RepairTypeErrorWithDefault(&rightType, GlobalIntType()); 320 RepairTypeErrorWithDefault(&unboxedL, GlobalIntType()); 321 RepairTypeErrorWithDefault(&unboxedR, GlobalIntType()); 322 323 if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) { 324 LogTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos); 325 return GlobalTypeError(); 326 } 327 328 auto promotedLeftType = ApplyUnaryOperatorPromotion(unboxedL, false, !isEqualOp); 329 auto promotedRightType = ApplyUnaryOperatorPromotion(unboxedR, false, !isEqualOp); 330 331 FlagExpressionWithUnboxing(leftType, unboxedL, left); 332 FlagExpressionWithUnboxing(rightType, unboxedR, right); 333 334 if (promotedLeftType == nullptr || !promotedLeftType->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) || 335 promotedRightType == nullptr || 336 !promotedRightType->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) { 337 LogTypeError("Bad operand type, the types of the operands must be numeric type.", pos); 338 return GlobalTypeError(); 339 } 340 341 if (promotedLeftType->HasTypeFlag(TypeFlag::CONSTANT) && promotedRightType->HasTypeFlag(TypeFlag::CONSTANT)) { 342 return HandleBitwiseOperationOnTypes(promotedLeftType, promotedRightType, operationType); 343 } 344 345 switch (ETSType(promotedLeftType)) { 346 case TypeFlag::BYTE: { 347 return GlobalByteType(); 348 } 349 case TypeFlag::SHORT: { 350 return GlobalShortType(); 351 } 352 case TypeFlag::CHAR: { 353 return GlobalCharType(); 354 } 355 case TypeFlag::INT: 356 case TypeFlag::FLOAT: { 357 return GlobalIntType(); 358 } 359 case TypeFlag::LONG: 360 case TypeFlag::DOUBLE: { 361 return GlobalLongType(); 362 } 363 default: { 364 UNREACHABLE(); 365 } 366 } 367 return nullptr; 368} 369 370checker::Type *ETSChecker::CheckBinaryOperatorBitwise( 371 std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op, bool isEqualOp, 372 std::tuple<checker::Type *, checker::Type *, Type *, Type *> types) 373{ 374 auto [left, right, operationType, pos] = op; 375 auto [leftType, rightType, unboxedL, unboxedR] = types; 376 377 RepairTypeErrorsInOperands(&leftType, &rightType); 378 RepairTypeErrorsInOperands(&unboxedL, &unboxedR); 379 if (leftType->IsTypeError()) { // both are errors 380 return GlobalTypeError(); 381 } 382 383 if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) { 384 LogTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos); 385 return GlobalTypeError(); 386 } 387 388 if (unboxedL != nullptr && unboxedL->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) && unboxedR != nullptr && 389 unboxedR->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN)) { 390 FlagExpressionWithUnboxing(leftType, unboxedL, left); 391 FlagExpressionWithUnboxing(rightType, unboxedR, right); 392 return HandleBooleanLogicalOperators(unboxedL, unboxedR, operationType); 393 } 394 395 auto [promotedType, bothConst] = 396 ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC, !isEqualOp); 397 398 FlagExpressionWithUnboxing(leftType, unboxedL, left); 399 FlagExpressionWithUnboxing(rightType, unboxedR, right); 400 401 if (promotedType == nullptr && !bothConst) { 402 LogTypeError("Bad operand type, the types of the operands must be numeric type.", pos); 403 return GlobalTypeError(); 404 } 405 406 if (bothConst) { 407 return HandleBitwiseOperationOnTypes(leftType, rightType, operationType); 408 } 409 410 return SelectGlobalIntegerTypeForNumeric(promotedType); 411} 412 413checker::Type *ETSChecker::CheckBinaryOperatorLogical(ir::Expression *left, ir::Expression *right, ir::Expression *expr, 414 lexer::SourcePosition pos, checker::Type *leftType, 415 checker::Type *rightType, Type *unboxedL, Type *unboxedR) 416{ 417 RepairTypeErrorsInOperands(&leftType, &rightType); 418 RepairTypeErrorsInOperands(&unboxedL, &unboxedR); 419 if (leftType->IsTypeError()) { // both are errors 420 return GlobalTypeError(); 421 } 422 423 if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) { 424 LogTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos); 425 return GlobalTypeError(); 426 } 427 428 if (unboxedL == nullptr || !unboxedL->IsConditionalExprType() || unboxedR == nullptr || 429 !unboxedR->IsConditionalExprType()) { 430 LogTypeError("Bad operand type, the types of the operands must be of possible condition type.", pos); 431 return GlobalTypeError(); 432 } 433 434 if (unboxedL->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { 435 FlagExpressionWithUnboxing(leftType, unboxedL, left); 436 } 437 438 if (unboxedR->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { 439 FlagExpressionWithUnboxing(rightType, unboxedR, right); 440 } 441 442 if (expr->IsBinaryExpression()) { 443 return HandleBooleanLogicalOperatorsExtended(unboxedL, unboxedR, expr->AsBinaryExpression()); 444 } 445 446 UNREACHABLE(); 447} 448 449void ETSChecker::LogOperatorCannotBeApplied(lexer::TokenType operationType, checker::Type *const leftType, 450 checker::Type *const rightType, lexer::SourcePosition pos) 451{ 452 LogTypeError({"Operator '", operationType, "' cannot be applied to types '", leftType, "' and '", rightType, "'."}, 453 pos); 454} 455 456bool ETSChecker::CheckValidEqualReferenceType(checker::Type *const leftType, checker::Type *const rightType) 457{ 458 auto isGlobalObjectType {[](checker::Type *const type) -> bool { 459 return type->IsETSObjectType() && type->AsETSObjectType()->IsGlobalETSObjectType(); 460 }}; 461 462 // Equality expression is always allowed for Object, undefined and null 463 if (isGlobalObjectType(leftType) || isGlobalObjectType(rightType) || leftType->IsETSUndefinedType() || 464 rightType->IsETSUndefinedType() || leftType->IsETSNullType() || rightType->IsETSNullType()) { 465 return true; 466 } 467 468 // NOTE (mxlgv): Skip for unions. Required implementation of the specification section: 469 // 7.25.6 Reference Equality Based on Actual Type (Union Equality Operators) 470 if (leftType->IsETSUnionType()) { 471 return leftType->AsETSUnionType()->IsOverlapWith(Relation(), rightType); 472 } 473 if (rightType->IsETSUnionType()) { 474 return rightType->AsETSUnionType()->IsOverlapWith(Relation(), leftType); 475 } 476 477 // NOTE (mxlgv): Skip for generic. Required implementation of the specification section: 478 // 7.25.6 Reference Equality Based on Actual Type (Type Parameter Equality Operators) 479 if (leftType->HasTypeFlag(TypeFlag::GENERIC) || rightType->HasTypeFlag(TypeFlag::GENERIC)) { 480 return true; 481 } 482 483 // Equality expression can only be applied to String and String, and BigInt and BigInt 484 if (leftType->IsETSStringType() || rightType->IsETSStringType() || leftType->IsETSBigIntType() || 485 rightType->IsETSBigIntType()) { 486 auto *const nonConstLhs = GetNonConstantType(leftType); 487 auto *const nonConstRhs = GetNonConstantType(rightType); 488 if (!Relation()->IsIdenticalTo(nonConstLhs, nonConstRhs) && 489 !Relation()->IsIdenticalTo(nonConstRhs, nonConstLhs)) { 490 return false; 491 } 492 } 493 494 return true; 495} 496 497std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorStrictEqual(ir::Expression *left, 498 lexer::TokenType operationType, 499 lexer::SourcePosition pos, 500 checker::Type *leftType, checker::Type *rightType) 501{ 502 RepairTypeErrorsInOperands(&leftType, &rightType); 503 if (leftType->IsTypeError()) { // both are errors 504 // We still know that operation result should be boolean, so recover. 505 return {GlobalETSBooleanType(), GlobalETSObjectType()}; 506 } 507 508 checker::Type *tsType {}; 509 if (!IsReferenceType(leftType) || !IsReferenceType(rightType)) { 510 LogTypeError("Both operands have to be reference types", pos); 511 return {GlobalETSBooleanType(), GlobalETSObjectType()}; 512 } 513 514 Relation()->SetNode(left); 515 if (!CheckValidEqualReferenceType(leftType, rightType)) { 516 LogOperatorCannotBeApplied(operationType, leftType, rightType, pos); 517 return {GlobalETSBooleanType(), GlobalETSObjectType()}; 518 } 519 520 if (!Relation()->IsCastableTo(leftType, rightType) && !Relation()->IsCastableTo(rightType, leftType)) { 521 LogOperatorCannotBeApplied(operationType, leftType, rightType, pos); 522 return {GlobalETSBooleanType(), GlobalETSObjectType()}; 523 } 524 525 tsType = GlobalETSBooleanType(); 526 if (rightType->IsETSDynamicType() && leftType->IsETSDynamicType()) { 527 return {tsType, GlobalBuiltinJSValueType()}; 528 } 529 530 return {tsType, GlobalETSObjectType()}; 531} 532 533std::optional<std::tuple<Type *, Type *>> ETSChecker::CheckBinaryOperatorEqualError(checker::Type *const leftType, 534 checker::Type *const rightType, 535 checker::Type *tsType, 536 lexer::SourcePosition pos) 537{ 538 if (leftType->IsETSIntEnumType() && rightType->IsETSIntEnumType()) { 539 if (!leftType->AsETSIntEnumType()->IsSameEnumType(rightType->AsETSIntEnumType())) { 540 // We still know that operation result should be boolean, so recover. 541 LogTypeError("Bad operand type, the types of the operands must be the same enum type.", pos); 542 return {{GlobalETSBooleanType(), leftType}}; 543 } 544 545 tsType = GlobalETSBooleanType(); 546 return std::make_tuple(tsType, leftType); 547 } 548 549 if (leftType->IsETSStringEnumType() && rightType->IsETSStringEnumType()) { 550 if (!leftType->AsETSStringEnumType()->IsSameEnumType(rightType->AsETSStringEnumType())) { 551 LogTypeError("Bad operand type, the types of the operands must be the same enum type.", pos); 552 return {{GlobalETSBooleanType(), leftType}}; 553 } 554 555 tsType = GlobalETSBooleanType(); 556 return std::make_tuple(tsType, leftType); 557 } 558 return std::nullopt; 559} 560 561std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorEqual(ir::Expression *left, ir::Expression *right, 562 lexer::TokenType operationType, 563 lexer::SourcePosition pos, checker::Type *leftType, 564 checker::Type *rightType, Type *unboxedL, 565 Type *unboxedR) 566{ 567 RepairTypeErrorsInOperands(&leftType, &rightType); 568 RepairTypeErrorsInOperands(&unboxedL, &unboxedR); 569 if (leftType->IsTypeError()) { // both are errors 570 return {GlobalETSBooleanType(), GlobalTypeError()}; 571 } 572 573 checker::Type *tsType {}; 574 575 auto checkError = CheckBinaryOperatorEqualError(leftType, rightType, tsType, pos); 576 if (checkError.has_value()) { 577 return checkError.value(); 578 } 579 if (leftType->IsETSDynamicType() || rightType->IsETSDynamicType()) { 580 return CheckBinaryOperatorEqualDynamic(left, right, pos); 581 } 582 583 if (IsReferenceType(leftType) && IsReferenceType(rightType)) { 584 Relation()->SetNode(left); 585 if (!CheckValidEqualReferenceType(leftType, rightType)) { 586 LogOperatorCannotBeApplied(operationType, leftType, rightType, pos); 587 return {GlobalETSBooleanType(), leftType}; 588 } 589 590 tsType = GlobalETSBooleanType(); 591 return {tsType, CreateETSUnionType({leftType, rightType})}; 592 } 593 594 if (unboxedL != nullptr && unboxedL->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) && unboxedR != nullptr && 595 unboxedR->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN)) { 596 if (unboxedL->HasTypeFlag(checker::TypeFlag::CONSTANT) && unboxedR->HasTypeFlag(checker::TypeFlag::CONSTANT)) { 597 bool res = unboxedL->AsETSBooleanType()->GetValue() == unboxedR->AsETSBooleanType()->GetValue(); 598 599 tsType = CreateETSBooleanType(operationType == lexer::TokenType::PUNCTUATOR_EQUAL ? res : !res); 600 return {tsType, tsType}; 601 } 602 603 FlagExpressionWithUnboxing(leftType, unboxedL, left); 604 FlagExpressionWithUnboxing(rightType, unboxedR, right); 605 606 tsType = GlobalETSBooleanType(); 607 return {tsType, tsType}; 608 } 609 610 // Temporary workaround before == and === refactoring 611 if ((rightType->IsETSNullType() && leftType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) || 612 (leftType->IsETSNullType() && rightType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE))) { 613 return {GlobalETSBooleanType(), CreateETSUnionType({leftType, rightType})}; 614 } 615 616 return {nullptr, nullptr}; 617} 618 619std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorEqualDynamic(ir::Expression *left, ir::Expression *right, 620 lexer::SourcePosition pos) 621{ 622 // NOTE: vpukhov. enforce intrinsic call in any case? 623 // canonicalize 624 auto *const dynExp = left->TsType()->IsETSDynamicType() ? left : right; 625 auto *const otherExp = dynExp == left ? right : left; 626 627 if (otherExp->TsType()->IsETSDynamicType()) { 628 return {GlobalETSBooleanType(), GlobalBuiltinJSValueType()}; 629 } 630 if (dynExp->TsType()->AsETSDynamicType()->IsConvertible(otherExp->TsType())) { 631 // NOTE: vpukhov. boxing flags are not set in dynamic values 632 return {GlobalETSBooleanType(), otherExp->TsType()}; 633 } 634 if (IsReferenceType(otherExp->TsType())) { 635 // have to prevent casting dyn_exp via ApplyCast without nullish flag 636 return {GlobalETSBooleanType(), GlobalETSNullishObjectType()}; 637 } 638 LogTypeError("Unimplemented case in dynamic type comparison.", pos); 639 return {GlobalETSBooleanType(), GlobalETSNullishObjectType()}; 640} 641 642// Satisfying the Chinese checker 643static bool NonNumericTypesAreAppropriateForComparison(Type *leftType, Type *rightType) 644{ 645 return (rightType->IsETSStringType() && leftType->IsETSStringType()) || 646 (((leftType->IsETSIntEnumType() && rightType->IsETSIntEnumType()) || 647 (leftType->IsETSStringEnumType() && rightType->IsETSStringEnumType())) && 648 leftType->AsETSEnumType()->IsSameEnumType(rightType->AsETSEnumType())); 649} 650 651std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorLessGreater(ir::Expression *left, ir::Expression *right, 652 lexer::TokenType operationType, 653 lexer::SourcePosition pos, bool isEqualOp, 654 checker::Type *leftType, checker::Type *rightType, 655 Type *unboxedL, Type *unboxedR) 656{ 657 RepairTypeErrorsInOperands(&leftType, &rightType); 658 RepairTypeErrorsInOperands(&unboxedL, &unboxedR); 659 if (leftType->IsTypeError()) { // both are errors 660 return {GlobalETSBooleanType(), GlobalTypeError()}; 661 } 662 663 if ((leftType->IsETSUnionType() || rightType->IsETSUnionType()) && 664 operationType != lexer::TokenType::PUNCTUATOR_EQUAL && 665 operationType != lexer::TokenType::PUNCTUATOR_NOT_EQUAL) { 666 LogTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos); 667 return {GlobalETSBooleanType(), leftType}; 668 } 669 670 checker::Type *tsType {}; 671 auto [promotedType, bothConst] = 672 ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_PRIMITIVE, !isEqualOp); 673 674 FlagExpressionWithUnboxing(leftType, unboxedL, left); 675 FlagExpressionWithUnboxing(rightType, unboxedR, right); 676 677 if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) { 678 return {GlobalETSBooleanType(), CreateETSUnionType({MaybeBoxExpression(left), MaybeBoxExpression(right)})}; 679 } 680 681 if ((unboxedL != nullptr) && (unboxedR != nullptr) && 682 (unboxedL->IsETSBooleanType() != unboxedR->IsETSBooleanType())) { 683 LogOperatorCannotBeApplied(operationType, leftType, rightType, pos); 684 return {GlobalETSBooleanType(), leftType}; 685 } 686 687 if (promotedType == nullptr && !bothConst) { 688 if (NonNumericTypesAreAppropriateForComparison(leftType, rightType)) { 689 return {GlobalETSBooleanType(), GlobalETSBooleanType()}; 690 } 691 if (((leftType->IsETSIntEnumType() && rightType->IsETSIntEnumType()) || 692 (leftType->IsETSStringEnumType() && rightType->IsETSStringEnumType())) && 693 leftType->AsETSEnumType()->IsSameEnumType(rightType->AsETSEnumType())) { 694 return {GlobalETSBooleanType(), GlobalETSBooleanType()}; 695 } 696 697 LogTypeError("Bad operand type, the types of the operands must be numeric, same enumeration, or boolean type.", 698 pos); 699 return {GlobalETSBooleanType(), GlobalETSBooleanType()}; 700 } 701 702 if (bothConst) { 703 tsType = HandleRelationOperationOnTypes(leftType, rightType, operationType); 704 return {tsType, tsType}; 705 } 706 707 tsType = GlobalETSBooleanType(); 708 auto *opType = promotedType; 709 return {tsType, opType}; 710} 711 712std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorInstanceOf(lexer::SourcePosition pos, checker::Type *leftType, 713 checker::Type *rightType) 714{ 715 RepairTypeErrorsInOperands(&leftType, &rightType); 716 if (leftType->IsTypeError()) { // both are errors 717 return {GlobalETSBooleanType(), GlobalTypeError()}; 718 } 719 720 checker::Type *tsType {}; 721 if (!IsReferenceType(leftType) || (!IsReferenceType(rightType) && !rightType->IsETSEnumType())) { 722 LogTypeError("Bad operand type, the types of the operands must be same type.", pos); 723 return {GlobalETSBooleanType(), leftType}; 724 } 725 726 if (rightType->IsETSDynamicType() && !rightType->AsETSDynamicType()->HasDecl()) { 727 LogTypeError("Right-hand side of instanceof expression must represent a type.", pos); 728 return {GlobalETSBooleanType(), leftType}; 729 } 730 731 tsType = GlobalETSBooleanType(); 732 checker::Type *opType = rightType->IsETSDynamicType() ? GlobalBuiltinJSValueType() : GlobalETSObjectType(); 733 ComputeApparentType(rightType); 734 RemoveStatus(checker::CheckerStatus::IN_INSTANCEOF_CONTEXT); 735 736 return {tsType, opType}; 737} 738 739bool ETSChecker::AdjustNumberLiteralType(ir::NumberLiteral *const literal, Type *literalType, Type *const otherType) 740{ 741 if (otherType->IsETSObjectType()) { 742 auto *const objectType = otherType->AsETSObjectType(); 743 if (objectType->HasObjectFlag(ETSObjectFlags::BUILTIN_TYPE) && !objectType->IsETSStringType()) { 744 literal->RemoveBoxingUnboxingFlags(GetBoxingFlag(literalType)); 745 literalType = ETSBuiltinTypeAsPrimitiveType(objectType); 746 literal->SetTsType(literalType); 747 literal->AddBoxingUnboxingFlags(GetBoxingFlag(literalType)); 748 return true; 749 } 750 } 751 return false; 752} 753 754Type *ETSChecker::CheckBinaryOperatorNullishCoalescing(ir::Expression *left, ir::Expression *right, 755 lexer::SourcePosition pos) 756{ 757 auto *leftType = left->TsType(); 758 if (!IsReferenceType(leftType) && !leftType->IsETSEnumType()) { 759 LogTypeError("Left-hand side of nullish-coalescing expression must be a reference or enum type.", pos); 760 return leftType; 761 } 762 763 auto *rightType = right->TsType(); 764 765 if (leftType->IsETSEnumType()) { 766 left->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::BOX_TO_ENUM); 767 leftType = leftType->AsETSEnumType()->GetDecl()->BoxedClass()->TsType(); 768 } else { 769 leftType = GetNonNullishType(leftType); 770 } 771 772 if (rightType->IsETSEnumType()) { 773 right->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::BOX_TO_ENUM); 774 rightType = rightType->AsETSEnumType()->GetDecl()->BoxedClass()->TsType(); 775 } else { 776 rightType = MaybeBoxExpression(right); 777 } 778 779 if (IsTypeIdenticalTo(leftType, rightType)) { 780 return leftType; 781 } 782 783 // If possible and required update number literal type to the proper value (identical to left-side type) 784 if (right->IsNumberLiteral() && AdjustNumberLiteralType(right->AsNumberLiteral(), rightType, leftType)) { 785 return leftType; 786 } 787 788 return CreateETSUnionType({leftType, rightType}); 789} 790 791using CheckBinaryFunction = std::function<checker::Type *( 792 ETSChecker *, std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op, 793 bool isEqualOp, std::tuple<checker::Type *, checker::Type *, Type *, Type *> types)>; 794 795std::map<lexer::TokenType, CheckBinaryFunction> &GetCheckMap() 796{ 797 static std::map<lexer::TokenType, CheckBinaryFunction> checkMap = { 798 {lexer::TokenType::PUNCTUATOR_MULTIPLY, &ETSChecker::CheckBinaryOperatorMulDivMod}, 799 {lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod}, 800 {lexer::TokenType::PUNCTUATOR_DIVIDE, &ETSChecker::CheckBinaryOperatorMulDivMod}, 801 {lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod}, 802 {lexer::TokenType::PUNCTUATOR_MOD, &ETSChecker::CheckBinaryOperatorMulDivMod}, 803 {lexer::TokenType::PUNCTUATOR_MOD_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod}, 804 805 {lexer::TokenType::PUNCTUATOR_MINUS, &ETSChecker::CheckBinaryOperatorPlus}, 806 {lexer::TokenType::PUNCTUATOR_MINUS_EQUAL, &ETSChecker::CheckBinaryOperatorPlus}, 807 {lexer::TokenType::PUNCTUATOR_PLUS, &ETSChecker::CheckBinaryOperatorPlus}, 808 {lexer::TokenType::PUNCTUATOR_PLUS_EQUAL, &ETSChecker::CheckBinaryOperatorPlus}, 809 810 {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT, &ETSChecker::CheckBinaryOperatorShift}, 811 {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift}, 812 {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT, &ETSChecker::CheckBinaryOperatorShift}, 813 {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift}, 814 {lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT, &ETSChecker::CheckBinaryOperatorShift}, 815 {lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift}, 816 817 {lexer::TokenType::PUNCTUATOR_BITWISE_OR, &ETSChecker::CheckBinaryOperatorBitwise}, 818 {lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise}, 819 {lexer::TokenType::PUNCTUATOR_BITWISE_AND, &ETSChecker::CheckBinaryOperatorBitwise}, 820 {lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise}, 821 {lexer::TokenType::PUNCTUATOR_BITWISE_XOR, &ETSChecker::CheckBinaryOperatorBitwise}, 822 {lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise}, 823 }; 824 825 return checkMap; 826} 827 828struct BinaryOperatorParams { 829 ir::Expression *left; 830 ir::Expression *right; 831 ir::Expression *expr; 832 lexer::TokenType operationType; 833 lexer::SourcePosition pos; 834 bool isEqualOp; 835}; 836 837struct TypeParams { 838 checker::Type *leftType; 839 checker::Type *rightType; 840 Type *unboxedL; 841 Type *unboxedR; 842}; 843 844static std::tuple<Type *, Type *> CheckBinaryOperatorHelper(ETSChecker *checker, 845 const BinaryOperatorParams &binaryParams, 846 const TypeParams &typeParams) 847{ 848 ir::Expression *left = binaryParams.left; 849 ir::Expression *right = binaryParams.right; 850 lexer::SourcePosition pos = binaryParams.pos; 851 checker::Type *const leftType = typeParams.leftType; 852 checker::Type *const rightType = typeParams.rightType; 853 checker::Type *tsType {}; 854 switch (binaryParams.operationType) { 855 case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: 856 case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { 857 tsType = checker->CheckBinaryOperatorLogical(left, right, binaryParams.expr, pos, leftType, rightType, 858 typeParams.unboxedL, typeParams.unboxedR); 859 break; 860 } 861 case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: 862 case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { 863 return checker->CheckBinaryOperatorStrictEqual(left, binaryParams.operationType, pos, leftType, rightType); 864 } 865 case lexer::TokenType::PUNCTUATOR_EQUAL: 866 case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { 867 std::tuple<Type *, Type *> res = 868 checker->CheckBinaryOperatorEqual(left, right, binaryParams.operationType, pos, leftType, rightType, 869 typeParams.unboxedL, typeParams.unboxedR); 870 if (!(std::get<0>(res) == nullptr && std::get<1>(res) == nullptr)) { 871 return res; 872 } 873 [[fallthrough]]; 874 } 875 case lexer::TokenType::PUNCTUATOR_LESS_THAN: 876 case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: 877 case lexer::TokenType::PUNCTUATOR_GREATER_THAN: 878 case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { 879 return checker->CheckBinaryOperatorLessGreater(left, right, binaryParams.operationType, pos, 880 binaryParams.isEqualOp, leftType, rightType, 881 typeParams.unboxedL, typeParams.unboxedR); 882 } 883 case lexer::TokenType::KEYW_INSTANCEOF: { 884 return checker->CheckBinaryOperatorInstanceOf(pos, leftType, rightType); 885 } 886 case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: { 887 tsType = checker->CheckBinaryOperatorNullishCoalescing(left, right, pos); 888 break; 889 } 890 default: { 891 UNREACHABLE(); 892 break; 893 } 894 } 895 896 return {tsType, tsType}; 897} 898 899namespace { 900bool IsStringEnum(const ir::Expression *expr) 901{ 902 if (expr == nullptr) { 903 return false; 904 } 905 if (expr->TsTypeOrError()->IsTypeError()) { 906 return false; 907 } 908 909 auto type = expr->TsType(); 910 if (type == nullptr) { 911 return false; 912 } 913 914 return type->IsETSStringEnumType(); 915} 916 917bool IsIntEnum(const ir::Expression *expr) 918{ 919 if (expr == nullptr) { 920 return false; 921 } 922 if (expr->TsTypeOrError()->IsTypeError()) { 923 return false; 924 } 925 926 auto type = expr->TsType(); 927 if (type == nullptr) { 928 return false; 929 } 930 931 return type->IsETSIntEnumType(); 932} 933 934bool CheckNumericOperatorContext(ir::Expression *expression, lexer::TokenType op) 935{ 936 const bool isMultiplicative = op == lexer::TokenType::PUNCTUATOR_MULTIPLY || 937 op == lexer::TokenType::PUNCTUATOR_DIVIDE || op == lexer::TokenType::PUNCTUATOR_MOD; 938 const bool isAdditive = op == lexer::TokenType::PUNCTUATOR_PLUS || op == lexer::TokenType::PUNCTUATOR_MINUS; 939 const bool isShift = op == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT || 940 op == lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT || 941 op == lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT; 942 const bool isRelational = 943 op == lexer::TokenType::PUNCTUATOR_GREATER_THAN || op == lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL || 944 op == lexer::TokenType::PUNCTUATOR_LESS_THAN || op == lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL; 945 const bool isEquality = op == lexer::TokenType::PUNCTUATOR_EQUAL || op == lexer::TokenType::PUNCTUATOR_NOT_EQUAL; 946 const bool isBitwise = op == lexer::TokenType::PUNCTUATOR_BITWISE_AND || 947 op == lexer::TokenType::PUNCTUATOR_BITWISE_OR || 948 op == lexer::TokenType::PUNCTUATOR_BITWISE_XOR; 949 const bool isConditionalAndOr = 950 op == lexer::TokenType::PUNCTUATOR_LOGICAL_AND || op == lexer::TokenType::PUNCTUATOR_LOGICAL_OR; 951 952 if (IsIntEnum(expression)) { 953 if (isMultiplicative || isAdditive || isShift || isRelational || isEquality || isBitwise || 954 isConditionalAndOr) { 955 expression->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF); 956 } 957 return true; 958 } 959 return false; 960} 961 962void CheckStringOperatorContext(ir::Expression *expression, checker::Type *otherType, lexer::TokenType op) 963{ 964 if (IsStringEnum(expression) && (otherType->IsETSStringType() || otherType->IsETSStringEnumType())) { 965 if (op == lexer::TokenType::PUNCTUATOR_PLUS) { 966 expression->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF); 967 } 968 } 969} 970 971bool CheckRelationalOperatorsBetweenEnums(ir::Expression *left, ir::Expression *right, lexer::TokenType op) 972{ 973 const bool isRelational = 974 op == lexer::TokenType::PUNCTUATOR_GREATER_THAN || op == lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL || 975 op == lexer::TokenType::PUNCTUATOR_LESS_THAN || op == lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL; 976 const bool isEquality = op == lexer::TokenType::PUNCTUATOR_EQUAL || op == lexer::TokenType::PUNCTUATOR_NOT_EQUAL; 977 978 if (((IsStringEnum(left) && IsStringEnum(right)) || 979 (IsIntEnum(left) && IsIntEnum(right)))) { // NOTE(psiket) In case of int enums it has been already checked in 980 // the CheckNumericOperatorContext function 981 if (isRelational || isEquality) { 982 left->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF); 983 right->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF); 984 return true; 985 } 986 } 987 return false; 988} 989 990void CheckNeedToGenerateGetValueForBinaryExpression(ir::Expression *expression) 991{ 992 if (!expression->IsBinaryExpression()) { 993 return; 994 } 995 996 auto binaryExpression = expression->AsBinaryExpression(); 997 auto op = binaryExpression->OperatorType(); 998 auto leftExp = binaryExpression->Left(); 999 auto rightExp = binaryExpression->Right(); 1000 1001 // Numeric Operator Context 1002 auto leftIsIntEnum = CheckNumericOperatorContext(leftExp, op); 1003 auto rightIsIntEnum = CheckNumericOperatorContext(rightExp, op); 1004 if (leftIsIntEnum || rightIsIntEnum) { 1005 return; 1006 } 1007 1008 // String Operator Context 1009 CheckStringOperatorContext(leftExp, rightExp->TsTypeOrError(), op); 1010 CheckStringOperatorContext(rightExp, leftExp->TsTypeOrError(), op); 1011 1012 // Relational operators if both are enumeration Types 1013 if (CheckRelationalOperatorsBetweenEnums(leftExp, rightExp, op)) { 1014 return; 1015 } 1016} 1017} // namespace 1018 1019std::tuple<Type *, Type *> ETSChecker::CheckArithmeticOperations( 1020 ir::Expression *expr, std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op, 1021 bool isEqualOp, std::tuple<checker::Type *, checker::Type *, Type *, Type *> types) 1022{ 1023 auto [left, right, operationType, pos] = op; 1024 auto [leftType, rightType, unboxedL, unboxedR] = types; 1025 1026 if (leftType->IsETSUnionType()) { 1027 leftType = GetNonConstantType(leftType); 1028 } 1029 1030 if (rightType->IsETSUnionType()) { 1031 rightType = GetNonConstantType(rightType); 1032 } 1033 1034 auto checkMap = GetCheckMap(); 1035 if (checkMap.find(operationType) != checkMap.end()) { 1036 auto check = checkMap[operationType]; 1037 auto tsType = check(this, std::make_tuple(left, right, operationType, pos), isEqualOp, 1038 std::make_tuple(leftType, rightType, unboxedL, unboxedR)); 1039 return {tsType, tsType}; 1040 } 1041 1042 return CheckBinaryOperatorHelper(this, {left, right, expr, operationType, pos, isEqualOp}, 1043 {leftType, rightType, unboxedL, unboxedR}); 1044} 1045 1046std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperator(ir::Expression *left, ir::Expression *right, 1047 ir::Expression *expr, lexer::TokenType operationType, 1048 lexer::SourcePosition pos, bool forcePromotion) 1049{ 1050 checker::Type *leftType = left->Check(this); 1051 1052 if (leftType == nullptr) { 1053 LogTypeError("Unexpected type error in binary expression", left->Start()); 1054 auto rightType = right->Check(this); 1055 return {rightType, rightType}; 1056 } 1057 1058 if (operationType == lexer::TokenType::KEYW_INSTANCEOF) { 1059 AddStatus(checker::CheckerStatus::IN_INSTANCEOF_CONTEXT); 1060 } 1061 1062 Context().CheckTestSmartCastCondition(operationType); 1063 1064 checker::Type *rightType = right->Check(this); 1065 if (right->IsTypeNode()) { 1066 rightType = right->AsTypeNode()->GetType(this); 1067 } 1068 1069 if (rightType == nullptr) { 1070 LogTypeError("Unexpected type error in binary expression", pos); 1071 return {leftType, leftType}; 1072 } 1073 1074 CheckNeedToGenerateGetValueForBinaryExpression(expr); 1075 1076 const bool isLogicalExtendedOperator = (operationType == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) || 1077 (operationType == lexer::TokenType::PUNCTUATOR_LOGICAL_OR); 1078 Type *unboxedL = 1079 isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(leftType) : ETSBuiltinTypeAsPrimitiveType(leftType); 1080 Type *unboxedR = isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(rightType) 1081 : ETSBuiltinTypeAsPrimitiveType(rightType); 1082 1083 bool isEqualOp = (operationType > lexer::TokenType::PUNCTUATOR_SUBSTITUTION && 1084 operationType < lexer::TokenType::PUNCTUATOR_ARROW) && 1085 !forcePromotion; 1086 1087 if (CheckBinaryOperatorForBigInt(leftType, rightType, operationType)) { 1088 switch (operationType) { 1089 case lexer::TokenType::PUNCTUATOR_GREATER_THAN: 1090 case lexer::TokenType::PUNCTUATOR_LESS_THAN: 1091 case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: 1092 case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: 1093 return {GlobalETSBooleanType(), GlobalETSBooleanType()}; 1094 default: 1095 return {leftType, rightType}; 1096 } 1097 } 1098 1099 return CheckArithmeticOperations(expr, std::make_tuple(left, right, operationType, pos), isEqualOp, 1100 std::make_tuple(leftType, rightType, unboxedL, unboxedR)); 1101} 1102 1103Type *ETSChecker::HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) 1104{ 1105 ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) && 1106 right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)); 1107 1108 if (left->IsDoubleType() || right->IsDoubleType()) { 1109 return PerformArithmeticOperationOnTypes<DoubleType>(left, right, operationType); 1110 } 1111 1112 if (left->IsFloatType() || right->IsFloatType()) { 1113 return PerformArithmeticOperationOnTypes<FloatType>(left, right, operationType); 1114 } 1115 1116 if (left->IsLongType() || right->IsLongType()) { 1117 return PerformArithmeticOperationOnTypes<LongType>(left, right, operationType); 1118 } 1119 1120 return PerformArithmeticOperationOnTypes<IntType>(left, right, operationType); 1121} 1122 1123Type *ETSChecker::HandleBitwiseOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) 1124{ 1125 ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) && 1126 right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)); 1127 1128 if (left->IsDoubleType() || right->IsDoubleType()) { 1129 return HandleBitWiseArithmetic<DoubleType, LongType>(left, right, operationType); 1130 } 1131 1132 if (left->IsFloatType() || right->IsFloatType()) { 1133 return HandleBitWiseArithmetic<FloatType, IntType>(left, right, operationType); 1134 } 1135 1136 if (left->IsLongType() || right->IsLongType()) { 1137 return HandleBitWiseArithmetic<LongType>(left, right, operationType); 1138 } 1139 1140 return HandleBitWiseArithmetic<IntType>(left, right, operationType); 1141} 1142 1143void ETSChecker::FlagExpressionWithUnboxing(Type *type, Type *unboxedType, ir::Expression *typeExpression) 1144{ 1145 if (type->IsETSObjectType() && (unboxedType != nullptr)) { 1146 typeExpression->AddBoxingUnboxingFlags(GetUnboxingFlag(unboxedType)); 1147 } 1148} 1149 1150} // namespace ark::es2panda::checker 1151