• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "ir/expressions/identifier.h"
19 #include "varbinder/variable.h"
20 #include "varbinder/scope.h"
21 #include "varbinder/declaration.h"
22 #include "checker/ETSchecker.h"
23 
24 namespace panda::es2panda::checker {
25 
NegateNumericType(Type * type,ir::Expression * node)26 Type *ETSChecker::NegateNumericType(Type *type, ir::Expression *node)
27 {
28     ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC));
29 
30     TypeFlag typeKind = ETSType(type);
31     Type *result = nullptr;
32 
33     switch (typeKind) {
34         case TypeFlag::BYTE: {
35             result = CreateByteType(-(type->AsByteType()->GetValue()));
36             break;
37         }
38         case TypeFlag::CHAR: {
39             result = CreateCharType(-(type->AsCharType()->GetValue()));
40             break;
41         }
42         case TypeFlag::SHORT: {
43             result = CreateShortType(-(type->AsShortType()->GetValue()));
44             break;
45         }
46         case TypeFlag::INT: {
47             result = CreateIntType(-(type->AsIntType()->GetValue()));
48             break;
49         }
50         case TypeFlag::LONG: {
51             result = CreateLongType(-(type->AsLongType()->GetValue()));
52             break;
53         }
54         case TypeFlag::FLOAT: {
55             result = CreateFloatType(-(type->AsFloatType()->GetValue()));
56             break;
57         }
58         case TypeFlag::DOUBLE: {
59             result = CreateDoubleType(-(type->AsDoubleType()->GetValue()));
60             break;
61         }
62         default: {
63             UNREACHABLE();
64         }
65     }
66 
67     node->SetTsType(result);
68     return result;
69 }
70 
BitwiseNegateNumericType(Type * type,ir::Expression * node)71 Type *ETSChecker::BitwiseNegateNumericType(Type *type, ir::Expression *node)
72 {
73     ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_INTEGRAL));
74 
75     TypeFlag typeKind = ETSType(type);
76 
77     Type *result = nullptr;
78 
79     switch (typeKind) {
80         case TypeFlag::BYTE: {
81             result = CreateByteType(static_cast<int8_t>(~static_cast<uint8_t>(type->AsByteType()->GetValue())));
82             break;
83         }
84         case TypeFlag::CHAR: {
85             result = CreateCharType(~(type->AsCharType()->GetValue()));
86             break;
87         }
88         case TypeFlag::SHORT: {
89             result = CreateShortType(static_cast<int16_t>(~static_cast<uint16_t>(type->AsShortType()->GetValue())));
90             break;
91         }
92         case TypeFlag::INT: {
93             result = CreateIntType(static_cast<int32_t>(~static_cast<uint32_t>(type->AsIntType()->GetValue())));
94             break;
95         }
96         case TypeFlag::LONG: {
97             result = CreateLongType(static_cast<int64_t>(~static_cast<uint64_t>(type->AsLongType()->GetValue())));
98             break;
99         }
100         case TypeFlag::FLOAT: {
101             result = CreateIntType(
102                 ~static_cast<uint32_t>(CastFloatToInt<FloatType::UType, int32_t>(type->AsFloatType()->GetValue())));
103             break;
104         }
105         case TypeFlag::DOUBLE: {
106             result = CreateLongType(
107                 ~static_cast<uint64_t>(CastFloatToInt<DoubleType::UType, int64_t>(type->AsDoubleType()->GetValue())));
108             break;
109         }
110         default: {
111             UNREACHABLE();
112         }
113     }
114 
115     node->SetTsType(result);
116     return result;
117 }
118 
HandleRelationOperationOnTypes(Type * left,Type * right,lexer::TokenType operationType)119 Type *ETSChecker::HandleRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
120 {
121     ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC) &&
122            right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC));
123 
124     if (left->IsDoubleType() || right->IsDoubleType()) {
125         return PerformRelationOperationOnTypes<DoubleType>(left, right, operationType);
126     }
127 
128     if (left->IsFloatType() || right->IsFloatType()) {
129         return PerformRelationOperationOnTypes<FloatType>(left, right, operationType);
130     }
131 
132     if (left->IsLongType() || right->IsLongType()) {
133         return PerformRelationOperationOnTypes<LongType>(left, right, operationType);
134     }
135 
136     return PerformRelationOperationOnTypes<IntType>(left, right, operationType);
137 }
138 
CheckBinaryOperatorForBigInt(Type * left,Type * right,ir::Expression * expr,lexer::TokenType op)139 bool ETSChecker::CheckBinaryOperatorForBigInt(Type *left, Type *right, ir::Expression *expr, lexer::TokenType op)
140 {
141     if ((left == nullptr) || (right == nullptr)) {
142         return false;
143     }
144 
145     if (!left->IsETSBigIntType()) {
146         return false;
147     }
148 
149     if (!right->IsETSBigIntType()) {
150         return false;
151     }
152 
153     if (expr->IsBinaryExpression()) {
154         ir::BinaryExpression *be = expr->AsBinaryExpression();
155         if (be->OperatorType() == lexer::TokenType::PUNCTUATOR_STRICT_EQUAL) {
156             // Handle strict comparison as normal comparison for bigint objects
157             be->SetOperator(lexer::TokenType::PUNCTUATOR_EQUAL);
158         }
159     }
160 
161     switch (op) {
162         case lexer::TokenType::PUNCTUATOR_EQUAL:
163         case lexer::TokenType::KEYW_INSTANCEOF:
164             // This is handled in the main CheckBinaryOperator function
165             return false;
166         default:
167             break;
168     }
169 
170     // Remove const flag - currently there are no compile time operations for bigint
171     left->RemoveTypeFlag(TypeFlag::CONSTANT);
172     right->RemoveTypeFlag(TypeFlag::CONSTANT);
173 
174     return true;
175 }
176 
CheckBinaryOperatorMulDivMod(ir::Expression * left,ir::Expression * right,lexer::TokenType operationType,lexer::SourcePosition pos,bool isEqualOp,checker::Type * const leftType,checker::Type * const rightType,Type * unboxedL,Type * unboxedR)177 checker::Type *ETSChecker::CheckBinaryOperatorMulDivMod(ir::Expression *left, ir::Expression *right,
178                                                         lexer::TokenType operationType, lexer::SourcePosition pos,
179                                                         bool isEqualOp, checker::Type *const leftType,
180                                                         checker::Type *const rightType, Type *unboxedL, Type *unboxedR)
181 {
182     checker::Type *tsType {};
183     auto [promotedType, bothConst] =
184         ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_NUMERIC, !isEqualOp);
185 
186     FlagExpressionWithUnboxing(leftType, unboxedL, left);
187     FlagExpressionWithUnboxing(rightType, unboxedR, right);
188 
189     if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) {
190         ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos);
191     }
192 
193     if (promotedType == nullptr && !bothConst) {
194         ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos);
195     }
196 
197     if (bothConst) {
198         tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType);
199     }
200 
201     tsType = (tsType != nullptr) ? tsType : promotedType;
202     return tsType;
203 }
204 
CheckBinaryOperatorPlus(ir::Expression * left,ir::Expression * right,lexer::TokenType operationType,lexer::SourcePosition pos,bool isEqualOp,checker::Type * const leftType,checker::Type * const rightType,Type * unboxedL,Type * unboxedR)205 checker::Type *ETSChecker::CheckBinaryOperatorPlus(ir::Expression *left, ir::Expression *right,
206                                                    lexer::TokenType operationType, lexer::SourcePosition pos,
207                                                    bool isEqualOp, checker::Type *const leftType,
208                                                    checker::Type *const rightType, Type *unboxedL, Type *unboxedR)
209 {
210     if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) {
211         ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos);
212     }
213 
214     if (leftType->IsETSStringType() || rightType->IsETSStringType()) {
215         if (operationType == lexer::TokenType::PUNCTUATOR_MINUS ||
216             operationType == lexer::TokenType::PUNCTUATOR_MINUS_EQUAL) {
217             ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos);
218         }
219 
220         return HandleStringConcatenation(leftType, rightType);
221     }
222 
223     auto [promotedType, bothConst] =
224         ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_NUMERIC, !isEqualOp);
225 
226     FlagExpressionWithUnboxing(leftType, unboxedL, left);
227     FlagExpressionWithUnboxing(rightType, unboxedR, right);
228 
229     if (promotedType == nullptr && !bothConst) {
230         ThrowTypeError("Bad operand type, the types of the operands must be numeric type or String.", pos);
231     }
232 
233     if (bothConst) {
234         return HandleArithmeticOperationOnTypes(leftType, rightType, operationType);
235     }
236 
237     return promotedType;
238 }
239 
CheckBinaryOperatorShift(ir::Expression * left,ir::Expression * right,lexer::TokenType operationType,lexer::SourcePosition pos,bool isEqualOp,checker::Type * const leftType,checker::Type * const rightType,Type * unboxedL,Type * unboxedR)240 checker::Type *ETSChecker::CheckBinaryOperatorShift(ir::Expression *left, ir::Expression *right,
241                                                     lexer::TokenType operationType, lexer::SourcePosition pos,
242                                                     bool isEqualOp, checker::Type *const leftType,
243                                                     checker::Type *const rightType, Type *unboxedL, Type *unboxedR)
244 {
245     if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) {
246         ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos);
247     }
248 
249     auto promotedLeftType = ApplyUnaryOperatorPromotion(unboxedL, false, !isEqualOp);
250     auto promotedRightType = ApplyUnaryOperatorPromotion(unboxedR, false, !isEqualOp);
251 
252     FlagExpressionWithUnboxing(leftType, unboxedL, left);
253     FlagExpressionWithUnboxing(rightType, unboxedR, right);
254 
255     if (promotedLeftType == nullptr || !promotedLeftType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC) ||
256         promotedRightType == nullptr || !promotedRightType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) {
257         ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos);
258     }
259 
260     if (promotedLeftType->HasTypeFlag(TypeFlag::CONSTANT) && promotedRightType->HasTypeFlag(TypeFlag::CONSTANT)) {
261         return HandleBitwiseOperationOnTypes(promotedLeftType, promotedRightType, operationType);
262     }
263 
264     switch (ETSType(promotedLeftType)) {
265         case TypeFlag::BYTE: {
266             return GlobalByteType();
267         }
268         case TypeFlag::SHORT: {
269             return GlobalShortType();
270         }
271         case TypeFlag::CHAR: {
272             return GlobalCharType();
273         }
274         case TypeFlag::INT:
275         case TypeFlag::FLOAT: {
276             return GlobalIntType();
277         }
278         case TypeFlag::LONG:
279         case TypeFlag::DOUBLE: {
280             return GlobalLongType();
281         }
282         default: {
283             UNREACHABLE();
284         }
285     }
286     return nullptr;
287 }
288 
CheckBinaryOperatorBitwise(ir::Expression * left,ir::Expression * right,lexer::TokenType operationType,lexer::SourcePosition pos,bool isEqualOp,checker::Type * const leftType,checker::Type * const rightType,Type * unboxedL,Type * unboxedR)289 checker::Type *ETSChecker::CheckBinaryOperatorBitwise(ir::Expression *left, ir::Expression *right,
290                                                       lexer::TokenType operationType, lexer::SourcePosition pos,
291                                                       bool isEqualOp, checker::Type *const leftType,
292                                                       checker::Type *const rightType, Type *unboxedL, Type *unboxedR)
293 {
294     if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) {
295         ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos);
296     }
297 
298     if (unboxedL != nullptr && unboxedL->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) && unboxedR != nullptr &&
299         unboxedR->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN)) {
300         FlagExpressionWithUnboxing(leftType, unboxedL, left);
301         FlagExpressionWithUnboxing(rightType, unboxedR, right);
302         return HandleBooleanLogicalOperators(unboxedL, unboxedR, operationType);
303     }
304 
305     auto [promotedType, bothConst] =
306         ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_NUMERIC, !isEqualOp);
307 
308     FlagExpressionWithUnboxing(leftType, unboxedL, left);
309     FlagExpressionWithUnboxing(rightType, unboxedR, right);
310 
311     if (promotedType == nullptr && !bothConst) {
312         ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos);
313     }
314 
315     if (bothConst) {
316         return HandleBitwiseOperationOnTypes(leftType, rightType, operationType);
317     }
318 
319     return SelectGlobalIntegerTypeForNumeric(promotedType);
320 }
321 
CheckBinaryOperatorLogical(ir::Expression * left,ir::Expression * right,ir::Expression * expr,lexer::SourcePosition pos,checker::Type * const leftType,checker::Type * const rightType,Type * unboxedL,Type * unboxedR)322 checker::Type *ETSChecker::CheckBinaryOperatorLogical(ir::Expression *left, ir::Expression *right, ir::Expression *expr,
323                                                       lexer::SourcePosition pos, checker::Type *const leftType,
324                                                       checker::Type *const rightType, Type *unboxedL, Type *unboxedR)
325 {
326     if (leftType->IsETSUnionType() || rightType->IsETSUnionType()) {
327         ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos);
328     }
329 
330     if (unboxedL == nullptr || !unboxedL->IsConditionalExprType() || unboxedR == nullptr ||
331         !unboxedR->IsConditionalExprType()) {
332         ThrowTypeError("Bad operand type, the types of the operands must be of possible condition type.", pos);
333     }
334 
335     if (unboxedL->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
336         FlagExpressionWithUnboxing(leftType, unboxedL, left);
337     }
338 
339     if (unboxedR->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
340         FlagExpressionWithUnboxing(rightType, unboxedR, right);
341     }
342 
343     if (expr->IsBinaryExpression()) {
344         return HandleBooleanLogicalOperatorsExtended(unboxedL, unboxedR, expr->AsBinaryExpression());
345     }
346 
347     UNREACHABLE();
348 }
349 
CheckBinaryOperatorStrictEqual(ir::Expression * left,lexer::SourcePosition pos,checker::Type * const leftType,checker::Type * const rightType)350 std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorStrictEqual(ir::Expression *left, lexer::SourcePosition pos,
351                                                                       checker::Type *const leftType,
352                                                                       checker::Type *const rightType)
353 {
354     checker::Type *tsType {};
355     if (!(leftType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT) || leftType->IsETSUnionType()) ||
356         !(rightType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT) || rightType->IsETSUnionType())) {
357         ThrowTypeError("Both operands have to be reference types", pos);
358     }
359 
360     Relation()->SetNode(left);
361     if (!Relation()->IsCastableTo(leftType, rightType) && !Relation()->IsCastableTo(rightType, leftType)) {
362         ThrowTypeError("The operands of strict equality are not compatible with each other", pos);
363     }
364     tsType = GlobalETSBooleanType();
365     if (rightType->IsETSDynamicType() && leftType->IsETSDynamicType()) {
366         return {tsType, GlobalBuiltinJSValueType()};
367     }
368     return {tsType, GlobalETSObjectType()};
369 }
370 
CheckBinaryOperatorEqual(ir::Expression * left,ir::Expression * right,lexer::TokenType operationType,lexer::SourcePosition pos,checker::Type * const leftType,checker::Type * const rightType,Type * unboxedL,Type * unboxedR)371 std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorEqual(
372     ir::Expression *left, ir::Expression *right, lexer::TokenType operationType, lexer::SourcePosition pos,
373     checker::Type *const leftType, checker::Type *const rightType, Type *unboxedL, Type *unboxedR)
374 {
375     checker::Type *tsType {};
376     if (leftType->IsETSEnumType() && rightType->IsETSEnumType()) {
377         if (!leftType->AsETSEnumType()->IsSameEnumType(rightType->AsETSEnumType())) {
378             ThrowTypeError("Bad operand type, the types of the operands must be the same enum type.", pos);
379         }
380 
381         tsType = GlobalETSBooleanType();
382         return {tsType, leftType};
383     }
384 
385     if (leftType->IsETSStringEnumType() && rightType->IsETSStringEnumType()) {
386         if (!leftType->AsETSStringEnumType()->IsSameEnumType(rightType->AsETSStringEnumType())) {
387             ThrowTypeError("Bad operand type, the types of the operands must be the same enum type.", pos);
388         }
389 
390         tsType = GlobalETSBooleanType();
391         return {tsType, leftType};
392     }
393 
394     if (leftType->IsETSDynamicType() || rightType->IsETSDynamicType()) {
395         return CheckBinaryOperatorEqualDynamic(left, right, pos);
396     }
397 
398     if (IsReferenceType(leftType) && IsReferenceType(rightType)) {
399         tsType = GlobalETSBooleanType();
400         auto *opType = GlobalETSObjectType();
401         return {tsType, opType};
402     }
403 
404     if (unboxedL != nullptr && unboxedL->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) && unboxedR != nullptr &&
405         unboxedR->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN)) {
406         if (unboxedL->HasTypeFlag(checker::TypeFlag::CONSTANT) && unboxedR->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
407             bool res = unboxedL->AsETSBooleanType()->GetValue() == unboxedR->AsETSBooleanType()->GetValue();
408 
409             tsType = CreateETSBooleanType(operationType == lexer::TokenType::PUNCTUATOR_EQUAL ? res : !res);
410             return {tsType, tsType};
411         }
412 
413         FlagExpressionWithUnboxing(leftType, unboxedL, left);
414         FlagExpressionWithUnboxing(rightType, unboxedR, right);
415 
416         tsType = GlobalETSBooleanType();
417         return {tsType, tsType};
418     }
419     return {nullptr, nullptr};
420 }
421 
CheckBinaryOperatorEqualDynamic(ir::Expression * left,ir::Expression * right,lexer::SourcePosition pos)422 std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorEqualDynamic(ir::Expression *left, ir::Expression *right,
423                                                                        lexer::SourcePosition pos)
424 {
425     // NOTE: vpukhov. enforce intrinsic call in any case?
426     // canonicalize
427     auto *const dynExp = left->TsType()->IsETSDynamicType() ? left : right;
428     auto *const otherExp = dynExp == left ? right : left;
429 
430     if (otherExp->TsType()->IsETSDynamicType()) {
431         return {GlobalETSBooleanType(), GlobalBuiltinJSValueType()};
432     }
433     if (dynExp->TsType()->AsETSDynamicType()->IsConvertible(otherExp->TsType())) {
434         // NOTE: vpukhov. boxing flags are not set in dynamic values
435         return {GlobalETSBooleanType(), otherExp->TsType()};
436     }
437     if (IsReferenceType(otherExp->TsType())) {
438         // have to prevent casting dyn_exp via ApplyCast without nullish flag
439         return {GlobalETSBooleanType(), GlobalETSNullishObjectType()};
440     }
441     ThrowTypeError("Unimplemented case in dynamic type comparison.", pos);
442 }
443 
CheckBinaryOperatorLessGreater(ir::Expression * left,ir::Expression * right,lexer::TokenType operationType,lexer::SourcePosition pos,bool isEqualOp,checker::Type * const leftType,checker::Type * const rightType,Type * unboxedL,Type * unboxedR)444 std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorLessGreater(
445     ir::Expression *left, ir::Expression *right, lexer::TokenType operationType, lexer::SourcePosition pos,
446     bool isEqualOp, checker::Type *const leftType, checker::Type *const rightType, Type *unboxedL, Type *unboxedR)
447 {
448     if ((leftType->IsETSUnionType() || rightType->IsETSUnionType()) &&
449         operationType != lexer::TokenType::PUNCTUATOR_EQUAL &&
450         operationType != lexer::TokenType::PUNCTUATOR_NOT_EQUAL) {
451         ThrowTypeError("Bad operand type, unions are not allowed in binary expressions except equality.", pos);
452     }
453 
454     checker::Type *tsType {};
455     auto [promotedType, bothConst] =
456         ApplyBinaryOperatorPromotion(unboxedL, unboxedR, TypeFlag::ETS_NUMERIC, !isEqualOp);
457 
458     FlagExpressionWithUnboxing(leftType, unboxedL, left);
459     FlagExpressionWithUnboxing(rightType, unboxedR, right);
460 
461     if (leftType->IsETSUnionType()) {
462         tsType = GlobalETSBooleanType();
463         return {tsType, leftType->AsETSUnionType()};
464     }
465 
466     if (rightType->IsETSUnionType()) {
467         tsType = GlobalETSBooleanType();
468         return {tsType, rightType->AsETSUnionType()};
469     }
470 
471     if (promotedType == nullptr && !bothConst) {
472         ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos);
473     }
474 
475     if (bothConst) {
476         tsType = HandleRelationOperationOnTypes(leftType, rightType, operationType);
477         return {tsType, tsType};
478     }
479 
480     tsType = GlobalETSBooleanType();
481     auto *opType = promotedType;
482     return {tsType, opType};
483 }
484 
CheckBinaryOperatorInstanceOf(lexer::SourcePosition pos,checker::Type * const leftType,checker::Type * const rightType)485 std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperatorInstanceOf(lexer::SourcePosition pos,
486                                                                      checker::Type *const leftType,
487                                                                      checker::Type *const rightType)
488 {
489     checker::Type *tsType {};
490     if (!IsReferenceType(leftType) || !IsReferenceType(rightType)) {
491         ThrowTypeError("Bad operand type, the types of the operands must be same type.", pos);
492     }
493 
494     if (rightType->IsETSDynamicType() || leftType->IsETSDynamicType()) {
495         if (!(rightType->IsETSDynamicType() && leftType->IsETSDynamicType())) {
496             ThrowTypeError("Bad operand type, both types of the operands must be dynamic.", pos);
497         }
498     }
499 
500     tsType = GlobalETSBooleanType();
501     checker::Type *opType = rightType->IsETSDynamicType() ? GlobalBuiltinJSValueType() : GlobalETSObjectType();
502     return {tsType, opType};
503 }
504 
CheckBinaryOperatorNullishCoalescing(ir::Expression * right,lexer::SourcePosition pos,checker::Type * const leftType,checker::Type * const rightType)505 Type *ETSChecker::CheckBinaryOperatorNullishCoalescing(ir::Expression *right, lexer::SourcePosition pos,
506                                                        checker::Type *const leftType, checker::Type *const rightType)
507 {
508     if (!leftType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) {
509         ThrowTypeError("Left-hand side expression must be a reference type.", pos);
510     }
511 
512     checker::Type *nonNullishLeftType = leftType;
513 
514     if (leftType->IsNullish()) {
515         nonNullishLeftType = GetNonNullishType(leftType);
516     }
517 
518     // NOTE: vpukhov. check convertibility and use numeric promotion
519 
520     if (rightType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
521         Relation()->SetNode(right);
522         auto boxedRightType = PrimitiveTypeAsETSBuiltinType(rightType);
523         if (boxedRightType == nullptr) {
524             ThrowTypeError("Invalid right-hand side expression", pos);
525         }
526         right->AddBoxingUnboxingFlags(GetBoxingFlag(boxedRightType));
527         return FindLeastUpperBound(nonNullishLeftType, boxedRightType);
528     }
529 
530     return FindLeastUpperBound(nonNullishLeftType, rightType);
531 }
532 
533 using CheckBinaryFunction = std::function<checker::Type *(
534     ETSChecker *, ir::Expression *left, ir::Expression *right, lexer::TokenType operationType,
535     lexer::SourcePosition pos, bool isEqualOp, checker::Type *const leftType, checker::Type *const rightType,
536     Type *unboxedL, Type *unboxedR)>;
537 
GetCheckMap()538 std::map<lexer::TokenType, CheckBinaryFunction> &GetCheckMap()
539 {
540     static std::map<lexer::TokenType, CheckBinaryFunction> checkMap = {
541         {lexer::TokenType::PUNCTUATOR_MULTIPLY, &ETSChecker::CheckBinaryOperatorMulDivMod},
542         {lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod},
543         {lexer::TokenType::PUNCTUATOR_DIVIDE, &ETSChecker::CheckBinaryOperatorMulDivMod},
544         {lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod},
545         {lexer::TokenType::PUNCTUATOR_MOD, &ETSChecker::CheckBinaryOperatorMulDivMod},
546         {lexer::TokenType::PUNCTUATOR_MOD_EQUAL, &ETSChecker::CheckBinaryOperatorMulDivMod},
547 
548         {lexer::TokenType::PUNCTUATOR_MINUS, &ETSChecker::CheckBinaryOperatorPlus},
549         {lexer::TokenType::PUNCTUATOR_MINUS_EQUAL, &ETSChecker::CheckBinaryOperatorPlus},
550         {lexer::TokenType::PUNCTUATOR_PLUS, &ETSChecker::CheckBinaryOperatorPlus},
551         {lexer::TokenType::PUNCTUATOR_PLUS_EQUAL, &ETSChecker::CheckBinaryOperatorPlus},
552 
553         {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT, &ETSChecker::CheckBinaryOperatorShift},
554         {lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift},
555         {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT, &ETSChecker::CheckBinaryOperatorShift},
556         {lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift},
557         {lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT, &ETSChecker::CheckBinaryOperatorShift},
558         {lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL, &ETSChecker::CheckBinaryOperatorShift},
559 
560         {lexer::TokenType::PUNCTUATOR_BITWISE_OR, &ETSChecker::CheckBinaryOperatorBitwise},
561         {lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise},
562         {lexer::TokenType::PUNCTUATOR_BITWISE_AND, &ETSChecker::CheckBinaryOperatorBitwise},
563         {lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise},
564         {lexer::TokenType::PUNCTUATOR_BITWISE_XOR, &ETSChecker::CheckBinaryOperatorBitwise},
565         {lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL, &ETSChecker::CheckBinaryOperatorBitwise},
566     };
567 
568     return checkMap;
569 }
570 
571 struct BinaryOperatorParams {
572     ir::Expression *left;
573     ir::Expression *right;
574     ir::Expression *expr;
575     lexer::TokenType operationType;
576     lexer::SourcePosition pos;
577     bool isEqualOp;
578 };
579 
580 struct TypeParams {
581     checker::Type *leftType;
582     checker::Type *rightType;
583     Type *unboxedL;
584     Type *unboxedR;
585 };
586 
CheckBinaryOperatorHelper(ETSChecker * checker,const BinaryOperatorParams & binaryParams,const TypeParams & typeParams)587 static std::tuple<Type *, Type *> CheckBinaryOperatorHelper(ETSChecker *checker,
588                                                             const BinaryOperatorParams &binaryParams,
589                                                             const TypeParams &typeParams)
590 {
591     ir::Expression *left = binaryParams.left;
592     ir::Expression *right = binaryParams.right;
593     lexer::SourcePosition pos = binaryParams.pos;
594     checker::Type *const leftType = typeParams.leftType;
595     checker::Type *const rightType = typeParams.rightType;
596     checker::Type *tsType {};
597     switch (binaryParams.operationType) {
598         case lexer::TokenType::PUNCTUATOR_LOGICAL_AND:
599         case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
600             tsType = checker->CheckBinaryOperatorLogical(left, right, binaryParams.expr, pos, leftType, rightType,
601                                                          typeParams.unboxedL, typeParams.unboxedR);
602             break;
603         }
604         case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
605         case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: {
606             return checker->CheckBinaryOperatorStrictEqual(left, pos, leftType, rightType);
607         }
608         case lexer::TokenType::PUNCTUATOR_EQUAL:
609         case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: {
610             std::tuple<Type *, Type *> res =
611                 checker->CheckBinaryOperatorEqual(left, right, binaryParams.operationType, pos, leftType, rightType,
612                                                   typeParams.unboxedL, typeParams.unboxedR);
613             if (!(std::get<0>(res) == nullptr && std::get<1>(res) == nullptr)) {
614                 return res;
615             }
616             [[fallthrough]];
617         }
618         case lexer::TokenType::PUNCTUATOR_LESS_THAN:
619         case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
620         case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
621         case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
622             return checker->CheckBinaryOperatorLessGreater(left, right, binaryParams.operationType, pos,
623                                                            binaryParams.isEqualOp, leftType, rightType,
624                                                            typeParams.unboxedL, typeParams.unboxedR);
625         }
626         case lexer::TokenType::KEYW_INSTANCEOF: {
627             return checker->CheckBinaryOperatorInstanceOf(pos, leftType, rightType);
628         }
629         case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: {
630             tsType = checker->CheckBinaryOperatorNullishCoalescing(right, pos, leftType, rightType);
631             break;
632         }
633         default: {
634             UNREACHABLE();
635             break;
636         }
637     }
638 
639     return {tsType, tsType};
640 }
641 
CheckBinaryOperator(ir::Expression * left,ir::Expression * right,ir::Expression * expr,lexer::TokenType op,lexer::SourcePosition pos,bool forcePromotion)642 std::tuple<Type *, Type *> ETSChecker::CheckBinaryOperator(ir::Expression *left, ir::Expression *right,
643                                                            ir::Expression *expr, lexer::TokenType op,
644                                                            lexer::SourcePosition pos, bool forcePromotion)
645 {
646     checker::Type *const leftType = left->Check(this);
647     checker::Type *const rightType = right->Check(this);
648     if ((leftType == nullptr) || (rightType == nullptr)) {
649         ThrowTypeError("Unexpected type error in binary expression", pos);
650     }
651 
652     const bool isLogicalExtendedOperator =
653         (op == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) || (op == lexer::TokenType::PUNCTUATOR_LOGICAL_OR);
654     Type *unboxedL =
655         isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(leftType) : ETSBuiltinTypeAsPrimitiveType(leftType);
656     Type *unboxedR = isLogicalExtendedOperator ? ETSBuiltinTypeAsConditionalType(rightType)
657                                                : ETSBuiltinTypeAsPrimitiveType(rightType);
658 
659     checker::Type *tsType {};
660     bool isEqualOp =
661         (op > lexer::TokenType::PUNCTUATOR_SUBSTITUTION && op < lexer::TokenType::PUNCTUATOR_ARROW) && !forcePromotion;
662 
663     if (CheckBinaryOperatorForBigInt(leftType, rightType, expr, op)) {
664         switch (op) {
665             case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
666             case lexer::TokenType::PUNCTUATOR_LESS_THAN:
667             case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL:
668             case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
669                 return {GlobalETSBooleanType(), GlobalETSBooleanType()};
670             default:
671                 return {leftType, rightType};
672         }
673     };
674 
675     auto checkMap = GetCheckMap();
676     if (checkMap.find(op) != checkMap.end()) {
677         auto check = checkMap[op];
678         tsType = check(this, left, right, op, pos, isEqualOp, leftType, rightType, unboxedL, unboxedR);
679         return {tsType, tsType};
680     }
681 
682     BinaryOperatorParams binaryParams {left, right, expr, op, pos, isEqualOp};
683     TypeParams typeParams {leftType, rightType, unboxedL, unboxedR};
684     return CheckBinaryOperatorHelper(this, binaryParams, typeParams);
685 }
686 
HandleArithmeticOperationOnTypes(Type * left,Type * right,lexer::TokenType operationType)687 Type *ETSChecker::HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
688 {
689     ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC) &&
690            right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC));
691 
692     if (left->IsDoubleType() || right->IsDoubleType()) {
693         return PerformArithmeticOperationOnTypes<DoubleType>(left, right, operationType);
694     }
695 
696     if (left->IsFloatType() || right->IsFloatType()) {
697         return PerformArithmeticOperationOnTypes<FloatType>(left, right, operationType);
698     }
699 
700     if (left->IsLongType() || right->IsLongType()) {
701         return PerformArithmeticOperationOnTypes<LongType>(left, right, operationType);
702     }
703 
704     return PerformArithmeticOperationOnTypes<IntType>(left, right, operationType);
705 }
706 
HandleBitwiseOperationOnTypes(Type * left,Type * right,lexer::TokenType operationType)707 Type *ETSChecker::HandleBitwiseOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
708 {
709     ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC) &&
710            right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC));
711 
712     if (left->IsDoubleType() || right->IsDoubleType()) {
713         return HandleBitWiseArithmetic<DoubleType, LongType>(left, right, operationType);
714     }
715 
716     if (left->IsFloatType() || right->IsFloatType()) {
717         return HandleBitWiseArithmetic<FloatType, IntType>(left, right, operationType);
718     }
719 
720     if (left->IsLongType() || right->IsLongType()) {
721         return HandleBitWiseArithmetic<LongType>(left, right, operationType);
722     }
723 
724     return HandleBitWiseArithmetic<IntType>(left, right, operationType);
725 }
726 
FlagExpressionWithUnboxing(Type * type,Type * unboxedType,ir::Expression * typeExpression)727 void ETSChecker::FlagExpressionWithUnboxing(Type *type, Type *unboxedType, ir::Expression *typeExpression)
728 {
729     if (type->IsETSObjectType() && (unboxedType != nullptr)) {
730         typeExpression->AddBoxingUnboxingFlags(GetUnboxingFlag(unboxedType));
731     }
732 }
733 
734 }  // namespace panda::es2panda::checker
735