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 "ir/expressions/assignmentExpression.h" 17#include "ir/expressions/memberExpression.h" 18 19#include "checker/TSchecker.h" 20 21namespace ark::es2panda::checker { 22 23void TSChecker::CheckBooleanLikeType(Type *leftType, Type *rightType, ir::AstNode *expr, lexer::TokenType op) 24{ 25 if (leftType->HasTypeFlag(TypeFlag::BOOLEAN_LIKE) && rightType->HasTypeFlag(TypeFlag::BOOLEAN_LIKE)) { 26 lexer::TokenType suggestedOp; 27 switch (op) { 28 case lexer::TokenType::PUNCTUATOR_BITWISE_OR: 29 case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { 30 suggestedOp = lexer::TokenType::PUNCTUATOR_LOGICAL_OR; 31 break; 32 } 33 case lexer::TokenType::PUNCTUATOR_BITWISE_AND: 34 case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { 35 suggestedOp = lexer::TokenType::PUNCTUATOR_LOGICAL_AND; 36 break; 37 } 38 case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: 39 case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { 40 suggestedOp = lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL; 41 break; 42 } 43 default: { 44 suggestedOp = lexer::TokenType::EOS; 45 break; 46 } 47 } 48 49 if (suggestedOp != lexer::TokenType::EOS) { 50 ThrowTypeError( 51 {"The ", op, " operator is not allowed for boolean types. Consider using ", suggestedOp, " instead"}, 52 expr->Start()); 53 } 54 } 55} 56Type *TSChecker::CheckBinaryOperator(ExpressionTypeInfo *leftRightType, ir::Expression *leftExpr, 57 ir::Expression *rightExpr, ir::AstNode *expr, lexer::TokenType op) 58{ 59 CheckNonNullType(leftRightType->leftType, leftExpr->Start()); 60 CheckNonNullType(leftRightType->rightType, rightExpr->Start()); 61 62 CheckBooleanLikeType(leftRightType->leftType, leftRightType->rightType, expr, op); 63 64 if (!leftRightType->leftType->HasTypeFlag(TypeFlag::VALID_ARITHMETIC_TYPE)) { 65 ThrowTypeError( 66 "The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an " 67 "enum " 68 "type.", 69 expr->Start()); 70 } 71 72 if (!leftRightType->rightType->HasTypeFlag(TypeFlag::VALID_ARITHMETIC_TYPE)) { 73 ThrowTypeError( 74 "The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an " 75 "enum " 76 "type.", 77 rightExpr->Start()); 78 } 79 80 Type *resultType = nullptr; 81 if ((leftRightType->leftType->IsAnyType() && leftRightType->rightType->IsAnyType()) || 82 !(leftRightType->leftType->HasTypeFlag(TypeFlag::BIGINT_LIKE) || 83 leftRightType->rightType->HasTypeFlag(TypeFlag::BIGINT_LIKE))) { 84 resultType = GlobalNumberType(); 85 } else if (leftRightType->leftType->HasTypeFlag(TypeFlag::BIGINT_LIKE) && 86 leftRightType->rightType->HasTypeFlag(TypeFlag::BIGINT_LIKE)) { 87 if (op == lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT || 88 op == lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL) { 89 ThrowTypeError({"operator ", op, " cannot be applied to types 'bigint' and 'bigint'"}, expr->Start()); 90 } 91 resultType = GlobalBigintType(); 92 } else { 93 ThrowBinaryLikeError(op, leftRightType->leftType, leftRightType->rightType, expr->Start()); 94 } 95 96 CheckAssignmentOperator(op, leftExpr, leftRightType->leftType, resultType); 97 return resultType; 98} 99 100Type *TSChecker::CheckPlusOperator(ExpressionTypeInfo *leftRightType, ir::Expression *leftExpr, 101 ir::Expression *rightExpr, ir::AstNode *expr, lexer::TokenType op) 102{ 103 if (!leftRightType->leftType->HasTypeFlag(TypeFlag::STRING_LIKE) && 104 !leftRightType->rightType->HasTypeFlag(TypeFlag::STRING_LIKE)) { 105 CheckNonNullType(leftRightType->leftType, leftExpr->Start()); 106 CheckNonNullType(leftRightType->rightType, rightExpr->Start()); 107 } 108 109 Type *resultType = nullptr; 110 if (IsTypeAssignableTo(leftRightType->leftType, GlobalNumberType()) && 111 IsTypeAssignableTo(leftRightType->rightType, GlobalNumberType())) { 112 resultType = GlobalNumberType(); 113 } else if (IsTypeAssignableTo(leftRightType->leftType, GlobalBigintType()) && 114 IsTypeAssignableTo(leftRightType->rightType, GlobalBigintType())) { 115 resultType = GlobalBigintType(); 116 } else if (IsTypeAssignableTo(leftRightType->leftType, GlobalStringType()) || 117 IsTypeAssignableTo(leftRightType->rightType, GlobalStringType())) { 118 resultType = GlobalStringType(); 119 } else if (MaybeTypeOfKind(leftRightType->leftType, TypeFlag::UNKNOWN)) { 120 ThrowTypeError("object is of type 'unknown'", leftExpr->Start()); 121 } else if (MaybeTypeOfKind(leftRightType->rightType, TypeFlag::UNKNOWN)) { 122 ThrowTypeError("object is of type 'unknown'", rightExpr->Start()); 123 } else if (leftRightType->leftType->IsAnyType() || leftRightType->rightType->IsAnyType()) { 124 resultType = GlobalAnyType(); 125 } else { 126 ThrowBinaryLikeError(op, leftRightType->leftType, leftRightType->rightType, expr->Start()); 127 } 128 129 if (op == lexer::TokenType::PUNCTUATOR_PLUS_EQUAL) { 130 CheckAssignmentOperator(op, leftExpr, leftRightType->leftType, resultType); 131 } 132 133 return resultType; 134} 135 136Type *TSChecker::CheckCompareOperator(ExpressionTypeInfo *leftRightType, ir::Expression *leftExpr, 137 ir::Expression *rightExpr, ir::AstNode *expr, lexer::TokenType op) 138{ 139 CheckNonNullType(leftRightType->leftType, leftExpr->Start()); 140 CheckNonNullType(leftRightType->rightType, rightExpr->Start()); 141 142 if (AreTypesComparable(leftRightType->leftType, leftRightType->rightType) || 143 (IsTypeAssignableTo(leftRightType->leftType, GlobalNumberOrBigintType()) && 144 IsTypeAssignableTo(leftRightType->rightType, GlobalNumberOrBigintType()))) { 145 return GlobalBooleanType(); 146 } 147 148 ThrowBinaryLikeError(op, leftRightType->leftType, leftRightType->rightType, expr->Start()); 149 150 return GlobalAnyType(); 151} 152 153Type *TSChecker::CheckAndOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr) 154{ 155 CheckTruthinessOfType(leftType, leftExpr->Start()); 156 157 if ((static_cast<uint64_t>(leftType->GetTypeFacts()) & static_cast<uint64_t>(TypeFacts::TRUTHY)) != 0U) { 158 Type *resultType = CreateUnionType({ExtractDefinitelyFalsyTypes(rightType), rightType}); 159 return resultType; 160 } 161 162 return leftType; 163} 164 165Type *TSChecker::CheckOrOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr) 166{ 167 CheckTruthinessOfType(leftType, leftExpr->Start()); 168 169 if ((static_cast<uint64_t>(leftType->GetTypeFacts()) & static_cast<uint64_t>(TypeFacts::FALSY)) != 0U) { 170 // NOTE: aszilagyi. subtype reduction in the result union 171 Type *resultType = CreateUnionType({RemoveDefinitelyFalsyTypes(leftType), rightType}); 172 return resultType; 173 } 174 175 return leftType; 176} 177 178static bool TypeHasCallOrConstructSignatures(Type *type) 179{ 180 return type->IsObjectType() && 181 (!type->AsObjectType()->CallSignatures().empty() || !type->AsObjectType()->ConstructSignatures().empty()); 182} 183 184Type *TSChecker::CheckInstanceofExpression(Type *leftType, Type *rightType, ir::Expression *rightExpr, 185 ir::AstNode *expr) 186{ 187 if (leftType->TypeFlags() != TypeFlag::ANY && IsAllTypesAssignableTo(leftType, GlobalPrimitiveType())) { 188 ThrowTypeError({"The left-hand side of an 'instanceof' expression must be of type 'any',", 189 " an object type or a type parameter."}, 190 expr->Start()); 191 } 192 193 // NOTE: aszilagyi. Check if right type is subtype of globalFunctionType 194 if (rightType->TypeFlags() != TypeFlag::ANY && !TypeHasCallOrConstructSignatures(rightType)) { 195 ThrowTypeError({"The right-hand side of an 'instanceof' expression must be of type 'any'", 196 " or of a type assignable to the 'Function' interface type."}, 197 rightExpr->Start()); 198 } 199 200 return GlobalBooleanType(); 201} 202 203Type *TSChecker::CheckInExpression(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, 204 ir::AstNode *expr) 205{ 206 CheckNonNullType(leftType, leftExpr->Start()); 207 CheckNonNullType(rightType, rightExpr->Start()); 208 209 // NOTE: aszilagyi. Check IsAllTypesAssignableTo with ESSymbol too 210 if (leftType->TypeFlags() != TypeFlag::ANY && !IsAllTypesAssignableTo(leftType, GlobalStringOrNumberType())) { 211 ThrowTypeError( 212 {"The left-hand side of an 'in' expression must be of type 'any',", " 'string', 'number', or 'symbol'."}, 213 expr->Start()); 214 } 215 216 // NOTE: aszilagyi. Handle type parameters 217 if (!IsAllTypesAssignableTo(rightType, GlobalNonPrimitiveType())) { 218 ThrowTypeError("The right-hand side of an 'in' expression must not be a primitive.", rightExpr->Start()); 219 } 220 221 return GlobalBooleanType(); 222} 223 224void TSChecker::CheckAssignmentOperator(lexer::TokenType op, ir::Expression *leftExpr, Type *leftType, Type *valueType) 225{ 226 if (IsAssignmentOperator(op)) { 227 CheckReferenceExpression( 228 leftExpr, "the left hand side of an assignment expression must be a variable or a property access", 229 "The left-hand side of an assignment expression may not be an optional property access."); 230 231 if (!IsTypeAssignableTo(valueType, leftType)) { 232 ThrowAssignmentError(valueType, leftType, leftExpr->Start(), 233 leftExpr->Parent()->AsAssignmentExpression()->Right()->IsMemberExpression() || 234 leftExpr->Parent()->AsAssignmentExpression()->Right()->IsChainExpression()); 235 } 236 } 237} 238} // namespace ark::es2panda::checker 239