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
18 namespace ark::es2panda::checker {
19
RepairTypeErrorsInOperands(Type ** left,Type ** right)20 static 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
RepairTypeErrorWithDefault(Type ** type,Type * dflt)30 static inline void RepairTypeErrorWithDefault(Type **type, Type *dflt)
31 {
32 if (IsTypeError(*type)) {
33 *type = dflt;
34 }
35 }
36
NegateNumericType(Type * type,ir::Expression * node)37 Type *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
BitwiseNegateNumericType(Type * type,ir::Expression * node)82 Type *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
HandleRelationOperationOnTypes(Type * left,Type * right,lexer::TokenType operationType)130 Type *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
CheckBinaryOperatorForBigInt(Type * left,Type * right,lexer::TokenType op)150 bool 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
CheckBinaryPlusMultDivOperandsForUnionType(const Type * leftType,const Type * rightType,const ir::Expression * left,const ir::Expression * right)179 bool 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
CheckBinaryOperatorMulDivMod(std::tuple<ir::Expression *,ir::Expression *,lexer::TokenType,lexer::SourcePosition> op,bool isEqualOp,std::tuple<checker::Type *,checker::Type *,Type *,Type * > types)200 checker::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
CheckBinaryOperatorPlusForEnums(const checker::Type * const leftType,const checker::Type * const rightType)238 checker::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
CheckBinaryOperatorPlus(std::tuple<ir::Expression *,ir::Expression *,lexer::TokenType,lexer::SourcePosition> op,bool isEqualOp,std::tuple<checker::Type *,checker::Type *,Type *,Type * > types)261 checker::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
CheckBinaryOperatorShift(std::tuple<ir::Expression *,ir::Expression *,lexer::TokenType,lexer::SourcePosition> op,bool isEqualOp,std::tuple<checker::Type *,checker::Type *,Type *,Type * > types)311 checker::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
CheckBinaryOperatorBitwise(std::tuple<ir::Expression *,ir::Expression *,lexer::TokenType,lexer::SourcePosition> op,bool isEqualOp,std::tuple<checker::Type *,checker::Type *,Type *,Type * > types)370 checker::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
CheckBinaryOperatorLogical(ir::Expression * left,ir::Expression * right,ir::Expression * expr,lexer::SourcePosition pos,checker::Type * leftType,checker::Type * rightType,Type * unboxedL,Type * unboxedR)413 checker::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
LogOperatorCannotBeApplied(lexer::TokenType operationType,checker::Type * const leftType,checker::Type * const rightType,lexer::SourcePosition pos)449 void 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
CheckValidEqualReferenceType(checker::Type * const leftType,checker::Type * const rightType)456 bool 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() || rightType->IsETSUnionType()) {
471 return true;
472 }
473
474 // NOTE (mxlgv): Skip for generic. Required implementation of the specification section:
475 // 7.25.6 Reference Equality Based on Actual Type (Type Parameter Equality Operators)
476 if (leftType->HasTypeFlag(TypeFlag::GENERIC) || rightType->HasTypeFlag(TypeFlag::GENERIC)) {
477 return true;
478 }
479
480 // Equality expression can only be applied to String and String, and BigInt and BigInt
481 if (leftType->IsETSStringType() || rightType->IsETSStringType() || leftType->IsETSBigIntType() ||
482 rightType->IsETSBigIntType()) {
483 if (!Relation()->IsIdenticalTo(leftType, rightType) && !Relation()->IsIdenticalTo(rightType, leftType)) {
484 return false;
485 }
486 }
487
488 return true;
489 }
490
CheckBinaryOperatorStrictEqual(ir::Expression * left,lexer::TokenType operationType,lexer::SourcePosition pos,checker::Type * leftType,checker::Type * rightType)491 std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorStrictEqual(ir::Expression *left,
492 lexer::TokenType operationType,
493 lexer::SourcePosition pos,
494 checker::Type *leftType, checker::Type *rightType)
495 {
496 RepairTypeErrorsInOperands(&leftType, &rightType);
497 if (leftType->IsTypeError()) { // both are errors
498 // We still know that operation result should be boolean, so recover.
499 return {GlobalETSBooleanType(), GlobalETSObjectType()};
500 }
501
502 checker::Type *tsType {};
503 if (!IsReferenceType(leftType) || !IsReferenceType(rightType)) {
504 LogTypeError("Both operands have to be reference types", pos);
505 return {GlobalETSBooleanType(), GlobalETSObjectType()};
506 }
507
508 Relation()->SetNode(left);
509 if (!CheckValidEqualReferenceType(leftType, rightType)) {
510 LogOperatorCannotBeApplied(operationType, leftType, rightType, pos);
511 return {GlobalETSBooleanType(), GlobalETSObjectType()};
512 }
513
514 if (!Relation()->IsCastableTo(leftType, rightType) && !Relation()->IsCastableTo(rightType, leftType)) {
515 LogOperatorCannotBeApplied(operationType, leftType, rightType, pos);
516 return {GlobalETSBooleanType(), GlobalETSObjectType()};
517 }
518
519 tsType = GlobalETSBooleanType();
520 if (rightType->IsETSDynamicType() && leftType->IsETSDynamicType()) {
521 return {tsType, GlobalBuiltinJSValueType()};
522 }
523
524 return {tsType, GlobalETSObjectType()};
525 }
526
CheckBinaryOperatorEqualError(checker::Type * const leftType,checker::Type * const rightType,checker::Type * tsType,lexer::SourcePosition pos)527 std::optional<std::tuple<Type *, Type *>> ETSChecker::CheckBinaryOperatorEqualError(checker::Type *const leftType,
528 checker::Type *const rightType,
529 checker::Type *tsType,
530 lexer::SourcePosition pos)
531 {
532 if (leftType->IsETSIntEnumType() && rightType->IsETSIntEnumType()) {
533 if (!leftType->AsETSIntEnumType()->IsSameEnumType(rightType->AsETSIntEnumType())) {
534 // We still know that operation result should be boolean, so recover.
535 LogTypeError("Bad operand type, the types of the operands must be the same enum type.", pos);
536 return {{GlobalETSBooleanType(), leftType}};
537 }
538
539 tsType = GlobalETSBooleanType();
540 return std::make_tuple(tsType, leftType);
541 }
542
543 if (leftType->IsETSStringEnumType() && rightType->IsETSStringEnumType()) {
544 if (!leftType->AsETSStringEnumType()->IsSameEnumType(rightType->AsETSStringEnumType())) {
545 LogTypeError("Bad operand type, the types of the operands must be the same enum type.", pos);
546 return {{GlobalETSBooleanType(), leftType}};
547 }
548
549 tsType = GlobalETSBooleanType();
550 return std::make_tuple(tsType, leftType);
551 }
552 return std::nullopt;
553 }
554
CheckBinaryOperatorEqual(ir::Expression * left,ir::Expression * right,lexer::TokenType operationType,lexer::SourcePosition pos,checker::Type * leftType,checker::Type * rightType,Type * unboxedL,Type * unboxedR)555 std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorEqual(ir::Expression *left, ir::Expression *right,
556 lexer::TokenType operationType,
557 lexer::SourcePosition pos, checker::Type *leftType,
558 checker::Type *rightType, Type *unboxedL,
559 Type *unboxedR)
560 {
561 RepairTypeErrorsInOperands(&leftType, &rightType);
562 RepairTypeErrorsInOperands(&unboxedL, &unboxedR);
563 if (leftType->IsTypeError()) { // both are errors
564 return {GlobalETSBooleanType(), GlobalTypeError()};
565 }
566
567 checker::Type *tsType {};
568
569 auto checkError = CheckBinaryOperatorEqualError(leftType, rightType, tsType, pos);
570 if (checkError.has_value()) {
571 return checkError.value();
572 }
573 if (leftType->IsETSDynamicType() || rightType->IsETSDynamicType()) {
574 return CheckBinaryOperatorEqualDynamic(left, right, pos);
575 }
576
577 if (IsReferenceType(leftType) && IsReferenceType(rightType)) {
578 Relation()->SetNode(left);
579 if (!CheckValidEqualReferenceType(leftType, rightType)) {
580 LogOperatorCannotBeApplied(operationType, leftType, rightType, pos);
581 return {GlobalETSBooleanType(), leftType};
582 }
583
584 tsType = GlobalETSBooleanType();
585 return {tsType, CreateETSUnionType({leftType, rightType})};
586 }
587
588 if (unboxedL != nullptr && unboxedL->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) && unboxedR != nullptr &&
589 unboxedR->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN)) {
590 if (unboxedL->HasTypeFlag(checker::TypeFlag::CONSTANT) && unboxedR->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
591 bool res = unboxedL->AsETSBooleanType()->GetValue() == unboxedR->AsETSBooleanType()->GetValue();
592
593 tsType = CreateETSBooleanType(operationType == lexer::TokenType::PUNCTUATOR_EQUAL ? res : !res);
594 return {tsType, tsType};
595 }
596
597 FlagExpressionWithUnboxing(leftType, unboxedL, left);
598 FlagExpressionWithUnboxing(rightType, unboxedR, right);
599
600 tsType = GlobalETSBooleanType();
601 return {tsType, tsType};
602 }
603
604 // Temporary workaround before == and === refactoring
605 if ((rightType->IsETSNullType() && leftType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) ||
606 (leftType->IsETSNullType() && rightType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE))) {
607 return {GlobalETSBooleanType(), CreateETSUnionType({leftType, rightType})};
608 }
609
610 return {nullptr, nullptr};
611 }
612
CheckBinaryOperatorEqualDynamic(ir::Expression * left,ir::Expression * right,lexer::SourcePosition pos)613 std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorEqualDynamic(ir::Expression *left, ir::Expression *right,
614 lexer::SourcePosition pos)
615 {
616 // NOTE: vpukhov. enforce intrinsic call in any case?
617 // canonicalize
618 auto *const dynExp = left->TsType()->IsETSDynamicType() ? left : right;
619 auto *const otherExp = dynExp == left ? right : left;
620
621 if (otherExp->TsType()->IsETSDynamicType()) {
622 return {GlobalETSBooleanType(), GlobalBuiltinJSValueType()};
623 }
624 if (dynExp->TsType()->AsETSDynamicType()->IsConvertible(otherExp->TsType())) {
625 // NOTE: vpukhov. boxing flags are not set in dynamic values
626 return {GlobalETSBooleanType(), otherExp->TsType()};
627 }
628 if (IsReferenceType(otherExp->TsType())) {
629 // have to prevent casting dyn_exp via ApplyCast without nullish flag
630 return {GlobalETSBooleanType(), GlobalETSNullishObjectType()};
631 }
632 LogTypeError("Unimplemented case in dynamic type comparison.", pos);
633 return {GlobalETSBooleanType(), GlobalETSNullishObjectType()};
634 }
635
636 // Satisfying the Chinese checker
NonNumericTypesAreAppropriateForComparison(Type * leftType,Type * rightType)637 static bool NonNumericTypesAreAppropriateForComparison(Type *leftType, Type *rightType)
638 {
639 return (rightType->IsETSStringType() && leftType->IsETSStringType()) ||
640 (((leftType->IsETSIntEnumType() && rightType->IsETSIntEnumType()) ||
641 (leftType->IsETSStringEnumType() && rightType->IsETSStringEnumType())) &&
642 leftType->AsETSEnumType()->IsSameEnumType(rightType->AsETSEnumType()));
643 }
644
CheckBinaryOperatorLessGreater(ir::Expression * left,ir::Expression * right,lexer::TokenType operationType,lexer::SourcePosition pos,bool isEqualOp,checker::Type * leftType,checker::Type * rightType,Type * unboxedL,Type * unboxedR)645 std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorLessGreater(ir::Expression *left, ir::Expression *right,
646 lexer::TokenType operationType,
647 lexer::SourcePosition pos, bool isEqualOp,
648 checker::Type *leftType, checker::Type *rightType,
649 Type *unboxedL, Type *unboxedR)
650 {
651 RepairTypeErrorsInOperands(&leftType, &rightType);
652 RepairTypeErrorsInOperands(&unboxedL, &unboxedR);
653 if (leftType->IsTypeError()) { // both are errors
654 return {GlobalETSBooleanType(), GlobalTypeError()};
655 }
656
657 if ((leftType->IsETSUnionType() || rightType->IsETSUnionType()) &&
658 operationType != lexer::TokenType::PUNCTUATOR_EQUAL &&
659 operationType != lexer::TokenType::PUNCTUATOR_NOT_EQUAL) {
660 LogTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos);
661 return {GlobalETSBooleanType(), leftType};
662 }
663
664 checker::Type *tsType {};
665 auto [promotedType, bothConst] =
666 ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_PRIMITIVE, !isEqualOp);
667
668 FlagExpressionWithUnboxing(leftType, unboxedL, left);
669 FlagExpressionWithUnboxing(rightType, unboxedR, right);
670
671 if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) {
672 return {GlobalETSBooleanType(), CreateETSUnionType({MaybeBoxExpression(left), MaybeBoxExpression(right)})};
673 }
674
675 if ((unboxedL != nullptr) && (unboxedR != nullptr) &&
676 (unboxedL->IsETSBooleanType() != unboxedR->IsETSBooleanType())) {
677 LogOperatorCannotBeApplied(operationType, leftType, rightType, pos);
678 return {GlobalETSBooleanType(), leftType};
679 }
680
681 if (promotedType == nullptr && !bothConst) {
682 if (NonNumericTypesAreAppropriateForComparison(leftType, rightType)) {
683 return {GlobalETSBooleanType(), GlobalETSBooleanType()};
684 }
685 if (((leftType->IsETSIntEnumType() && rightType->IsETSIntEnumType()) ||
686 (leftType->IsETSStringEnumType() && rightType->IsETSStringEnumType())) &&
687 leftType->AsETSEnumType()->IsSameEnumType(rightType->AsETSEnumType())) {
688 return {GlobalETSBooleanType(), GlobalETSBooleanType()};
689 }
690
691 LogTypeError("Bad operand type, the types of the operands must be numeric, same enumeration, or boolean type.",
692 pos);
693 return {GlobalETSBooleanType(), GlobalETSBooleanType()};
694 }
695
696 if (bothConst) {
697 tsType = HandleRelationOperationOnTypes(leftType, rightType, operationType);
698 return {tsType, tsType};
699 }
700
701 tsType = GlobalETSBooleanType();
702 auto *opType = promotedType;
703 return {tsType, opType};
704 }
705
CheckBinaryOperatorInstanceOf(lexer::SourcePosition pos,checker::Type * leftType,checker::Type * rightType)706 std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorInstanceOf(lexer::SourcePosition pos, checker::Type *leftType,
707 checker::Type *rightType)
708 {
709 RepairTypeErrorsInOperands(&leftType, &rightType);
710 if (leftType->IsTypeError()) { // both are errors
711 return {GlobalETSBooleanType(), GlobalTypeError()};
712 }
713
714 checker::Type *tsType {};
715 if (!IsReferenceType(leftType) || (!IsReferenceType(rightType) && !rightType->IsETSEnumType())) {
716 LogTypeError("Bad operand type, the types of the operands must be same type.", pos);
717 return {GlobalETSBooleanType(), leftType};
718 }
719
720 if (rightType->IsETSDynamicType() && !rightType->AsETSDynamicType()->HasDecl()) {
721 LogTypeError("Right-hand side of instanceof expression must represent a type.", pos);
722 return {GlobalETSBooleanType(), leftType};
723 }
724
725 tsType = GlobalETSBooleanType();
726 checker::Type *opType = rightType->IsETSDynamicType() ? GlobalBuiltinJSValueType() : GlobalETSObjectType();
727 ComputeApparentType(rightType);
728 RemoveStatus(checker::CheckerStatus::IN_INSTANCEOF_CONTEXT);
729
730 return {tsType, opType};
731 }
732
AdjustNumberLiteralType(ir::NumberLiteral * const literal,Type * literalType,Type * const otherType)733 bool ETSChecker::AdjustNumberLiteralType(ir::NumberLiteral *const literal, Type *literalType, Type *const otherType)
734 {
735 if (otherType->IsETSObjectType()) {
736 auto *const objectType = otherType->AsETSObjectType();
737 if (objectType->HasObjectFlag(ETSObjectFlags::BUILTIN_TYPE) && !objectType->IsETSStringType()) {
738 literal->RemoveBoxingUnboxingFlags(GetBoxingFlag(literalType));
739 literalType = ETSBuiltinTypeAsPrimitiveType(objectType);
740 literal->SetTsType(literalType);
741 literal->AddBoxingUnboxingFlags(GetBoxingFlag(literalType));
742 return true;
743 }
744 }
745 return false;
746 }
747
CheckBinaryOperatorNullishCoalescing(ir::Expression * left,ir::Expression * right,lexer::SourcePosition pos)748 Type *ETSChecker::CheckBinaryOperatorNullishCoalescing(ir::Expression *left, ir::Expression *right,
749 lexer::SourcePosition pos)
750 {
751 auto *leftType = left->TsType();
752 if (!IsReferenceType(leftType)) {
753 LogTypeError("Left-hand side of nullish-coalescing expression must be a reference type.", pos);
754 return leftType;
755 }
756
757 leftType = GetNonNullishType(leftType);
758 auto *rightType = MaybeBoxExpression(right);
759
760 if (IsTypeIdenticalTo(leftType, rightType)) {
761 return leftType;
762 }
763
764 // If possible and required update number literal type to the proper value (identical to left-side type)
765 if (right->IsNumberLiteral() && AdjustNumberLiteralType(right->AsNumberLiteral(), rightType, leftType)) {
766 return leftType;
767 }
768
769 return CreateETSUnionType({leftType, rightType});
770 }
771
772 using CheckBinaryFunction = std::function<checker::Type *(
773 ETSChecker *, std::tuple<ir::Expression *, ir::Expression *, lexer::TokenType, lexer::SourcePosition> op,
774 bool isEqualOp, std::tuple<checker::Type *, checker::Type *, Type *, Type *> types)>;
775
GetCheckMap()776 std::map<lexer::TokenType, CheckBinaryFunction> &GetCheckMap()
777 {
778 static std::map<lexer::TokenType, CheckBinaryFunction> checkMap = {
779 {lexer::TokenType::PUNCTUATOR_MULTIPLY, &ETSChecker::CheckBinaryOperatorMulDivMod},
780 {lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod},
781 {lexer::TokenType::PUNCTUATOR_DIVIDE, &ETSChecker::CheckBinaryOperatorMulDivMod},
782 {lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod},
783 {lexer::TokenType::PUNCTUATOR_MOD, &ETSChecker::CheckBinaryOperatorMulDivMod},
784 {lexer::TokenType::PUNCTUATOR_MOD_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod},
785
786 {lexer::TokenType::PUNCTUATOR_MINUS, &ETSChecker::CheckBinaryOperatorPlus},
787 {lexer::TokenType::PUNCTUATOR_MINUS_EQUAL, &ETSChecker::CheckBinaryOperatorPlus},
788 {lexer::TokenType::PUNCTUATOR_PLUS, &ETSChecker::CheckBinaryOperatorPlus},
789 {lexer::TokenType::PUNCTUATOR_PLUS_EQUAL, &ETSChecker::CheckBinaryOperatorPlus},
790
791 {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT, &ETSChecker::CheckBinaryOperatorShift},
792 {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift},
793 {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT, &ETSChecker::CheckBinaryOperatorShift},
794 {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift},
795 {lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT, &ETSChecker::CheckBinaryOperatorShift},
796 {lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift},
797
798 {lexer::TokenType::PUNCTUATOR_BITWISE_OR, &ETSChecker::CheckBinaryOperatorBitwise},
799 {lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise},
800 {lexer::TokenType::PUNCTUATOR_BITWISE_AND, &ETSChecker::CheckBinaryOperatorBitwise},
801 {lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise},
802 {lexer::TokenType::PUNCTUATOR_BITWISE_XOR, &ETSChecker::CheckBinaryOperatorBitwise},
803 {lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise},
804 };
805
806 return checkMap;
807 }
808
809 struct BinaryOperatorParams {
810 ir::Expression *left;
811 ir::Expression *right;
812 ir::Expression *expr;
813 lexer::TokenType operationType;
814 lexer::SourcePosition pos;
815 bool isEqualOp;
816 };
817
818 struct TypeParams {
819 checker::Type *leftType;
820 checker::Type *rightType;
821 Type *unboxedL;
822 Type *unboxedR;
823 };
824
CheckBinaryOperatorHelper(ETSChecker * checker,const BinaryOperatorParams & binaryParams,const TypeParams & typeParams)825 static std::tuple<Type *, Type *> CheckBinaryOperatorHelper(ETSChecker *checker,
826 const BinaryOperatorParams &binaryParams,
827 const TypeParams &typeParams)
828 {
829 ir::Expression *left = binaryParams.left;
830 ir::Expression *right = binaryParams.right;
831 lexer::SourcePosition pos = binaryParams.pos;
832 checker::Type *const leftType = typeParams.leftType;
833 checker::Type *const rightType = typeParams.rightType;
834 checker::Type *tsType {};
835 switch (binaryParams.operationType) {
836 case lexer::TokenType::PUNCTUATOR_LOGICAL_AND:
837 case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
838 tsType = checker->CheckBinaryOperatorLogical(left, right, binaryParams.expr, pos, leftType, rightType,
839 typeParams.unboxedL, typeParams.unboxedR);
840 break;
841 }
842 case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
843 case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: {
844 return checker->CheckBinaryOperatorStrictEqual(left, binaryParams.operationType, pos, leftType, rightType);
845 }
846 case lexer::TokenType::PUNCTUATOR_EQUAL:
847 case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: {
848 std::tuple<Type *, Type *> res =
849 checker->CheckBinaryOperatorEqual(left, right, binaryParams.operationType, pos, leftType, rightType,
850 typeParams.unboxedL, typeParams.unboxedR);
851 if (!(std::get<0>(res) == nullptr && std::get<1>(res) == nullptr)) {
852 return res;
853 }
854 [[fallthrough]];
855 }
856 case lexer::TokenType::PUNCTUATOR_LESS_THAN:
857 case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
858 case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
859 case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
860 return checker->CheckBinaryOperatorLessGreater(left, right, binaryParams.operationType, pos,
861 binaryParams.isEqualOp, leftType, rightType,
862 typeParams.unboxedL, typeParams.unboxedR);
863 }
864 case lexer::TokenType::KEYW_INSTANCEOF: {
865 return checker->CheckBinaryOperatorInstanceOf(pos, leftType, rightType);
866 }
867 case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: {
868 tsType = checker->CheckBinaryOperatorNullishCoalescing(left, right, pos);
869 break;
870 }
871 default: {
872 UNREACHABLE();
873 break;
874 }
875 }
876
877 return {tsType, tsType};
878 }
879
880 namespace {
IsStringEnum(const ir::Expression * expr)881 bool IsStringEnum(const ir::Expression *expr)
882 {
883 if (expr == nullptr) {
884 return false;
885 }
886 auto type = expr->TsType();
887 if (type == nullptr) {
888 return false;
889 }
890
891 return type->IsETSStringEnumType();
892 }
893
IsIntEnum(const ir::Expression * expr)894 bool IsIntEnum(const ir::Expression *expr)
895 {
896 if (expr == nullptr) {
897 return false;
898 }
899
900 auto type = expr->TsType();
901 if (type == nullptr) {
902 return false;
903 }
904
905 return type->IsETSIntEnumType();
906 }
907
CheckNumericOperatorContext(ir::Expression * expression,lexer::TokenType op)908 bool CheckNumericOperatorContext(ir::Expression *expression, lexer::TokenType op)
909 {
910 const bool isMultiplicative = op == lexer::TokenType::PUNCTUATOR_MULTIPLY ||
911 op == lexer::TokenType::PUNCTUATOR_DIVIDE || op == lexer::TokenType::PUNCTUATOR_MOD;
912 const bool isAdditive = op == lexer::TokenType::PUNCTUATOR_PLUS || op == lexer::TokenType::PUNCTUATOR_MINUS;
913 const bool isShift = op == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT ||
914 op == lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT ||
915 op == lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT;
916 const bool isRelational =
917 op == lexer::TokenType::PUNCTUATOR_GREATER_THAN || op == lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL ||
918 op == lexer::TokenType::PUNCTUATOR_LESS_THAN || op == lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL;
919 const bool isEquality = op == lexer::TokenType::PUNCTUATOR_EQUAL || op == lexer::TokenType::PUNCTUATOR_NOT_EQUAL;
920 const bool isBitwise = op == lexer::TokenType::PUNCTUATOR_BITWISE_AND ||
921 op == lexer::TokenType::PUNCTUATOR_BITWISE_OR ||
922 op == lexer::TokenType::PUNCTUATOR_BITWISE_XOR;
923 const bool isConditionalAndOr =
924 op == lexer::TokenType::PUNCTUATOR_LOGICAL_AND || op == lexer::TokenType::PUNCTUATOR_LOGICAL_OR;
925
926 if (IsIntEnum(expression)) {
927 if (isMultiplicative || isAdditive || isShift || isRelational || isEquality || isBitwise ||
928 isConditionalAndOr) {
929 expression->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF);
930 }
931 return true;
932 }
933 return false;
934 }
935
CheckStringOperatorContext(ir::Expression * expression,checker::Type * otherType,lexer::TokenType op)936 void CheckStringOperatorContext(ir::Expression *expression, checker::Type *otherType, lexer::TokenType op)
937 {
938 if (IsStringEnum(expression) && (otherType->IsETSStringType() || otherType->IsETSStringEnumType())) {
939 if (op == lexer::TokenType::PUNCTUATOR_PLUS) {
940 expression->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF);
941 }
942 }
943 }
944
CheckRelationalOperatorsBetweenEnums(ir::Expression * left,ir::Expression * right,lexer::TokenType op)945 bool CheckRelationalOperatorsBetweenEnums(ir::Expression *left, ir::Expression *right, lexer::TokenType op)
946 {
947 const bool isRelational =
948 op == lexer::TokenType::PUNCTUATOR_GREATER_THAN || op == lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL ||
949 op == lexer::TokenType::PUNCTUATOR_LESS_THAN || op == lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL;
950 const bool isEquality = op == lexer::TokenType::PUNCTUATOR_EQUAL || op == lexer::TokenType::PUNCTUATOR_NOT_EQUAL;
951
952 if (((IsStringEnum(left) && IsStringEnum(right)) ||
953 (IsIntEnum(left) && IsIntEnum(right)))) { // NOTE(psiket) In case of int enums it has been already checked in
954 // the CheckNumericOperatorContext function
955 if (isRelational || isEquality) {
956 left->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF);
957 right->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF);
958 return true;
959 }
960 }
961 return false;
962 }
963
CheckNeedToGenerateGetValueForBinaryExpression(ir::Expression * expression)964 void CheckNeedToGenerateGetValueForBinaryExpression(ir::Expression *expression)
965 {
966 if (!expression->IsBinaryExpression()) {
967 return;
968 }
969
970 auto binaryExpression = expression->AsBinaryExpression();
971 auto op = binaryExpression->OperatorType();
972 auto leftExp = binaryExpression->Left();
973 auto rightExp = binaryExpression->Right();
974
975 // Numeric Operator Context
976 auto leftIsIntEnum = CheckNumericOperatorContext(leftExp, op);
977 auto rightIsIntEnum = CheckNumericOperatorContext(rightExp, op);
978 if (leftIsIntEnum || rightIsIntEnum) {
979 return;
980 }
981
982 // String Operator Context
983 CheckStringOperatorContext(leftExp, rightExp->TsType(), op);
984 CheckStringOperatorContext(rightExp, leftExp->TsType(), op);
985
986 // Relational operators if both are enumeration Types
987 if (CheckRelationalOperatorsBetweenEnums(leftExp, rightExp, op)) {
988 return;
989 }
990 }
991 } // namespace
992
CheckBinaryOperator(ir::Expression * left,ir::Expression * right,ir::Expression * expr,lexer::TokenType operationType,lexer::SourcePosition pos,bool forcePromotion)993 std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperator(ir::Expression *left, ir::Expression *right,
994 ir::Expression *expr, lexer::TokenType operationType,
995 lexer::SourcePosition pos, bool forcePromotion)
996 {
997 checker::Type *const leftType = left->Check(this);
998
999 if (leftType == nullptr) {
1000 LogTypeError("Unexpected type error in binary expression", left->Start());
1001 auto rightType = right->Check(this);
1002 return {rightType, rightType};
1003 }
1004
1005 if (operationType == lexer::TokenType::KEYW_INSTANCEOF) {
1006 AddStatus(checker::CheckerStatus::IN_INSTANCEOF_CONTEXT);
1007 }
1008
1009 Context().CheckTestSmartCastCondition(operationType);
1010
1011 checker::Type *rightType = right->Check(this);
1012 if (right->IsTypeNode()) {
1013 rightType = right->AsTypeNode()->GetType(this);
1014 }
1015
1016 if (rightType == nullptr) {
1017 LogTypeError("Unexpected type error in binary expression", pos);
1018 return {leftType, leftType};
1019 }
1020
1021 CheckNeedToGenerateGetValueForBinaryExpression(expr);
1022
1023 const bool isLogicalExtendedOperator = (operationType == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) ||
1024 (operationType == lexer::TokenType::PUNCTUATOR_LOGICAL_OR);
1025 Type *unboxedL =
1026 isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(leftType) : ETSBuiltinTypeAsPrimitiveType(leftType);
1027 Type *unboxedR = isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(rightType)
1028 : ETSBuiltinTypeAsPrimitiveType(rightType);
1029
1030 bool isEqualOp = (operationType > lexer::TokenType::PUNCTUATOR_SUBSTITUTION &&
1031 operationType < lexer::TokenType::PUNCTUATOR_ARROW) &&
1032 !forcePromotion;
1033
1034 if (CheckBinaryOperatorForBigInt(leftType, rightType, operationType)) {
1035 switch (operationType) {
1036 case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
1037 case lexer::TokenType::PUNCTUATOR_LESS_THAN:
1038 case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL:
1039 case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
1040 return {GlobalETSBooleanType(), GlobalETSBooleanType()};
1041 default:
1042 return {leftType, rightType};
1043 }
1044 }
1045
1046 auto checkMap = GetCheckMap();
1047 if (checkMap.find(operationType) != checkMap.end()) {
1048 auto check = checkMap[operationType];
1049 auto tsType = check(this, std::make_tuple(left, right, operationType, pos), isEqualOp,
1050 std::make_tuple(leftType, rightType, unboxedL, unboxedR));
1051 return {tsType, tsType};
1052 }
1053
1054 return CheckBinaryOperatorHelper(this, {left, right, expr, operationType, pos, isEqualOp},
1055 {leftType, rightType, unboxedL, unboxedR});
1056 }
1057
HandleArithmeticOperationOnTypes(Type * left,Type * right,lexer::TokenType operationType)1058 Type *ETSChecker::HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
1059 {
1060 ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) &&
1061 right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC));
1062
1063 if (left->IsDoubleType() || right->IsDoubleType()) {
1064 return PerformArithmeticOperationOnTypes<DoubleType>(left, right, operationType);
1065 }
1066
1067 if (left->IsFloatType() || right->IsFloatType()) {
1068 return PerformArithmeticOperationOnTypes<FloatType>(left, right, operationType);
1069 }
1070
1071 if (left->IsLongType() || right->IsLongType()) {
1072 return PerformArithmeticOperationOnTypes<LongType>(left, right, operationType);
1073 }
1074
1075 return PerformArithmeticOperationOnTypes<IntType>(left, right, operationType);
1076 }
1077
HandleBitwiseOperationOnTypes(Type * left,Type * right,lexer::TokenType operationType)1078 Type *ETSChecker::HandleBitwiseOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
1079 {
1080 ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) &&
1081 right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC));
1082
1083 if (left->IsDoubleType() || right->IsDoubleType()) {
1084 return HandleBitWiseArithmetic<DoubleType, LongType>(left, right, operationType);
1085 }
1086
1087 if (left->IsFloatType() || right->IsFloatType()) {
1088 return HandleBitWiseArithmetic<FloatType, IntType>(left, right, operationType);
1089 }
1090
1091 if (left->IsLongType() || right->IsLongType()) {
1092 return HandleBitWiseArithmetic<LongType>(left, right, operationType);
1093 }
1094
1095 return HandleBitWiseArithmetic<IntType>(left, right, operationType);
1096 }
1097
FlagExpressionWithUnboxing(Type * type,Type * unboxedType,ir::Expression * typeExpression)1098 void ETSChecker::FlagExpressionWithUnboxing(Type *type, Type *unboxedType, ir::Expression *typeExpression)
1099 {
1100 if (type->IsETSObjectType() && (unboxedType != nullptr)) {
1101 typeExpression->AddBoxingUnboxingFlags(GetUnboxingFlag(unboxedType));
1102 }
1103 }
1104
1105 } // namespace ark::es2panda::checker
1106