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