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