• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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