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