13af6ab5fSopenharmony_ci/** 23af6ab5fSopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License. 53af6ab5fSopenharmony_ci * You may obtain a copy of the License at 63af6ab5fSopenharmony_ci * 73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83af6ab5fSopenharmony_ci * 93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and 133af6ab5fSopenharmony_ci * limitations under the License. 143af6ab5fSopenharmony_ci */ 153af6ab5fSopenharmony_ci 163af6ab5fSopenharmony_ci#include "ir/expressions/assignmentExpression.h" 173af6ab5fSopenharmony_ci#include "ir/expressions/memberExpression.h" 183af6ab5fSopenharmony_ci 193af6ab5fSopenharmony_ci#include "checker/TSchecker.h" 203af6ab5fSopenharmony_ci 213af6ab5fSopenharmony_cinamespace ark::es2panda::checker { 223af6ab5fSopenharmony_ci 233af6ab5fSopenharmony_civoid TSChecker::CheckBooleanLikeType(Type *leftType, Type *rightType, ir::AstNode *expr, lexer::TokenType op) 243af6ab5fSopenharmony_ci{ 253af6ab5fSopenharmony_ci if (leftType->HasTypeFlag(TypeFlag::BOOLEAN_LIKE) && rightType->HasTypeFlag(TypeFlag::BOOLEAN_LIKE)) { 263af6ab5fSopenharmony_ci lexer::TokenType suggestedOp; 273af6ab5fSopenharmony_ci switch (op) { 283af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_BITWISE_OR: 293af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { 303af6ab5fSopenharmony_ci suggestedOp = lexer::TokenType::PUNCTUATOR_LOGICAL_OR; 313af6ab5fSopenharmony_ci break; 323af6ab5fSopenharmony_ci } 333af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_BITWISE_AND: 343af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { 353af6ab5fSopenharmony_ci suggestedOp = lexer::TokenType::PUNCTUATOR_LOGICAL_AND; 363af6ab5fSopenharmony_ci break; 373af6ab5fSopenharmony_ci } 383af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: 393af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { 403af6ab5fSopenharmony_ci suggestedOp = lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL; 413af6ab5fSopenharmony_ci break; 423af6ab5fSopenharmony_ci } 433af6ab5fSopenharmony_ci default: { 443af6ab5fSopenharmony_ci suggestedOp = lexer::TokenType::EOS; 453af6ab5fSopenharmony_ci break; 463af6ab5fSopenharmony_ci } 473af6ab5fSopenharmony_ci } 483af6ab5fSopenharmony_ci 493af6ab5fSopenharmony_ci if (suggestedOp != lexer::TokenType::EOS) { 503af6ab5fSopenharmony_ci ThrowTypeError( 513af6ab5fSopenharmony_ci {"The ", op, " operator is not allowed for boolean types. Consider using ", suggestedOp, " instead"}, 523af6ab5fSopenharmony_ci expr->Start()); 533af6ab5fSopenharmony_ci } 543af6ab5fSopenharmony_ci } 553af6ab5fSopenharmony_ci} 563af6ab5fSopenharmony_ciType *TSChecker::CheckBinaryOperator(ExpressionTypeInfo *leftRightType, ir::Expression *leftExpr, 573af6ab5fSopenharmony_ci ir::Expression *rightExpr, ir::AstNode *expr, lexer::TokenType op) 583af6ab5fSopenharmony_ci{ 593af6ab5fSopenharmony_ci CheckNonNullType(leftRightType->leftType, leftExpr->Start()); 603af6ab5fSopenharmony_ci CheckNonNullType(leftRightType->rightType, rightExpr->Start()); 613af6ab5fSopenharmony_ci 623af6ab5fSopenharmony_ci CheckBooleanLikeType(leftRightType->leftType, leftRightType->rightType, expr, op); 633af6ab5fSopenharmony_ci 643af6ab5fSopenharmony_ci if (!leftRightType->leftType->HasTypeFlag(TypeFlag::VALID_ARITHMETIC_TYPE)) { 653af6ab5fSopenharmony_ci ThrowTypeError( 663af6ab5fSopenharmony_ci "The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an " 673af6ab5fSopenharmony_ci "enum " 683af6ab5fSopenharmony_ci "type.", 693af6ab5fSopenharmony_ci expr->Start()); 703af6ab5fSopenharmony_ci } 713af6ab5fSopenharmony_ci 723af6ab5fSopenharmony_ci if (!leftRightType->rightType->HasTypeFlag(TypeFlag::VALID_ARITHMETIC_TYPE)) { 733af6ab5fSopenharmony_ci ThrowTypeError( 743af6ab5fSopenharmony_ci "The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an " 753af6ab5fSopenharmony_ci "enum " 763af6ab5fSopenharmony_ci "type.", 773af6ab5fSopenharmony_ci rightExpr->Start()); 783af6ab5fSopenharmony_ci } 793af6ab5fSopenharmony_ci 803af6ab5fSopenharmony_ci Type *resultType = nullptr; 813af6ab5fSopenharmony_ci if ((leftRightType->leftType->IsAnyType() && leftRightType->rightType->IsAnyType()) || 823af6ab5fSopenharmony_ci !(leftRightType->leftType->HasTypeFlag(TypeFlag::BIGINT_LIKE) || 833af6ab5fSopenharmony_ci leftRightType->rightType->HasTypeFlag(TypeFlag::BIGINT_LIKE))) { 843af6ab5fSopenharmony_ci resultType = GlobalNumberType(); 853af6ab5fSopenharmony_ci } else if (leftRightType->leftType->HasTypeFlag(TypeFlag::BIGINT_LIKE) && 863af6ab5fSopenharmony_ci leftRightType->rightType->HasTypeFlag(TypeFlag::BIGINT_LIKE)) { 873af6ab5fSopenharmony_ci if (op == lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT || 883af6ab5fSopenharmony_ci op == lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL) { 893af6ab5fSopenharmony_ci ThrowTypeError({"operator ", op, " cannot be applied to types 'bigint' and 'bigint'"}, expr->Start()); 903af6ab5fSopenharmony_ci } 913af6ab5fSopenharmony_ci resultType = GlobalBigintType(); 923af6ab5fSopenharmony_ci } else { 933af6ab5fSopenharmony_ci ThrowBinaryLikeError(op, leftRightType->leftType, leftRightType->rightType, expr->Start()); 943af6ab5fSopenharmony_ci } 953af6ab5fSopenharmony_ci 963af6ab5fSopenharmony_ci CheckAssignmentOperator(op, leftExpr, leftRightType->leftType, resultType); 973af6ab5fSopenharmony_ci return resultType; 983af6ab5fSopenharmony_ci} 993af6ab5fSopenharmony_ci 1003af6ab5fSopenharmony_ciType *TSChecker::CheckPlusOperator(ExpressionTypeInfo *leftRightType, ir::Expression *leftExpr, 1013af6ab5fSopenharmony_ci ir::Expression *rightExpr, ir::AstNode *expr, lexer::TokenType op) 1023af6ab5fSopenharmony_ci{ 1033af6ab5fSopenharmony_ci if (!leftRightType->leftType->HasTypeFlag(TypeFlag::STRING_LIKE) && 1043af6ab5fSopenharmony_ci !leftRightType->rightType->HasTypeFlag(TypeFlag::STRING_LIKE)) { 1053af6ab5fSopenharmony_ci CheckNonNullType(leftRightType->leftType, leftExpr->Start()); 1063af6ab5fSopenharmony_ci CheckNonNullType(leftRightType->rightType, rightExpr->Start()); 1073af6ab5fSopenharmony_ci } 1083af6ab5fSopenharmony_ci 1093af6ab5fSopenharmony_ci Type *resultType = nullptr; 1103af6ab5fSopenharmony_ci if (IsTypeAssignableTo(leftRightType->leftType, GlobalNumberType()) && 1113af6ab5fSopenharmony_ci IsTypeAssignableTo(leftRightType->rightType, GlobalNumberType())) { 1123af6ab5fSopenharmony_ci resultType = GlobalNumberType(); 1133af6ab5fSopenharmony_ci } else if (IsTypeAssignableTo(leftRightType->leftType, GlobalBigintType()) && 1143af6ab5fSopenharmony_ci IsTypeAssignableTo(leftRightType->rightType, GlobalBigintType())) { 1153af6ab5fSopenharmony_ci resultType = GlobalBigintType(); 1163af6ab5fSopenharmony_ci } else if (IsTypeAssignableTo(leftRightType->leftType, GlobalStringType()) || 1173af6ab5fSopenharmony_ci IsTypeAssignableTo(leftRightType->rightType, GlobalStringType())) { 1183af6ab5fSopenharmony_ci resultType = GlobalStringType(); 1193af6ab5fSopenharmony_ci } else if (MaybeTypeOfKind(leftRightType->leftType, TypeFlag::UNKNOWN)) { 1203af6ab5fSopenharmony_ci ThrowTypeError("object is of type 'unknown'", leftExpr->Start()); 1213af6ab5fSopenharmony_ci } else if (MaybeTypeOfKind(leftRightType->rightType, TypeFlag::UNKNOWN)) { 1223af6ab5fSopenharmony_ci ThrowTypeError("object is of type 'unknown'", rightExpr->Start()); 1233af6ab5fSopenharmony_ci } else if (leftRightType->leftType->IsAnyType() || leftRightType->rightType->IsAnyType()) { 1243af6ab5fSopenharmony_ci resultType = GlobalAnyType(); 1253af6ab5fSopenharmony_ci } else { 1263af6ab5fSopenharmony_ci ThrowBinaryLikeError(op, leftRightType->leftType, leftRightType->rightType, expr->Start()); 1273af6ab5fSopenharmony_ci } 1283af6ab5fSopenharmony_ci 1293af6ab5fSopenharmony_ci if (op == lexer::TokenType::PUNCTUATOR_PLUS_EQUAL) { 1303af6ab5fSopenharmony_ci CheckAssignmentOperator(op, leftExpr, leftRightType->leftType, resultType); 1313af6ab5fSopenharmony_ci } 1323af6ab5fSopenharmony_ci 1333af6ab5fSopenharmony_ci return resultType; 1343af6ab5fSopenharmony_ci} 1353af6ab5fSopenharmony_ci 1363af6ab5fSopenharmony_ciType *TSChecker::CheckCompareOperator(ExpressionTypeInfo *leftRightType, ir::Expression *leftExpr, 1373af6ab5fSopenharmony_ci ir::Expression *rightExpr, ir::AstNode *expr, lexer::TokenType op) 1383af6ab5fSopenharmony_ci{ 1393af6ab5fSopenharmony_ci CheckNonNullType(leftRightType->leftType, leftExpr->Start()); 1403af6ab5fSopenharmony_ci CheckNonNullType(leftRightType->rightType, rightExpr->Start()); 1413af6ab5fSopenharmony_ci 1423af6ab5fSopenharmony_ci if (AreTypesComparable(leftRightType->leftType, leftRightType->rightType) || 1433af6ab5fSopenharmony_ci (IsTypeAssignableTo(leftRightType->leftType, GlobalNumberOrBigintType()) && 1443af6ab5fSopenharmony_ci IsTypeAssignableTo(leftRightType->rightType, GlobalNumberOrBigintType()))) { 1453af6ab5fSopenharmony_ci return GlobalBooleanType(); 1463af6ab5fSopenharmony_ci } 1473af6ab5fSopenharmony_ci 1483af6ab5fSopenharmony_ci ThrowBinaryLikeError(op, leftRightType->leftType, leftRightType->rightType, expr->Start()); 1493af6ab5fSopenharmony_ci 1503af6ab5fSopenharmony_ci return GlobalAnyType(); 1513af6ab5fSopenharmony_ci} 1523af6ab5fSopenharmony_ci 1533af6ab5fSopenharmony_ciType *TSChecker::CheckAndOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr) 1543af6ab5fSopenharmony_ci{ 1553af6ab5fSopenharmony_ci CheckTruthinessOfType(leftType, leftExpr->Start()); 1563af6ab5fSopenharmony_ci 1573af6ab5fSopenharmony_ci if ((static_cast<uint64_t>(leftType->GetTypeFacts()) & static_cast<uint64_t>(TypeFacts::TRUTHY)) != 0U) { 1583af6ab5fSopenharmony_ci Type *resultType = CreateUnionType({ExtractDefinitelyFalsyTypes(rightType), rightType}); 1593af6ab5fSopenharmony_ci return resultType; 1603af6ab5fSopenharmony_ci } 1613af6ab5fSopenharmony_ci 1623af6ab5fSopenharmony_ci return leftType; 1633af6ab5fSopenharmony_ci} 1643af6ab5fSopenharmony_ci 1653af6ab5fSopenharmony_ciType *TSChecker::CheckOrOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr) 1663af6ab5fSopenharmony_ci{ 1673af6ab5fSopenharmony_ci CheckTruthinessOfType(leftType, leftExpr->Start()); 1683af6ab5fSopenharmony_ci 1693af6ab5fSopenharmony_ci if ((static_cast<uint64_t>(leftType->GetTypeFacts()) & static_cast<uint64_t>(TypeFacts::FALSY)) != 0U) { 1703af6ab5fSopenharmony_ci // NOTE: aszilagyi. subtype reduction in the result union 1713af6ab5fSopenharmony_ci Type *resultType = CreateUnionType({RemoveDefinitelyFalsyTypes(leftType), rightType}); 1723af6ab5fSopenharmony_ci return resultType; 1733af6ab5fSopenharmony_ci } 1743af6ab5fSopenharmony_ci 1753af6ab5fSopenharmony_ci return leftType; 1763af6ab5fSopenharmony_ci} 1773af6ab5fSopenharmony_ci 1783af6ab5fSopenharmony_cistatic bool TypeHasCallOrConstructSignatures(Type *type) 1793af6ab5fSopenharmony_ci{ 1803af6ab5fSopenharmony_ci return type->IsObjectType() && 1813af6ab5fSopenharmony_ci (!type->AsObjectType()->CallSignatures().empty() || !type->AsObjectType()->ConstructSignatures().empty()); 1823af6ab5fSopenharmony_ci} 1833af6ab5fSopenharmony_ci 1843af6ab5fSopenharmony_ciType *TSChecker::CheckInstanceofExpression(Type *leftType, Type *rightType, ir::Expression *rightExpr, 1853af6ab5fSopenharmony_ci ir::AstNode *expr) 1863af6ab5fSopenharmony_ci{ 1873af6ab5fSopenharmony_ci if (leftType->TypeFlags() != TypeFlag::ANY && IsAllTypesAssignableTo(leftType, GlobalPrimitiveType())) { 1883af6ab5fSopenharmony_ci ThrowTypeError({"The left-hand side of an 'instanceof' expression must be of type 'any',", 1893af6ab5fSopenharmony_ci " an object type or a type parameter."}, 1903af6ab5fSopenharmony_ci expr->Start()); 1913af6ab5fSopenharmony_ci } 1923af6ab5fSopenharmony_ci 1933af6ab5fSopenharmony_ci // NOTE: aszilagyi. Check if right type is subtype of globalFunctionType 1943af6ab5fSopenharmony_ci if (rightType->TypeFlags() != TypeFlag::ANY && !TypeHasCallOrConstructSignatures(rightType)) { 1953af6ab5fSopenharmony_ci ThrowTypeError({"The right-hand side of an 'instanceof' expression must be of type 'any'", 1963af6ab5fSopenharmony_ci " or of a type assignable to the 'Function' interface type."}, 1973af6ab5fSopenharmony_ci rightExpr->Start()); 1983af6ab5fSopenharmony_ci } 1993af6ab5fSopenharmony_ci 2003af6ab5fSopenharmony_ci return GlobalBooleanType(); 2013af6ab5fSopenharmony_ci} 2023af6ab5fSopenharmony_ci 2033af6ab5fSopenharmony_ciType *TSChecker::CheckInExpression(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, 2043af6ab5fSopenharmony_ci ir::AstNode *expr) 2053af6ab5fSopenharmony_ci{ 2063af6ab5fSopenharmony_ci CheckNonNullType(leftType, leftExpr->Start()); 2073af6ab5fSopenharmony_ci CheckNonNullType(rightType, rightExpr->Start()); 2083af6ab5fSopenharmony_ci 2093af6ab5fSopenharmony_ci // NOTE: aszilagyi. Check IsAllTypesAssignableTo with ESSymbol too 2103af6ab5fSopenharmony_ci if (leftType->TypeFlags() != TypeFlag::ANY && !IsAllTypesAssignableTo(leftType, GlobalStringOrNumberType())) { 2113af6ab5fSopenharmony_ci ThrowTypeError( 2123af6ab5fSopenharmony_ci {"The left-hand side of an 'in' expression must be of type 'any',", " 'string', 'number', or 'symbol'."}, 2133af6ab5fSopenharmony_ci expr->Start()); 2143af6ab5fSopenharmony_ci } 2153af6ab5fSopenharmony_ci 2163af6ab5fSopenharmony_ci // NOTE: aszilagyi. Handle type parameters 2173af6ab5fSopenharmony_ci if (!IsAllTypesAssignableTo(rightType, GlobalNonPrimitiveType())) { 2183af6ab5fSopenharmony_ci ThrowTypeError("The right-hand side of an 'in' expression must not be a primitive.", rightExpr->Start()); 2193af6ab5fSopenharmony_ci } 2203af6ab5fSopenharmony_ci 2213af6ab5fSopenharmony_ci return GlobalBooleanType(); 2223af6ab5fSopenharmony_ci} 2233af6ab5fSopenharmony_ci 2243af6ab5fSopenharmony_civoid TSChecker::CheckAssignmentOperator(lexer::TokenType op, ir::Expression *leftExpr, Type *leftType, Type *valueType) 2253af6ab5fSopenharmony_ci{ 2263af6ab5fSopenharmony_ci if (IsAssignmentOperator(op)) { 2273af6ab5fSopenharmony_ci CheckReferenceExpression( 2283af6ab5fSopenharmony_ci leftExpr, "the left hand side of an assignment expression must be a variable or a property access", 2293af6ab5fSopenharmony_ci "The left-hand side of an assignment expression may not be an optional property access."); 2303af6ab5fSopenharmony_ci 2313af6ab5fSopenharmony_ci if (!IsTypeAssignableTo(valueType, leftType)) { 2323af6ab5fSopenharmony_ci ThrowAssignmentError(valueType, leftType, leftExpr->Start(), 2333af6ab5fSopenharmony_ci leftExpr->Parent()->AsAssignmentExpression()->Right()->IsMemberExpression() || 2343af6ab5fSopenharmony_ci leftExpr->Parent()->AsAssignmentExpression()->Right()->IsChainExpression()); 2353af6ab5fSopenharmony_ci } 2363af6ab5fSopenharmony_ci } 2373af6ab5fSopenharmony_ci} 2383af6ab5fSopenharmony_ci} // namespace ark::es2panda::checker 239