• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "TSAnalyzer.h"
17 
18 #include "checker/TSchecker.h"
19 #include "checker/ts/destructuringContext.h"
20 
21 namespace ark::es2panda::checker {
22 
GetTSChecker() const23 TSChecker *TSAnalyzer::GetTSChecker() const
24 {
25     return static_cast<TSChecker *>(GetChecker());
26 }
27 
28 // from base folder
Check(ir::CatchClause * st) const29 checker::Type *TSAnalyzer::Check(ir::CatchClause *st) const
30 {
31     TSChecker *checker = GetTSChecker();
32     ir::Expression *typeAnnotation = st->Param()->AsAnnotatedExpression()->TypeAnnotation();
33 
34     if (typeAnnotation != nullptr) {
35         checker::Type *catchParamType = typeAnnotation->Check(checker);
36 
37         if (!catchParamType->HasTypeFlag(checker::TypeFlag::ANY_OR_UNKNOWN)) {
38             checker->ThrowTypeError("Catch clause variable type annotation must be 'any' or 'unknown' if specified",
39                                     st->Start());
40         }
41     }
42 
43     st->Body()->Check(checker);
44 
45     return nullptr;
46 }
47 
Check(ir::ClassDefinition * node) const48 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ClassDefinition *node) const
49 {
50     TSChecker *checker = GetTSChecker();
51     // NOTE: aszilagyi.
52     return checker->GlobalAnyType();
53 }
54 
Check(ir::MetaProperty * expr) const55 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::MetaProperty *expr) const
56 {
57     TSChecker *checker = GetTSChecker();
58     // NOTE: aszilagyi.
59     return checker->GlobalAnyType();
60 }
61 
Check(ir::TSIndexSignature * node) const62 checker::Type *TSAnalyzer::Check(ir::TSIndexSignature *node) const
63 {
64     TSChecker *checker = GetTSChecker();
65     if (node->TsType() != nullptr) {
66         return node->TsType();
67     }
68 
69     const util::StringView &paramName = node->Param()->AsIdentifier()->Name();
70     node->typeAnnotation_->Check(checker);
71     checker::Type *indexType = node->typeAnnotation_->GetType(checker);
72     checker::IndexInfo *info =
73         checker->Allocator()->New<checker::IndexInfo>(indexType, paramName, node->Readonly(), node->Start());
74     checker::ObjectDescriptor *desc = checker->Allocator()->New<checker::ObjectDescriptor>(checker->Allocator());
75     checker::ObjectType *placeholder = checker->Allocator()->New<checker::ObjectLiteralType>(desc);
76 
77     if (node->Kind() == ir::TSIndexSignature::TSIndexSignatureKind::NUMBER) {
78         placeholder->Desc()->numberIndexInfo = info;
79     } else {
80         placeholder->Desc()->stringIndexInfo = info;
81     }
82 
83     node->SetTsType(placeholder);
84     return placeholder;
85 }
86 
Check(ir::TSMethodSignature * node) const87 checker::Type *TSAnalyzer::Check(ir::TSMethodSignature *node) const
88 {
89     TSChecker *checker = GetTSChecker();
90     if (node->Computed()) {
91         checker->CheckComputedPropertyName(node->Key());
92     }
93 
94     checker::ScopeContext scopeCtx(checker, node->Scope());
95 
96     auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
97     checker->CheckFunctionParameterDeclarations(node->Params(), signatureInfo);
98 
99     auto *callSignature = checker->Allocator()->New<checker::Signature>(signatureInfo, checker->GlobalAnyType());
100     node->Variable()->SetTsType(checker->CreateFunctionTypeWithSignature(callSignature));
101 
102     auto returnType = node->ReturnTypeAnnotation();
103     if (returnType == nullptr) {
104         checker->ThrowTypeError(
105             "Method signature, which lacks return-type annotation, implicitly has an 'any' return type.",
106             node->Start());
107     }
108 
109     returnType->Check(checker);
110     callSignature->SetReturnType(returnType->GetType(checker));
111 
112     return nullptr;
113 }
114 
Check(ir::TSPropertySignature * node) const115 checker::Type *TSAnalyzer::Check(ir::TSPropertySignature *node) const
116 {
117     TSChecker *checker = GetTSChecker();
118     if (node->TypeAnnotation() != nullptr) {
119         node->TypeAnnotation()->Check(checker);
120     }
121 
122     if (node->Computed()) {
123         checker->CheckComputedPropertyName(node->Key());
124     }
125 
126     if (node->TypeAnnotation() != nullptr) {
127         node->Variable()->SetTsType(node->TypeAnnotation()->GetType(checker));
128         return nullptr;
129     }
130 
131     checker->ThrowTypeError("Property implicitly has an 'any' type.", node->Start());
132     return nullptr;
133 }
134 
Check(ir::TSSignatureDeclaration * node) const135 checker::Type *TSAnalyzer::Check(ir::TSSignatureDeclaration *node) const
136 {
137     TSChecker *checker = GetTSChecker();
138     if (node->TsType() != nullptr) {
139         return node->TsType();
140     }
141 
142     checker::ScopeContext scopeCtx(checker, node->Scope());
143 
144     auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
145     checker->CheckFunctionParameterDeclarations(node->Params(), signatureInfo);
146 
147     bool isCallSignature = (node->Kind() == ir::TSSignatureDeclaration::TSSignatureDeclarationKind::CALL_SIGNATURE);
148 
149     if (node->ReturnTypeAnnotation() == nullptr) {
150         if (isCallSignature) {
151             checker->ThrowTypeError(
152                 "Call signature, which lacks return-type annotation, implicitly has an 'any' return type.",
153                 node->Start());
154         }
155 
156         checker->ThrowTypeError(
157             "Construct signature, which lacks return-type annotation, implicitly has an 'any' return type.",
158             node->Start());
159     }
160 
161     node->ReturnTypeAnnotation()->Check(checker);
162     checker::Type *returnType = node->ReturnTypeAnnotation()->GetType(checker);
163 
164     auto *signature = checker->Allocator()->New<checker::Signature>(signatureInfo, returnType);
165 
166     checker::Type *placeholderObj = nullptr;
167 
168     if (isCallSignature) {
169         placeholderObj = checker->CreateObjectTypeWithCallSignature(signature);
170     } else {
171         placeholderObj = checker->CreateObjectTypeWithConstructSignature(signature);
172     }
173 
174     node->SetTsType(placeholderObj);
175     return placeholderObj;
176 }
177 
GetSpreadElementType(checker::TSChecker * checker,checker::Type * spreadType,ArenaVector<checker::Type * > & elementTypes,const lexer::SourcePosition & loc)178 static void GetSpreadElementType(checker::TSChecker *checker, checker::Type *spreadType,
179                                  ArenaVector<checker::Type *> &elementTypes, const lexer::SourcePosition &loc)
180 {
181     bool inConstContext = checker->HasStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
182 
183     if (spreadType->IsObjectType() && spreadType->AsObjectType()->IsTupleType()) {
184         ArenaVector<checker::Type *> tupleElementTypes(checker->Allocator()->Adapter());
185         checker::TupleType *spreadTuple = spreadType->AsObjectType()->AsTupleType();
186 
187         for (auto *it : spreadTuple->Properties()) {
188             if (inConstContext) {
189                 elementTypes.push_back(it->TsType());
190                 continue;
191             }
192 
193             tupleElementTypes.push_back(it->TsType());
194         }
195 
196         if (inConstContext) {
197             return;
198         }
199 
200         elementTypes.push_back(checker->CreateUnionType(std::move(tupleElementTypes)));
201         return;
202     }
203 
204     if (!spreadType->IsUnionType()) {
205         checker->ThrowTypeError(
206             {"Type '", spreadType, "' must have a '[Symbol.iterator]()' method that returns an iterator."}, loc);
207         return;
208     }
209 
210     ArenaVector<checker::Type *> spreadTypes(checker->Allocator()->Adapter());
211     bool throwError = false;
212 
213     for (auto *type : spreadType->AsUnionType()->ConstituentTypes()) {
214         if (type->IsArrayType()) {
215             spreadTypes.push_back(type->AsArrayType()->ElementType());
216             continue;
217         }
218 
219         if (type->IsObjectType() && type->AsObjectType()->IsTupleType()) {
220             checker::TupleType *tuple = type->AsObjectType()->AsTupleType();
221 
222             for (auto *it : tuple->Properties()) {
223                 spreadTypes.push_back(it->TsType());
224             }
225 
226             continue;
227         }
228 
229         throwError = true;
230         break;
231     }
232 
233     if (!throwError) {
234         elementTypes.push_back(checker->CreateUnionType(std::move(spreadTypes)));
235         return;
236     }
237 
238     checker->ThrowTypeError(
239         {"Type '", spreadType, "' must have a '[Symbol.iterator]()' method that returns an iterator."}, loc);
240 }
241 
Check(ir::ArrayExpression * expr) const242 checker::Type *TSAnalyzer::Check(ir::ArrayExpression *expr) const
243 {
244     TSChecker *checker = GetTSChecker();
245     ArenaVector<checker::Type *> elementTypes(checker->Allocator()->Adapter());
246     ArenaVector<checker::ElementFlags> elementFlags(checker->Allocator()->Adapter());
247     bool inConstContext = checker->HasStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
248     bool createTuple = checker->HasStatus(checker::CheckerStatus::FORCE_TUPLE);
249 
250     for (auto *it : expr->Elements()) {
251         if (it->IsSpreadElement()) {
252             checker::Type *spreadType = it->AsSpreadElement()->Argument()->Check(checker);
253 
254             if (spreadType->IsArrayType()) {
255                 elementTypes.push_back(inConstContext ? spreadType : spreadType->AsArrayType()->ElementType());
256                 elementFlags.push_back(checker::ElementFlags::VARIADIC);
257                 continue;
258             }
259 
260             GetSpreadElementType(checker, spreadType, elementTypes, it->Start());
261             elementFlags.push_back(checker::ElementFlags::REST);
262             continue;
263         }
264 
265         checker::Type *elementType = it->Check(checker);
266 
267         if (!inConstContext) {
268             elementType = checker->GetBaseTypeOfLiteralType(elementType);
269         }
270 
271         elementFlags.push_back(checker::ElementFlags::REQUIRED);
272         elementTypes.push_back(elementType);
273     }
274 
275     if (inConstContext || createTuple) {
276         checker::ObjectDescriptor *desc = checker->Allocator()->New<checker::ObjectDescriptor>(checker->Allocator());
277         uint32_t index = 0;
278 
279         for (auto it = elementTypes.begin(); it != elementTypes.end(); it++, index++) {
280             util::StringView memberIndex = util::Helpers::ToStringView(checker->Allocator(), index);
281             varbinder::LocalVariable *tupleMember = varbinder::Scope::CreateVar(
282                 checker->Allocator(), memberIndex, varbinder::VariableFlags::PROPERTY, nullptr);
283 
284             if (inConstContext) {
285                 tupleMember->AddFlag(varbinder::VariableFlags::READONLY);
286             }
287 
288             tupleMember->SetTsType(*it);
289             desc->properties.push_back(tupleMember);
290         }
291 
292         const checker::TupleTypeInfo tupleTypeInfo = {ElementFlags::REQUIRED, index, index, inConstContext};
293         return checker->CreateTupleType(desc, std::move(elementFlags), tupleTypeInfo);
294     }
295 
296     checker::Type *arrayElementType = nullptr;
297     if (elementTypes.empty()) {
298         arrayElementType = checker->GlobalAnyType();
299     } else {
300         arrayElementType = checker->CreateUnionType(std::move(elementTypes));
301     }
302 
303     return checker->Allocator()->New<checker::ArrayType>(arrayElementType);
304 }
305 
Check(ir::ArrowFunctionExpression * expr) const306 checker::Type *TSAnalyzer::Check(ir::ArrowFunctionExpression *expr) const
307 {
308     TSChecker *checker = GetTSChecker();
309     varbinder::Variable *funcVar = nullptr;
310 
311     if (expr->Function()->Parent()->Parent() != nullptr &&
312         expr->Function()->Parent()->Parent()->IsVariableDeclarator() &&
313         expr->Function()->Parent()->Parent()->AsVariableDeclarator()->Id()->IsIdentifier()) {
314         funcVar = expr->Function()->Parent()->Parent()->AsVariableDeclarator()->Id()->AsIdentifier()->Variable();
315     }
316 
317     checker::ScopeContext scopeCtx(checker, expr->Function()->Scope());
318 
319     auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
320     checker->CheckFunctionParameterDeclarations(expr->Function()->Params(), signatureInfo);
321 
322     auto *signature = checker->Allocator()->New<checker::Signature>(signatureInfo, checker->GlobalResolvingReturnType(),
323                                                                     expr->Function());
324     checker::Type *funcType = checker->CreateFunctionTypeWithSignature(signature);
325 
326     if (funcVar != nullptr && funcVar->TsType() == nullptr) {
327         funcVar->SetTsType(funcType);
328     }
329 
330     signature->SetReturnType(checker->HandleFunctionReturn(expr->Function()));
331 
332     if (!expr->Function()->Body()->IsExpression()) {
333         expr->Function()->Body()->Check(checker);
334     }
335 
336     return funcType;
337 }
338 
CheckAssignmentExprOperatorType(ir::AssignmentExpression * expr,checker::Type * leftType,checker::Type * rightType) const339 checker::Type *TSAnalyzer::CheckAssignmentExprOperatorType(ir::AssignmentExpression *expr, checker::Type *leftType,
340                                                            checker::Type *rightType) const
341 {
342     TSChecker *checker = GetTSChecker();
343     ExpressionTypeInfo leftRightType {};
344     leftRightType.leftType = leftType;
345     leftRightType.rightType = rightType;
346     switch (expr->OperatorType()) {
347         case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL:
348         case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL:
349         case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL:
350         case lexer::TokenType::PUNCTUATOR_MOD_EQUAL:
351         case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL:
352         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL:
353         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL:
354         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL:
355         case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL:
356         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL:
357         case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: {
358             return checker->CheckBinaryOperator(&leftRightType, expr->Left(), expr->Right(), expr,
359                                                 expr->OperatorType());
360         }
361         case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
362             return checker->CheckPlusOperator(&leftRightType, expr->Left(), expr->Right(), expr, expr->OperatorType());
363         }
364         case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
365             checker->CheckAssignmentOperator(expr->OperatorType(), expr->Left(), leftType, rightType);
366             return rightType;
367         }
368         default: {
369             UNREACHABLE();
370             break;
371         }
372     }
373 
374     return nullptr;
375 }
376 
Check(ir::AssignmentExpression * expr) const377 checker::Type *TSAnalyzer::Check(ir::AssignmentExpression *expr) const
378 {
379     TSChecker *checker = GetTSChecker();
380     if (expr->Left()->IsArrayPattern()) {
381         auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
382         auto destructuringContext =
383             checker::ArrayDestructuringContext({checker, expr->Left(), true, true, nullptr, expr->Right()});
384         destructuringContext.Start();
385         return destructuringContext.InferredType();
386     }
387 
388     if (expr->Left()->IsObjectPattern()) {
389         auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
390         auto destructuringContext =
391             checker::ObjectDestructuringContext({checker, expr->Left(), true, true, nullptr, expr->Right()});
392         destructuringContext.Start();
393         return destructuringContext.InferredType();
394     }
395 
396     if (expr->Left()->IsIdentifier() && expr->Left()->AsIdentifier()->Variable() != nullptr &&
397         expr->Left()->AsIdentifier()->Variable()->Declaration()->IsConstDecl()) {
398         checker->ThrowTypeError(
399             {"Cannot assign to ", expr->Left()->AsIdentifier()->Name(), " because it is a constant."},
400             expr->Left()->Start());
401     }
402 
403     auto *leftType = expr->Left()->Check(checker);
404 
405     if (leftType->HasTypeFlag(checker::TypeFlag::READONLY)) {
406         checker->ThrowTypeError("Cannot assign to this property because it is readonly.", expr->Left()->Start());
407     }
408 
409     if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
410         checker->ElaborateElementwise(leftType, expr->Right(), expr->Left()->Start());
411         return checker->CheckTypeCached(expr->Right());
412     }
413 
414     auto *rightType = expr->Right()->Check(checker);
415 
416     return CheckAssignmentExprOperatorType(expr, leftType, rightType);
417 }
418 
Check(ir::AwaitExpression * expr) const419 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::AwaitExpression *expr) const
420 {
421     TSChecker *checker = GetTSChecker();
422     // NOTE(aszilagyi)
423     return checker->GlobalAnyType();
424 }
425 
CheckBinaryExprArithmLogical(ir::BinaryExpression * expr,ExpressionTypeInfo * leftRightType,TSChecker * checker) const426 checker::Type *TSAnalyzer::CheckBinaryExprArithmLogical(ir::BinaryExpression *expr, ExpressionTypeInfo *leftRightType,
427                                                         TSChecker *checker) const
428 {
429     switch (expr->OperatorType()) {
430         case lexer::TokenType::PUNCTUATOR_MULTIPLY:
431         case lexer::TokenType::PUNCTUATOR_EXPONENTIATION:
432         case lexer::TokenType::PUNCTUATOR_DIVIDE:
433         case lexer::TokenType::PUNCTUATOR_MOD:
434         case lexer::TokenType::PUNCTUATOR_MINUS:
435         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
436         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT:
437         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT:
438         case lexer::TokenType::PUNCTUATOR_BITWISE_AND:
439         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR:
440         case lexer::TokenType::PUNCTUATOR_BITWISE_OR: {
441             return checker->CheckBinaryOperator(leftRightType, expr->Left(), expr->Right(), expr, expr->OperatorType());
442         }
443         case lexer::TokenType::PUNCTUATOR_PLUS: {
444             return checker->CheckPlusOperator(leftRightType, expr->Left(), expr->Right(), expr, expr->OperatorType());
445         }
446         case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
447             return checker->CheckAndOperator(leftRightType->leftType, leftRightType->rightType, expr->Left());
448         }
449         case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
450             return checker->CheckOrOperator(leftRightType->leftType, leftRightType->rightType, expr->Left());
451         }
452         default: {
453             return nullptr;
454         }
455     }
456 }
457 
Check(ir::BinaryExpression * expr) const458 checker::Type *TSAnalyzer::Check(ir::BinaryExpression *expr) const
459 {
460     TSChecker *checker = GetTSChecker();
461     ExpressionTypeInfo leftRightType {};
462     leftRightType.leftType = expr->Left()->Check(checker);
463     leftRightType.rightType = expr->Right()->Check(checker);
464 
465     auto *checkBinaryExprPunctuator = CheckBinaryExprArithmLogical(expr, &leftRightType, checker);
466     if (checkBinaryExprPunctuator != nullptr) {
467         return checkBinaryExprPunctuator;
468     }
469 
470     switch (expr->OperatorType()) {
471         case lexer::TokenType::PUNCTUATOR_LESS_THAN:
472         case lexer::TokenType::PUNCTUATOR_GREATER_THAN: {
473             return checker->CheckCompareOperator(&leftRightType, expr->Left(), expr->Right(), expr,
474                                                  expr->OperatorType());
475         }
476         case lexer::TokenType::PUNCTUATOR_EQUAL:
477         case lexer::TokenType::PUNCTUATOR_NOT_EQUAL:
478         case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
479         case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: {
480             if (checker->IsTypeEqualityComparableTo(leftRightType.leftType, leftRightType.rightType) ||
481                 checker->IsTypeEqualityComparableTo(leftRightType.rightType, leftRightType.leftType)) {
482                 return checker->GlobalBooleanType();
483             }
484 
485             checker->ThrowBinaryLikeError(expr->OperatorType(), leftRightType.leftType, leftRightType.rightType,
486                                           expr->Start());
487         }
488         case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: {
489             // NOTE: Csaba Repasi. Implement checker for nullish coalescing
490             return checker->GlobalAnyType();
491         }
492         case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
493             checker->CheckAssignmentOperator(expr->OperatorType(), expr->Left(), leftRightType.leftType,
494                                              leftRightType.rightType);
495             return leftRightType.rightType;
496         }
497         case lexer::TokenType::KEYW_INSTANCEOF: {
498             return checker->CheckInstanceofExpression(leftRightType.leftType, leftRightType.rightType, expr->Right(),
499                                                       expr);
500         }
501         case lexer::TokenType::KEYW_IN: {
502             return checker->CheckInExpression(leftRightType.leftType, leftRightType.rightType, expr->Left(),
503                                               expr->Right(), expr);
504         }
505         default: {
506             UNREACHABLE();
507             break;
508         }
509     }
510 
511     return nullptr;
512 }
513 
Check(ir::CallExpression * expr) const514 checker::Type *TSAnalyzer::Check(ir::CallExpression *expr) const
515 {
516     TSChecker *checker = GetTSChecker();
517     checker::Type *calleeType = expr->callee_->Check(checker);
518 
519     // NOTE: aszilagyi. handle optional chain
520     if (calleeType->IsObjectType()) {
521         checker::ObjectType *calleeObj = calleeType->AsObjectType();
522         return checker->ResolveCallOrNewExpression(calleeObj->CallSignatures(), expr->Arguments(), expr->Start());
523     }
524 
525     checker->ThrowTypeError("This expression is not callable.", expr->Start());
526     return nullptr;
527 }
528 
Check(ir::ChainExpression * expr) const529 checker::Type *TSAnalyzer::Check(ir::ChainExpression *expr) const
530 {
531     TSChecker *checker = GetTSChecker();
532     return expr->expression_->Check(checker);
533 }
534 
Check(ir::ConditionalExpression * expr) const535 checker::Type *TSAnalyzer::Check(ir::ConditionalExpression *expr) const
536 {
537     TSChecker *checker = GetTSChecker();
538     checker::Type *testType = expr->Test()->Check(checker);
539 
540     checker->CheckTruthinessOfType(testType, expr->Test()->Start());
541     checker->CheckTestingKnownTruthyCallableOrAwaitableType(expr->Test(), testType, expr->Consequent());
542 
543     checker::Type *consequentType = expr->Consequent()->Check(checker);
544     checker::Type *alternateType = expr->Alternate()->Check(checker);
545 
546     return checker->CreateUnionType({consequentType, alternateType});
547 }
548 
Check(ir::FunctionExpression * expr) const549 checker::Type *TSAnalyzer::Check(ir::FunctionExpression *expr) const
550 {
551     TSChecker *checker = GetTSChecker();
552     varbinder::Variable *funcVar = nullptr;
553 
554     if (expr->Function()->Parent()->Parent() != nullptr &&
555         expr->Function()->Parent()->Parent()->IsVariableDeclarator() &&
556         expr->Function()->Parent()->Parent()->AsVariableDeclarator()->Id()->IsIdentifier()) {
557         funcVar = expr->Function()->Parent()->Parent()->AsVariableDeclarator()->Id()->AsIdentifier()->Variable();
558     }
559 
560     checker::ScopeContext scopeCtx(checker, expr->Function()->Scope());
561 
562     auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
563     checker->CheckFunctionParameterDeclarations(expr->Function()->Params(), signatureInfo);
564 
565     auto *signature = checker->Allocator()->New<checker::Signature>(signatureInfo, checker->GlobalResolvingReturnType(),
566                                                                     expr->Function());
567     checker::Type *funcType = checker->CreateFunctionTypeWithSignature(signature);
568 
569     if (funcVar != nullptr && funcVar->TsType() == nullptr) {
570         funcVar->SetTsType(funcType);
571     }
572 
573     signature->SetReturnType(checker->HandleFunctionReturn(expr->Function()));
574 
575     expr->Function()->Body()->Check(checker);
576 
577     return funcType;
578 }
579 
Check(ir::Identifier * expr) const580 checker::Type *TSAnalyzer::Check(ir::Identifier *expr) const
581 {
582     TSChecker *checker = GetTSChecker();
583     if (expr->Variable() == nullptr) {
584         if (expr->Name().Is("undefined")) {
585             return checker->GlobalUndefinedType();
586         }
587 
588         checker->ThrowTypeError({"Cannot find name ", expr->Name()}, expr->Start());
589     }
590 
591     const varbinder::Decl *decl = expr->Variable()->Declaration();
592 
593     if (decl->IsTypeAliasDecl() || decl->IsInterfaceDecl()) {
594         checker->ThrowTypeError({expr->Name(), " only refers to a type, but is being used as a value here."},
595                                 expr->Start());
596     }
597 
598     expr->SetTsType(checker->GetTypeOfVariable(expr->Variable()));
599     return expr->TsType();
600 }
601 
CheckComputed(ir::MemberExpression * expr,checker::Type * indexType) const602 void TSAnalyzer::CheckComputed(ir::MemberExpression *expr, checker::Type *indexType) const
603 {
604     TSChecker *checker = GetTSChecker();
605     if (!indexType->HasTypeFlag(checker::TypeFlag::STRING_LIKE | checker::TypeFlag::NUMBER_LIKE)) {
606         checker->ThrowTypeError({"Type ", indexType, " cannot be used as index type"}, expr->Property()->Start());
607     }
608 
609     if (indexType->IsNumberType()) {
610         checker->ThrowTypeError("No index signature with a parameter of type 'string' was found on type this type",
611                                 expr->Start());
612     }
613 
614     if (indexType->IsStringType()) {
615         checker->ThrowTypeError("No index signature with a parameter of type 'number' was found on type this type",
616                                 expr->Start());
617     }
618 
619     switch (expr->Property()->Type()) {
620         case ir::AstNodeType::IDENTIFIER: {
621             checker->ThrowTypeError(
622                 {"Property ", expr->Property()->AsIdentifier()->Name(), " does not exist on this type."},
623                 expr->Property()->Start());
624         }
625         case ir::AstNodeType::NUMBER_LITERAL: {
626             checker->ThrowTypeError(
627                 {"Property ", expr->Property()->AsNumberLiteral()->Str(), " does not exist on this type."},
628                 expr->Property()->Start());
629         }
630         case ir::AstNodeType::STRING_LITERAL: {
631             checker->ThrowTypeError(
632                 {"Property ", expr->Property()->AsStringLiteral()->Str(), " does not exist on this type."},
633                 expr->Property()->Start());
634         }
635         default: {
636             UNREACHABLE();
637         }
638     }
639 }
640 
Check(ir::MemberExpression * expr) const641 checker::Type *TSAnalyzer::Check(ir::MemberExpression *expr) const
642 {
643     TSChecker *checker = GetTSChecker();
644     checker::Type *baseType = checker->CheckNonNullType(expr->Object()->Check(checker), expr->Object()->Start());
645 
646     if (expr->IsComputed()) {
647         checker::Type *indexType = expr->Property()->Check(checker);
648         checker::Type *indexedAccessType = checker->GetPropertyTypeForIndexType(baseType, indexType);
649 
650         if (indexedAccessType != nullptr) {
651             return indexedAccessType;
652         }
653         CheckComputed(expr, indexType);
654     }
655 
656     varbinder::Variable *prop = checker->GetPropertyOfType(baseType, expr->Property()->AsIdentifier()->Name());
657 
658     if (prop != nullptr) {
659         checker::Type *propType = checker->GetTypeOfVariable(prop);
660         if (prop->HasFlag(varbinder::VariableFlags::READONLY)) {
661             propType->AddTypeFlag(checker::TypeFlag::READONLY);
662         }
663 
664         return propType;
665     }
666 
667     if (baseType->IsObjectType()) {
668         checker::ObjectType *objType = baseType->AsObjectType();
669 
670         if (objType->StringIndexInfo() != nullptr) {
671             checker::Type *indexType = objType->StringIndexInfo()->GetType();
672             if (objType->StringIndexInfo()->Readonly()) {
673                 indexType->AddTypeFlag(checker::TypeFlag::READONLY);
674             }
675 
676             return indexType;
677         }
678     }
679 
680     checker->ThrowTypeError({"Property ", expr->Property()->AsIdentifier()->Name(), " does not exist on this type."},
681                             expr->Property()->Start());
682     return nullptr;
683 }
684 
Check(ir::NewExpression * expr) const685 checker::Type *TSAnalyzer::Check(ir::NewExpression *expr) const
686 {
687     TSChecker *checker = GetTSChecker();
688     checker::Type *calleeType = expr->callee_->Check(checker);
689 
690     if (calleeType->IsObjectType()) {
691         checker::ObjectType *calleeObj = calleeType->AsObjectType();
692         return checker->ResolveCallOrNewExpression(calleeObj->ConstructSignatures(), expr->Arguments(), expr->Start());
693     }
694 
695     checker->ThrowTypeError("This expression is not callable.", expr->Start());
696     return nullptr;
697 }
GetPropertyName(const ir::Expression * key)698 static const util::StringView &GetPropertyName(const ir::Expression *key)
699 {
700     if (key->IsIdentifier()) {
701         return key->AsIdentifier()->Name();
702     }
703 
704     if (key->IsStringLiteral()) {
705         return key->AsStringLiteral()->Str();
706     }
707 
708     ASSERT(key->IsNumberLiteral());
709     return key->AsNumberLiteral()->Str();
710 }
711 
GetFlagsForProperty(const ir::Property * prop)712 static varbinder::VariableFlags GetFlagsForProperty(const ir::Property *prop)
713 {
714     if (!prop->IsMethod()) {
715         return varbinder::VariableFlags::PROPERTY;
716     }
717 
718     varbinder::VariableFlags propFlags = varbinder::VariableFlags::METHOD;
719 
720     if (prop->IsAccessor() && prop->Kind() == ir::PropertyKind::GET) {
721         propFlags |= varbinder::VariableFlags::READONLY;
722     }
723 
724     return propFlags;
725 }
726 
GetTypeForProperty(ir::Property * prop,checker::TSChecker * checker)727 static checker::Type *GetTypeForProperty(ir::Property *prop, checker::TSChecker *checker)
728 {
729     if (prop->IsAccessor()) {
730         checker::Type *funcType = prop->Value()->Check(checker);
731 
732         if (prop->Kind() == ir::PropertyKind::SET) {
733             return checker->GlobalAnyType();
734         }
735 
736         ASSERT(funcType->IsObjectType() && funcType->AsObjectType()->IsFunctionType());
737         return funcType->AsObjectType()->CallSignatures()[0]->ReturnType();
738     }
739 
740     if (prop->IsShorthand()) {
741         return prop->Key()->Check(checker);
742     }
743 
744     return prop->Value()->Check(checker);
745 }
746 
CheckSpread(std::unordered_map<util::StringView,lexer::SourcePosition> & allPropertiesMap,checker::ObjectDescriptor * desc,ir::Expression * it) const747 void TSAnalyzer::CheckSpread(std::unordered_map<util::StringView, lexer::SourcePosition> &allPropertiesMap,
748                              checker::ObjectDescriptor *desc, ir::Expression *it) const
749 {
750     TSChecker *checker = GetTSChecker();
751     ASSERT(it->IsSpreadElement());
752 
753     checker::Type *const spreadType = it->AsSpreadElement()->Argument()->Check(checker);
754 
755     // NOTE: aszilagyi. handle union of object types
756     if (!spreadType->IsObjectType()) {
757         checker->ThrowTypeError("Spread types may only be created from object types.", it->Start());
758     }
759 
760     for (auto *spreadProp : spreadType->AsObjectType()->Properties()) {
761         auto found = allPropertiesMap.find(spreadProp->Name());
762         if (found != allPropertiesMap.end()) {
763             checker->ThrowTypeError({found->first, " is specified more than once, so this usage will be overwritten."},
764                                     found->second);
765         }
766 
767         varbinder::LocalVariable *foundMember = desc->FindProperty(spreadProp->Name());
768 
769         if (foundMember != nullptr) {
770             foundMember->SetTsType(spreadProp->TsType());
771             continue;
772         }
773 
774         desc->properties.push_back(spreadProp);
775     }
776 }
777 
CheckNonComputed(checker::ObjectDescriptor * desc,ir::Expression * it,std::unordered_map<util::StringView,lexer::SourcePosition> & allPropertiesMap,bool inConstContext) const778 void TSAnalyzer::CheckNonComputed(checker::ObjectDescriptor *desc, ir::Expression *it,
779                                   std::unordered_map<util::StringView, lexer::SourcePosition> &allPropertiesMap,
780                                   bool inConstContext) const
781 {
782     TSChecker *checker = GetTSChecker();
783     auto *prop = it->AsProperty();
784     checker::Type *propType = GetTypeForProperty(prop, checker);
785     varbinder::VariableFlags flags = GetFlagsForProperty(prop);
786     const util::StringView &propName = GetPropertyName(prop->Key());
787 
788     auto *memberVar = varbinder::Scope::CreateVar(checker->Allocator(), propName, flags, it);
789 
790     if (inConstContext) {
791         memberVar->AddFlag(varbinder::VariableFlags::READONLY);
792     } else {
793         propType = checker->GetBaseTypeOfLiteralType(propType);
794     }
795 
796     memberVar->SetTsType(propType);
797 
798     if (prop->Key()->IsNumberLiteral()) {
799         memberVar->AddFlag(varbinder::VariableFlags::NUMERIC_NAME);
800     }
801 
802     varbinder::LocalVariable *foundMember = desc->FindProperty(propName);
803     allPropertiesMap.insert({propName, it->Start()});
804 
805     if (foundMember != nullptr) {
806         foundMember->SetTsType(propType);
807         return;
808     }
809 
810     desc->properties.push_back(memberVar);
811 }
812 
CreateUnionTypeHelper(ArenaVector<checker::Type * > & computedPropTypes,bool inConstContext) const813 checker::IndexInfo *TSAnalyzer::CreateUnionTypeHelper(ArenaVector<checker::Type *> &computedPropTypes,
814                                                       bool inConstContext) const
815 {
816     TSChecker *checker = GetTSChecker();
817 
818     return checker->Allocator()->New<checker::IndexInfo>(checker->CreateUnionType(std::move(computedPropTypes)), "x",
819                                                          inConstContext);
820 }
821 
Check(ir::ObjectExpression * expr) const822 checker::Type *TSAnalyzer::Check(ir::ObjectExpression *expr) const
823 {
824     TSChecker *checker = GetTSChecker();
825 
826     checker::ObjectDescriptor *desc = checker->Allocator()->New<checker::ObjectDescriptor>(checker->Allocator());
827     std::unordered_map<util::StringView, lexer::SourcePosition> allPropertiesMap;
828     bool inConstContext = checker->HasStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
829     ArenaVector<checker::Type *> computedNumberPropTypes(checker->Allocator()->Adapter());
830     ArenaVector<checker::Type *> computedStringPropTypes(checker->Allocator()->Adapter());
831     bool hasComputedNumberProperty = false;
832     bool hasComputedStringProperty = false;
833     bool seenSpread = false;
834 
835     for (auto *it : expr->Properties()) {
836         if (it->IsProperty()) {
837             auto *prop = it->AsProperty();
838 
839             if (prop->IsComputed() && checker->CheckComputedPropertyName(prop->Key())->IsNumberType()) {
840                 hasComputedNumberProperty = true;
841                 computedNumberPropTypes.push_back(prop->Value()->Check(checker));
842                 continue;
843             }
844 
845             if (prop->IsComputed() && checker->CheckComputedPropertyName(prop->Key())->IsStringType()) {
846                 hasComputedStringProperty = true;
847                 computedStringPropTypes.push_back(prop->Value()->Check(checker));
848                 continue;
849             }
850 
851             CheckNonComputed(desc, it, allPropertiesMap, inConstContext);
852         }
853 
854         if (it->IsSpreadElement()) {
855             CheckSpread(allPropertiesMap, desc, it);
856             seenSpread = true;
857         }
858     }
859 
860     if (!seenSpread && (hasComputedNumberProperty || hasComputedStringProperty)) {
861         for (auto *it : desc->properties) {
862             computedStringPropTypes.push_back(it->TsType());
863 
864             if (hasComputedNumberProperty && it->HasFlag(varbinder::VariableFlags::NUMERIC_NAME)) {
865                 computedNumberPropTypes.push_back(it->TsType());
866             }
867         }
868 
869         if (hasComputedNumberProperty) {
870             desc->numberIndexInfo = CreateUnionTypeHelper(computedNumberPropTypes, inConstContext);
871         }
872 
873         if (hasComputedStringProperty) {
874             desc->stringIndexInfo = CreateUnionTypeHelper(computedStringPropTypes, inConstContext);
875         }
876     }
877 
878     checker::Type *returnType = checker->Allocator()->New<checker::ObjectLiteralType>(desc);
879     returnType->AsObjectType()->AddObjectFlag(checker::ObjectFlags::RESOLVED_MEMBERS |
880                                               checker::ObjectFlags::CHECK_EXCESS_PROPS);
881     return returnType;
882 }
883 
Check(ir::OmittedExpression * expr) const884 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::OmittedExpression *expr) const
885 {
886     TSChecker *checker = GetTSChecker();
887     return checker->GlobalUndefinedType();
888 }
889 
Check(ir::OpaqueTypeNode * expr) const890 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::OpaqueTypeNode *expr) const
891 {
892     return expr->TsType();
893 }
894 
Check(ir::SequenceExpression * expr) const895 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::SequenceExpression *expr) const
896 {
897     TSChecker *checker = GetTSChecker();
898     // NOTE: aszilagyi.
899     return checker->GlobalAnyType();
900 }
901 
Check(ir::SuperExpression * expr) const902 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::SuperExpression *expr) const
903 {
904     TSChecker *checker = GetTSChecker();
905     // NOTE: aszilagyi.
906     return checker->GlobalAnyType();
907 }
908 
Check(ir::TaggedTemplateExpression * expr) const909 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TaggedTemplateExpression *expr) const
910 {
911     TSChecker *checker = GetTSChecker();
912     // NOTE: aszilagyi.
913     return checker->GlobalAnyType();
914 }
915 
Check(ir::TemplateLiteral * expr) const916 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TemplateLiteral *expr) const
917 {
918     TSChecker *checker = GetTSChecker();
919     // NOTE(aszilagyi)
920     return checker->GlobalAnyType();
921 }
922 
Check(ir::ThisExpression * expr) const923 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ThisExpression *expr) const
924 {
925     TSChecker *checker = GetTSChecker();
926     // NOTE: aszilagyi
927     return checker->GlobalAnyType();
928 }
929 
Check(ir::TypeofExpression * expr) const930 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TypeofExpression *expr) const
931 {
932     TSChecker *checker = GetTSChecker();
933     return checker->GlobalStringType();
934 }
935 
CheckDeleteKeyword(checker::TSChecker * checker,ir::UnaryExpression * expr) const936 checker::Type *TSAnalyzer::CheckDeleteKeyword([[maybe_unused]] checker::TSChecker *checker,
937                                               ir::UnaryExpression *expr) const
938 {
939     checker::Type *propType = expr->argument_->Check(checker);
940     if (!expr->Argument()->IsMemberExpression()) {
941         checker->ThrowTypeError("The operand of a delete operator must be a property reference.",
942                                 expr->Argument()->Start());
943     }
944     if (propType->Variable()->HasFlag(varbinder::VariableFlags::READONLY)) {
945         checker->ThrowTypeError("The operand of a delete operator cannot be a readonly property.",
946                                 expr->Argument()->Start());
947     }
948     if (!propType->Variable()->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
949         checker->ThrowTypeError("The operand of a delete operator must be a optional.", expr->Argument()->Start());
950     }
951     return checker->GlobalBooleanType();
952 }
953 
CheckLiteral(checker::TSChecker * checker,ir::UnaryExpression * expr) const954 checker::Type *TSAnalyzer::CheckLiteral([[maybe_unused]] checker::TSChecker *checker, ir::UnaryExpression *expr) const
955 {
956     if (!expr->Argument()->IsLiteral()) {
957         return nullptr;
958     }
959 
960     const ir::Literal *lit = expr->Argument()->AsLiteral();
961     if (lit->IsNumberLiteral()) {
962         auto numberValue = lit->AsNumberLiteral()->Number().GetDouble();
963         if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS) {
964             return checker->CreateNumberLiteralType(numberValue);
965         }
966         if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_MINUS) {
967             return checker->CreateNumberLiteralType(-numberValue);
968         }
969     } else if (lit->IsBigIntLiteral() && expr->OperatorType() == lexer::TokenType::PUNCTUATOR_MINUS) {
970         return checker->CreateBigintLiteralType(lit->AsBigIntLiteral()->Str(), true);
971     }
972 
973     return nullptr;
974 }
975 
Check(ir::UnaryExpression * expr) const976 checker::Type *TSAnalyzer::Check(ir::UnaryExpression *expr) const
977 {
978     TSChecker *checker = GetTSChecker();
979     checker::Type *operandType = expr->argument_->Check(checker);
980 
981     if (expr->operator_ == lexer::TokenType::KEYW_TYPEOF) {
982         return operandType;
983     }
984 
985     if (expr->operator_ == lexer::TokenType::KEYW_DELETE) {
986         return CheckDeleteKeyword(checker, expr);
987     }
988 
989     auto *res = CheckLiteral(checker, expr);
990     if (res != nullptr) {
991         return res;
992     }
993 
994     switch (expr->operator_) {
995         case lexer::TokenType::PUNCTUATOR_PLUS:
996         case lexer::TokenType::PUNCTUATOR_MINUS:
997         case lexer::TokenType::PUNCTUATOR_TILDE: {
998             checker->CheckNonNullType(operandType, expr->Start());
999             // NOTE: aszilagyi. check Symbol like types
1000 
1001             if (expr->operator_ == lexer::TokenType::PUNCTUATOR_PLUS) {
1002                 if (checker::TSChecker::MaybeTypeOfKind(operandType, checker::TypeFlag::BIGINT_LIKE)) {
1003                     checker->ThrowTypeError({"Operator '+' cannot be applied to type '", operandType, "'"},
1004                                             expr->Start());
1005                 }
1006 
1007                 return checker->GlobalNumberType();
1008             }
1009 
1010             return checker->GetUnaryResultType(operandType);
1011         }
1012         case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: {
1013             checker->CheckTruthinessOfType(operandType, expr->Start());
1014             auto facts = operandType->GetTypeFacts();
1015             if ((facts & checker::TypeFacts::TRUTHY) != 0) {
1016                 return checker->GlobalFalseType();
1017             }
1018 
1019             if ((facts & checker::TypeFacts::FALSY) != 0) {
1020                 return checker->GlobalTrueType();
1021             }
1022 
1023             return checker->GlobalBooleanType();
1024         }
1025         default: {
1026             UNREACHABLE();
1027         }
1028     }
1029 
1030     return nullptr;
1031 }
1032 
Check(ir::UpdateExpression * expr) const1033 checker::Type *TSAnalyzer::Check(ir::UpdateExpression *expr) const
1034 {
1035     TSChecker *checker = GetTSChecker();
1036     checker::Type *operandType = expr->argument_->Check(checker);
1037     checker->CheckNonNullType(operandType, expr->Start());
1038 
1039     if (!operandType->HasTypeFlag(checker::TypeFlag::VALID_ARITHMETIC_TYPE)) {
1040         checker->ThrowTypeError("An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type.",
1041                                 expr->Start());
1042     }
1043 
1044     checker->CheckReferenceExpression(
1045         expr->argument_, "The operand of an increment or decrement operator must be a variable or a property access",
1046         "The operand of an increment or decrement operator may not be an optional property access");
1047 
1048     return checker->GetUnaryResultType(operandType);
1049 }
1050 
Check(ir::YieldExpression * expr) const1051 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::YieldExpression *expr) const
1052 {
1053     TSChecker *checker = GetTSChecker();
1054     // NOTE: aszilagyi.
1055     return checker->GlobalAnyType();
1056 }
1057 // compile methods for LITERAL EXPRESSIONS in alphabetical order
Check(ir::BigIntLiteral * expr) const1058 checker::Type *TSAnalyzer::Check(ir::BigIntLiteral *expr) const
1059 {
1060     TSChecker *checker = GetTSChecker();
1061     auto search = checker->BigintLiteralMap().find(expr->Str());
1062     if (search != checker->BigintLiteralMap().end()) {
1063         return search->second;
1064     }
1065 
1066     auto *newBigintLiteralType = checker->Allocator()->New<checker::BigintLiteralType>(expr->Str(), false);
1067     checker->BigintLiteralMap().insert({expr->Str(), newBigintLiteralType});
1068     return newBigintLiteralType;
1069 }
1070 
Check(ir::BooleanLiteral * expr) const1071 checker::Type *TSAnalyzer::Check(ir::BooleanLiteral *expr) const
1072 {
1073     TSChecker *checker = GetTSChecker();
1074     return expr->Value() ? checker->GlobalTrueType() : checker->GlobalFalseType();
1075 }
1076 
Check(ir::NullLiteral * expr) const1077 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::NullLiteral *expr) const
1078 {
1079     TSChecker *checker = GetTSChecker();
1080     return checker->GlobalNullType();
1081 }
1082 
Check(ir::NumberLiteral * expr) const1083 checker::Type *TSAnalyzer::Check(ir::NumberLiteral *expr) const
1084 {
1085     TSChecker *checker = GetTSChecker();
1086     auto search = checker->NumberLiteralMap().find(expr->Number().GetDouble());
1087     if (search != checker->NumberLiteralMap().end()) {
1088         return search->second;
1089     }
1090 
1091     auto *newNumLiteralType = checker->Allocator()->New<checker::NumberLiteralType>(expr->Number().GetDouble());
1092     checker->NumberLiteralMap().insert({expr->Number().GetDouble(), newNumLiteralType});
1093     return newNumLiteralType;
1094 }
1095 
Check(ir::RegExpLiteral * expr) const1096 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::RegExpLiteral *expr) const
1097 {
1098     TSChecker *checker = GetTSChecker();
1099     // NOTE: aszilagyi
1100     return checker->GlobalAnyType();
1101 }
1102 
Check(ir::AnnotationDeclaration * expr) const1103 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::AnnotationDeclaration *expr) const
1104 {
1105     return nullptr;
1106 }
1107 
Check(ir::AnnotationUsage * expr) const1108 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::AnnotationUsage *expr) const
1109 {
1110     return nullptr;
1111 }
1112 
Check(ir::StringLiteral * expr) const1113 checker::Type *TSAnalyzer::Check(ir::StringLiteral *expr) const
1114 {
1115     TSChecker *checker = GetTSChecker();
1116     auto search = checker->StringLiteralMap().find(expr->Str());
1117     if (search != checker->StringLiteralMap().end()) {
1118         return search->second;
1119     }
1120 
1121     auto *newStrLiteralType = checker->Allocator()->New<checker::StringLiteralType>(expr->Str());
1122     checker->StringLiteralMap().insert({expr->Str(), newStrLiteralType});
1123 
1124     return newStrLiteralType;
1125 }
1126 
Check(ir::BlockStatement * st) const1127 checker::Type *TSAnalyzer::Check(ir::BlockStatement *st) const
1128 {
1129     TSChecker *checker = GetTSChecker();
1130     checker::ScopeContext scopeCtx(checker, st->Scope());
1131 
1132     for (auto *it : st->Statements()) {
1133         it->Check(checker);
1134     }
1135 
1136     return nullptr;
1137 }
1138 
Check(ir::BreakStatement * st) const1139 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::BreakStatement *st) const
1140 {
1141     return nullptr;
1142 }
1143 
Check(ir::DoWhileStatement * st) const1144 checker::Type *TSAnalyzer::Check(ir::DoWhileStatement *st) const
1145 {
1146     TSChecker *checker = GetTSChecker();
1147     checker::ScopeContext scopeCtx(checker, st->Scope());
1148 
1149     checker::Type *testType = st->Test()->Check(checker);
1150     checker->CheckTruthinessOfType(testType, st->Test()->Start());
1151     st->Body()->Check(checker);
1152 
1153     return nullptr;
1154 }
1155 
Check(ir::EmptyStatement * st) const1156 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::EmptyStatement *st) const
1157 {
1158     return nullptr;
1159 }
1160 
Check(ir::ExpressionStatement * st) const1161 checker::Type *TSAnalyzer::Check(ir::ExpressionStatement *st) const
1162 {
1163     TSChecker *checker = GetTSChecker();
1164     return st->GetExpression()->Check(checker);
1165 }
1166 
Check(ir::ForUpdateStatement * st) const1167 checker::Type *TSAnalyzer::Check(ir::ForUpdateStatement *st) const
1168 {
1169     TSChecker *checker = GetTSChecker();
1170     checker::ScopeContext scopeCtx(checker, st->Scope());
1171 
1172     if (st->Init() != nullptr) {
1173         st->Init()->Check(checker);
1174     }
1175 
1176     if (st->Test() != nullptr) {
1177         checker::Type *testType = st->Test()->Check(checker);
1178         checker->CheckTruthinessOfType(testType, st->Start());
1179     }
1180 
1181     if (st->Update() != nullptr) {
1182         st->Update()->Check(checker);
1183     }
1184 
1185     st->Body()->Check(checker);
1186 
1187     return nullptr;
1188 }
1189 
Check(ir::FunctionDeclaration * st) const1190 checker::Type *TSAnalyzer::Check(ir::FunctionDeclaration *st) const
1191 {
1192     TSChecker *checker = GetTSChecker();
1193     if (st->Function()->IsOverload()) {
1194         return nullptr;
1195     }
1196 
1197     const util::StringView &funcName = st->Function()->Id()->Name();
1198     auto result = checker->Scope()->Find(funcName);
1199     ASSERT(result.variable);
1200 
1201     checker::ScopeContext scopeCtx(checker, st->Function()->Scope());
1202 
1203     if (result.variable->TsType() == nullptr) {
1204         checker->InferFunctionDeclarationType(result.variable->Declaration()->AsFunctionDecl(), result.variable);
1205     }
1206 
1207     st->Function()->Body()->Check(checker);
1208 
1209     return nullptr;
1210 }
1211 
Check(ir::IfStatement * st) const1212 checker::Type *TSAnalyzer::Check(ir::IfStatement *st) const
1213 {
1214     TSChecker *checker = GetTSChecker();
1215     checker::Type *testType = st->Test()->Check(checker);
1216     checker->CheckTruthinessOfType(testType, st->Start());
1217     checker->CheckTestingKnownTruthyCallableOrAwaitableType(st->Test(), testType, st->Consequent());
1218 
1219     st->Consequent()->Check(checker);
1220 
1221     if (st->Alternate() != nullptr) {
1222         st->Alternate()->Check(checker);
1223     }
1224 
1225     return nullptr;
1226 }
1227 
Check(ir::ReturnStatement * st) const1228 checker::Type *TSAnalyzer::Check(ir::ReturnStatement *st) const
1229 {
1230     TSChecker *checker = GetTSChecker();
1231     ir::AstNode *ancestor = util::Helpers::FindAncestorGivenByType(st, ir::AstNodeType::SCRIPT_FUNCTION);
1232     ASSERT(ancestor && ancestor->IsScriptFunction());
1233     auto *containingFunc = ancestor->AsScriptFunction();
1234 
1235     if (containingFunc->Parent()->Parent()->IsMethodDefinition()) {
1236         const ir::MethodDefinition *containingClassMethod = containingFunc->Parent()->Parent()->AsMethodDefinition();
1237         if (containingClassMethod->Kind() == ir::MethodDefinitionKind::SET) {
1238             checker->ThrowTypeError("Setters cannot return a value", st->Start());
1239         }
1240     }
1241 
1242     if (containingFunc->ReturnTypeAnnotation() != nullptr) {
1243         checker::Type *returnType = checker->GlobalUndefinedType();
1244         checker::Type *funcReturnType = containingFunc->ReturnTypeAnnotation()->GetType(checker);
1245 
1246         if (st->Argument() != nullptr) {
1247             checker->ElaborateElementwise(funcReturnType, st->Argument(), st->Start());
1248             returnType = checker->CheckTypeCached(st->Argument());
1249         }
1250 
1251         checker->IsTypeAssignableTo(returnType, funcReturnType,
1252                                     {"Type '", returnType, "' is not assignable to type '", funcReturnType, "'."},
1253                                     st->Start());
1254     }
1255 
1256     return nullptr;
1257 }
1258 
Check(ir::SwitchStatement * st) const1259 checker::Type *TSAnalyzer::Check(ir::SwitchStatement *st) const
1260 {
1261     TSChecker *checker = GetTSChecker();
1262     checker::ScopeContext scopeCtx(checker, st->Scope());
1263 
1264     checker::Type *exprType = st->Discriminant()->Check(checker);
1265     bool exprIsLiteral = checker::TSChecker::IsLiteralType(exprType);
1266 
1267     for (auto *it : st->Cases()) {
1268         if (it->Test() != nullptr) {
1269             checker::Type *caseType = it->Test()->Check(checker);
1270             bool caseIsLiteral = checker::TSChecker::IsLiteralType(caseType);
1271             checker::Type *comparedExprType = exprType;
1272 
1273             if (!caseIsLiteral || !exprIsLiteral) {
1274                 caseType = caseIsLiteral ? checker->GetBaseTypeOfLiteralType(caseType) : caseType;
1275                 comparedExprType = checker->GetBaseTypeOfLiteralType(exprType);
1276             }
1277 
1278             if (!checker->IsTypeEqualityComparableTo(comparedExprType, caseType) &&
1279                 !checker->IsTypeComparableTo(caseType, comparedExprType)) {
1280                 checker->ThrowTypeError({"Type ", caseType, " is not comparable to type ", comparedExprType},
1281                                         it->Test()->Start());
1282             }
1283         }
1284 
1285         for (auto *caseStmt : it->Consequent()) {
1286             caseStmt->Check(checker);
1287         }
1288     }
1289 
1290     return nullptr;
1291 }
1292 
Check(ir::TryStatement * st) const1293 checker::Type *TSAnalyzer::Check(ir::TryStatement *st) const
1294 {
1295     TSChecker *checker = GetTSChecker();
1296     st->Block()->Check(checker);
1297 
1298     for (auto *catchClause : st->CatchClauses()) {
1299         if (catchClause != nullptr) {
1300             catchClause->Check(checker);
1301         }
1302     }
1303 
1304     if (st->HasFinalizer()) {
1305         st->finalizer_->Check(checker);
1306     }
1307 
1308     return nullptr;
1309 }
1310 
CheckSimpleVariableDeclaration(checker::TSChecker * checker,ir::VariableDeclarator * declarator)1311 static void CheckSimpleVariableDeclaration(checker::TSChecker *checker, ir::VariableDeclarator *declarator)
1312 {
1313     varbinder::Variable *const bindingVar = declarator->Id()->AsIdentifier()->Variable();
1314     checker::Type *previousType = bindingVar->TsType();
1315     auto *const typeAnnotation = declarator->Id()->AsIdentifier()->TypeAnnotation();
1316     auto *const initializer = declarator->Init();
1317     const bool isConst = declarator->Parent()->AsVariableDeclaration()->Kind() ==
1318                          ir::VariableDeclaration::VariableDeclarationKind::CONST;
1319 
1320     if (isConst) {
1321         checker->AddStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
1322     }
1323 
1324     if (typeAnnotation != nullptr) {
1325         typeAnnotation->Check(checker);
1326     }
1327 
1328     if (typeAnnotation != nullptr && initializer != nullptr) {
1329         checker::Type *const annotationType = typeAnnotation->GetType(checker);
1330         checker->ElaborateElementwise(annotationType, initializer, declarator->Id()->Start());
1331         bindingVar->SetTsType(annotationType);
1332     } else if (typeAnnotation != nullptr) {
1333         bindingVar->SetTsType(typeAnnotation->GetType(checker));
1334     } else if (initializer != nullptr) {
1335         checker::Type *initializerType = checker->CheckTypeCached(initializer);
1336 
1337         if (!isConst) {
1338             initializerType = checker->GetBaseTypeOfLiteralType(initializerType);
1339         }
1340 
1341         if (initializerType->IsNullType()) {
1342             checker->ThrowTypeError(
1343                 {"Cannot infer type for variable '", declarator->Id()->AsIdentifier()->Name(), "'."},
1344                 declarator->Id()->Start());
1345         }
1346 
1347         bindingVar->SetTsType(initializerType);
1348     } else {
1349         checker->ThrowTypeError({"Variable ", declarator->Id()->AsIdentifier()->Name(), " implicitly has an any type."},
1350                                 declarator->Id()->Start());
1351     }
1352 
1353     if (previousType != nullptr) {
1354         checker->IsTypeIdenticalTo(bindingVar->TsType(), previousType,
1355                                    {"Subsequent variable declaration must have the same type. Variable '",
1356                                     bindingVar->Name(), "' must be of type '", previousType, "', but here has type '",
1357                                     bindingVar->TsType(), "'."},
1358                                    declarator->Id()->Start());
1359     }
1360 
1361     checker->RemoveStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
1362 }
1363 
Check(ir::VariableDeclarator * st) const1364 checker::Type *TSAnalyzer::Check(ir::VariableDeclarator *st) const
1365 {
1366     TSChecker *checker = GetTSChecker();
1367 
1368     if (st->TsType() == st->CHECKED) {
1369         return nullptr;
1370     }
1371 
1372     if (st->Id()->IsIdentifier()) {
1373         CheckSimpleVariableDeclaration(checker, st);
1374         st->SetTsType(st->CHECKED);
1375         return nullptr;
1376     }
1377 
1378     if (st->Id()->IsArrayPattern()) {
1379         auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
1380         checker::ArrayDestructuringContext({checker, st->Id(), false,
1381                                             st->Id()->AsArrayPattern()->TypeAnnotation() == nullptr,
1382                                             st->Id()->AsArrayPattern()->TypeAnnotation(), st->Init()})
1383             .Start();
1384 
1385         st->SetTsType(st->CHECKED);
1386         return nullptr;
1387     }
1388 
1389     ASSERT(st->Id()->IsObjectPattern());
1390     auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
1391     checker::ObjectDestructuringContext({checker, st->Id(), false,
1392                                          st->Id()->AsObjectPattern()->TypeAnnotation() == nullptr,
1393                                          st->Id()->AsObjectPattern()->TypeAnnotation(), st->Init()})
1394         .Start();
1395 
1396     st->SetTsType(st->CHECKED);
1397     return nullptr;
1398 }
1399 
Check(ir::VariableDeclaration * st) const1400 checker::Type *TSAnalyzer::Check(ir::VariableDeclaration *st) const
1401 {
1402     TSChecker *checker = GetTSChecker();
1403     for (auto *it : st->Declarators()) {
1404         it->Check(checker);
1405     }
1406 
1407     return nullptr;
1408 }
1409 
Check(ir::WhileStatement * st) const1410 checker::Type *TSAnalyzer::Check(ir::WhileStatement *st) const
1411 {
1412     TSChecker *checker = GetTSChecker();
1413     checker::ScopeContext scopeCtx(checker, st->Scope());
1414 
1415     checker::Type *testType = st->Test()->Check(checker);
1416     checker->CheckTruthinessOfType(testType, st->Test()->Start());
1417 
1418     st->Body()->Check(checker);
1419     return nullptr;
1420 }
1421 // from ts folder
Check(ir::TSAnyKeyword * node) const1422 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSAnyKeyword *node) const
1423 {
1424     return nullptr;
1425 }
1426 
Check(ir::TSArrayType * node) const1427 checker::Type *TSAnalyzer::Check(ir::TSArrayType *node) const
1428 {
1429     TSChecker *checker = GetTSChecker();
1430     node->elementType_->Check(checker);
1431     return nullptr;
1432 }
1433 
IsValidConstAssertionArgument(checker::Checker * checker,const ir::AstNode * arg)1434 static bool IsValidConstAssertionArgument(checker::Checker *checker, const ir::AstNode *arg)
1435 {
1436     switch (arg->Type()) {
1437         case ir::AstNodeType::NUMBER_LITERAL:
1438         case ir::AstNodeType::STRING_LITERAL:
1439         case ir::AstNodeType::BIGINT_LITERAL:
1440         case ir::AstNodeType::BOOLEAN_LITERAL:
1441         case ir::AstNodeType::ARRAY_EXPRESSION:
1442         case ir::AstNodeType::OBJECT_EXPRESSION:
1443         case ir::AstNodeType::TEMPLATE_LITERAL: {
1444             return true;
1445         }
1446         case ir::AstNodeType::UNARY_EXPRESSION: {
1447             const ir::UnaryExpression *unaryExpr = arg->AsUnaryExpression();
1448             lexer::TokenType op = unaryExpr->OperatorType();
1449             const ir::Expression *unaryArg = unaryExpr->Argument();
1450             return (op == lexer::TokenType::PUNCTUATOR_MINUS && unaryArg->IsLiteral() &&
1451                     (unaryArg->AsLiteral()->IsNumberLiteral() || unaryArg->AsLiteral()->IsBigIntLiteral())) ||
1452                    (op == lexer::TokenType::PUNCTUATOR_PLUS && unaryArg->IsLiteral() &&
1453                     unaryArg->AsLiteral()->IsNumberLiteral());
1454         }
1455         case ir::AstNodeType::MEMBER_EXPRESSION: {
1456             const ir::MemberExpression *memberExpr = arg->AsMemberExpression();
1457             if (memberExpr->Object()->IsIdentifier()) {
1458                 auto result = checker->Scope()->Find(memberExpr->Object()->AsIdentifier()->Name());
1459                 constexpr auto ENUM_LITERAL_TYPE = checker::EnumLiteralType::EnumLiteralTypeKind::LITERAL;
1460                 if (result.variable != nullptr &&
1461                     result.variable->TsType()->HasTypeFlag(checker::TypeFlag::ENUM_LITERAL) &&
1462                     result.variable->TsType()->AsEnumLiteralType()->Kind() == ENUM_LITERAL_TYPE) {
1463                     return true;
1464                 }
1465             }
1466             return false;
1467         }
1468         default:
1469             return false;
1470     }
1471 }
1472 
Check(ir::TSAsExpression * expr) const1473 checker::Type *TSAnalyzer::Check(ir::TSAsExpression *expr) const
1474 {
1475     TSChecker *checker = GetTSChecker();
1476     if (expr->IsConst()) {
1477         auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_CONST_CONTEXT);
1478         checker::Type *exprType = expr->Expr()->Check(checker);
1479 
1480         if (!IsValidConstAssertionArgument(checker, expr->Expr())) {
1481             checker->ThrowTypeError(
1482                 "A 'const' assertions can only be applied to references to enum members, or string, number, "
1483                 "boolean, array, or object literals.",
1484                 expr->Expr()->Start());
1485         }
1486 
1487         return exprType;
1488     }
1489 
1490     auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::NO_OPTS);
1491 
1492     expr->TypeAnnotation()->Check(checker);
1493     checker::Type *exprType = checker->GetBaseTypeOfLiteralType(expr->Expr()->Check(checker));
1494     checker::Type *targetType = expr->TypeAnnotation()->GetType(checker);
1495 
1496     checker->IsTypeComparableTo(
1497         targetType, exprType,
1498         {"Conversion of type '", exprType, "' to type '", targetType,
1499          "' may be a mistake because neither type sufficiently overlaps with the other. If this was ",
1500          "intentional, convert the expression to 'unknown' first."},
1501         expr->Start());
1502 
1503     return targetType;
1504 }
1505 
Check(ir::TSBigintKeyword * node) const1506 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSBigintKeyword *node) const
1507 {
1508     return nullptr;
1509 }
1510 
Check(ir::TSBooleanKeyword * node) const1511 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSBooleanKeyword *node) const
1512 {
1513     return nullptr;
1514 }
1515 
Check(ir::TSConstructorType * node) const1516 checker::Type *TSAnalyzer::Check(ir::TSConstructorType *node) const
1517 {
1518     TSChecker *checker = GetTSChecker();
1519     checker::ScopeContext scopeCtx(checker, node->Scope());
1520 
1521     auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
1522     checker->CheckFunctionParameterDeclarations(node->Params(), signatureInfo);
1523     node->ReturnType()->Check(checker);
1524     auto *constructSignature =
1525         checker->Allocator()->New<checker::Signature>(signatureInfo, node->ReturnType()->GetType(checker));
1526 
1527     return checker->CreateConstructorTypeWithSignature(constructSignature);
1528 }
1529 
EvaluateIdentifier(checker::TSChecker * checker,varbinder::EnumVariable * enumVar,const ir::Identifier * expr)1530 static varbinder::EnumMemberResult EvaluateIdentifier(checker::TSChecker *checker, varbinder::EnumVariable *enumVar,
1531                                                       const ir::Identifier *expr)
1532 {
1533     if (expr->Name() == "NaN") {
1534         return std::nan("");
1535     }
1536     if (expr->Name() == "Infinity") {
1537         return std::numeric_limits<double>::infinity();
1538     }
1539 
1540     varbinder::Variable *enumMember = expr->AsIdentifier()->Variable();
1541 
1542     if (enumMember == nullptr) {
1543         checker->ThrowTypeError({"Cannot find name ", expr->AsIdentifier()->Name()},
1544                                 enumVar->Declaration()->Node()->Start());
1545     }
1546 
1547     if (enumMember->IsEnumVariable()) {
1548         varbinder::EnumVariable *exprEnumVar = enumMember->AsEnumVariable();
1549         if (std::holds_alternative<bool>(exprEnumVar->Value())) {
1550             checker->ThrowTypeError(
1551                 "A member initializer in a enum declaration cannot reference members declared after it, "
1552                 "including "
1553                 "members defined in other enums.",
1554                 enumVar->Declaration()->Node()->Start());
1555         }
1556 
1557         return exprEnumVar->Value();
1558     }
1559 
1560     return false;
1561 }
1562 
ToInt(double num)1563 static int32_t ToInt(double num)
1564 {
1565     if (num >= std::numeric_limits<int32_t>::min() && num <= std::numeric_limits<int32_t>::max()) {
1566         return static_cast<int32_t>(num);
1567     }
1568 
1569     // NOTE (aszilagyi): Perform ECMA defined toInt conversion
1570 
1571     return 0;
1572 }
1573 
ToUInt(double num)1574 static uint32_t ToUInt(double num)
1575 {
1576     if (num >= std::numeric_limits<uint32_t>::min() && num <= std::numeric_limits<uint32_t>::max()) {
1577         return static_cast<int32_t>(num);
1578     }
1579 
1580     // NOTE (aszilagyi): Perform ECMA defined toInt conversion
1581 
1582     return 0;
1583 }
1584 
GetOperationResulForDouble(lexer::TokenType type,varbinder::EnumMemberResult left,varbinder::EnumMemberResult right)1585 varbinder::EnumMemberResult GetOperationResulForDouble(lexer::TokenType type, varbinder::EnumMemberResult left,
1586                                                        varbinder::EnumMemberResult right)
1587 {
1588     switch (type) {
1589         case lexer::TokenType::PUNCTUATOR_BITWISE_OR: {
1590             return static_cast<double>(ToUInt(std::get<double>(left)) | ToUInt(std::get<double>(right)));
1591         }
1592         case lexer::TokenType::PUNCTUATOR_BITWISE_AND: {
1593             return static_cast<double>(ToUInt(std::get<double>(left)) & ToUInt(std::get<double>(right)));
1594         }
1595         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: {
1596             return static_cast<double>(ToUInt(std::get<double>(left)) ^ ToUInt(std::get<double>(right)));
1597         }
1598         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: {  // NOLINTNEXTLINE(hicpp-signed-bitwise)
1599             return static_cast<double>(ToInt(std::get<double>(left)) << ToUInt(std::get<double>(right)));
1600         }
1601         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: {  // NOLINTNEXTLINE(hicpp-signed-bitwise)
1602             return static_cast<double>(ToInt(std::get<double>(left)) >> ToUInt(std::get<double>(right)));
1603         }
1604         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: {
1605             return static_cast<double>(ToUInt(std::get<double>(left)) >> ToUInt(std::get<double>(right)));
1606         }
1607         case lexer::TokenType::PUNCTUATOR_PLUS: {
1608             return std::get<double>(left) + std::get<double>(right);
1609         }
1610         case lexer::TokenType::PUNCTUATOR_MINUS: {
1611             return std::get<double>(left) - std::get<double>(right);
1612         }
1613         case lexer::TokenType::PUNCTUATOR_MULTIPLY: {
1614             return std::get<double>(left) * std::get<double>(right);
1615         }
1616         case lexer::TokenType::PUNCTUATOR_DIVIDE: {
1617             return std::get<double>(left) / std::get<double>(right);
1618         }
1619         case lexer::TokenType::PUNCTUATOR_MOD: {
1620             return std::fmod(std::get<double>(left), std::get<double>(right));
1621         }
1622         case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: {
1623             return std::pow(std::get<double>(left), std::get<double>(right));
1624         }
1625         default: {
1626             return false;
1627         }
1628     }
1629 }
1630 
EvaluateBinaryExpression(checker::TSChecker * checker,varbinder::EnumVariable * enumVar,const ir::BinaryExpression * expr) const1631 varbinder::EnumMemberResult TSAnalyzer::EvaluateBinaryExpression(checker::TSChecker *checker,
1632                                                                  varbinder::EnumVariable *enumVar,
1633                                                                  const ir::BinaryExpression *expr) const
1634 {
1635     varbinder::EnumMemberResult left = EvaluateEnumMember(checker, enumVar, expr->AsBinaryExpression()->Left());
1636     varbinder::EnumMemberResult right = EvaluateEnumMember(checker, enumVar, expr->AsBinaryExpression()->Right());
1637     if (std::holds_alternative<double>(left) && std::holds_alternative<double>(right)) {
1638         GetOperationResulForDouble(expr->AsBinaryExpression()->OperatorType(), left, right);
1639     }
1640 
1641     if (std::holds_alternative<util::StringView>(left) && std::holds_alternative<util::StringView>(right) &&
1642         expr->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS) {
1643         std::stringstream ss;
1644         ss << std::get<util::StringView>(left) << std::get<util::StringView>(right);
1645 
1646         util::UString res(ss.str(), checker->Allocator());
1647         return res.View();
1648     }
1649 
1650     return false;
1651 }
1652 
EvaluateUnaryExpression(checker::TSChecker * checker,varbinder::EnumVariable * enumVar,const ir::UnaryExpression * expr) const1653 varbinder::EnumMemberResult TSAnalyzer::EvaluateUnaryExpression(checker::TSChecker *checker,
1654                                                                 varbinder::EnumVariable *enumVar,
1655                                                                 const ir::UnaryExpression *expr) const
1656 {
1657     varbinder::EnumMemberResult value = EvaluateEnumMember(checker, enumVar, expr->Argument());
1658     if (!std::holds_alternative<double>(value)) {
1659         return false;
1660     }
1661 
1662     switch (expr->OperatorType()) {
1663         case lexer::TokenType::PUNCTUATOR_PLUS: {
1664             return std::get<double>(value);
1665         }
1666         case lexer::TokenType::PUNCTUATOR_MINUS: {
1667             return -std::get<double>(value);
1668         }
1669         case lexer::TokenType::PUNCTUATOR_TILDE: {
1670             return static_cast<double>(~ToInt(std::get<double>(value)));  // NOLINT(hicpp-signed-bitwise)
1671         }
1672         default: {
1673             break;
1674         }
1675     }
1676 
1677     return false;
1678 }
1679 
EvaluateEnumMember(checker::TSChecker * checker,varbinder::EnumVariable * enumVar,const ir::AstNode * expr) const1680 varbinder::EnumMemberResult TSAnalyzer::EvaluateEnumMember(checker::TSChecker *checker,
1681                                                            varbinder::EnumVariable *enumVar,
1682                                                            const ir::AstNode *expr) const
1683 {
1684     switch (expr->Type()) {
1685         case ir::AstNodeType::UNARY_EXPRESSION: {
1686             return EvaluateUnaryExpression(checker, enumVar, expr->AsUnaryExpression());
1687         }
1688         case ir::AstNodeType::BINARY_EXPRESSION: {
1689             return EvaluateBinaryExpression(checker, enumVar, expr->AsBinaryExpression());
1690         }
1691         case ir::AstNodeType::NUMBER_LITERAL: {
1692             return expr->AsNumberLiteral()->Number().GetDouble();
1693         }
1694         case ir::AstNodeType::STRING_LITERAL: {
1695             return expr->AsStringLiteral()->Str();
1696         }
1697         case ir::AstNodeType::IDENTIFIER: {
1698             return EvaluateIdentifier(checker, enumVar, expr->AsIdentifier());
1699         }
1700         case ir::AstNodeType::MEMBER_EXPRESSION: {
1701             return EvaluateEnumMember(checker, enumVar, expr->AsMemberExpression());
1702         }
1703         default:
1704             break;
1705     }
1706 
1707     return false;
1708 }
1709 
IsComputedEnumMember(const ir::Expression * init)1710 static bool IsComputedEnumMember(const ir::Expression *init)
1711 {
1712     if (init->IsLiteral()) {
1713         return !init->AsLiteral()->IsStringLiteral() && !init->AsLiteral()->IsNumberLiteral();
1714     }
1715 
1716     if (init->IsTemplateLiteral()) {
1717         return !init->AsTemplateLiteral()->Quasis().empty();
1718     }
1719 
1720     return true;
1721 }
1722 
AddEnumValueDeclaration(checker::TSChecker * checker,double number,varbinder::EnumVariable * variable)1723 static void AddEnumValueDeclaration(checker::TSChecker *checker, double number, varbinder::EnumVariable *variable)
1724 {
1725     variable->SetTsType(checker->GlobalNumberType());
1726 
1727     util::StringView memberStr = util::Helpers::ToStringView(checker->Allocator(), number);
1728 
1729     varbinder::LocalScope *enumScope = checker->Scope()->AsLocalScope();
1730     varbinder::Variable *res = enumScope->FindLocal(memberStr, varbinder::ResolveBindingOptions::BINDINGS);
1731     varbinder::EnumVariable *enumVar = nullptr;
1732 
1733     if (res == nullptr) {
1734         auto *decl = checker->Allocator()->New<varbinder::EnumDecl>(memberStr);
1735         decl->BindNode(variable->Declaration()->Node());
1736         enumScope->AddDecl(checker->Allocator(), decl, ScriptExtension::TS);
1737         res = enumScope->FindLocal(memberStr, varbinder::ResolveBindingOptions::BINDINGS);
1738         ASSERT(res && res->IsEnumVariable());
1739         enumVar = res->AsEnumVariable();
1740         enumVar->AsEnumVariable()->SetBackReference();
1741         enumVar->SetTsType(checker->GlobalStringType());
1742     } else {
1743         ASSERT(res->IsEnumVariable());
1744         enumVar = res->AsEnumVariable();
1745         auto *decl = checker->Allocator()->New<varbinder::EnumDecl>(memberStr);
1746         decl->BindNode(variable->Declaration()->Node());
1747         enumVar->ResetDecl(decl);
1748     }
1749 
1750     enumVar->SetValue(variable->Declaration()->Name());
1751 }
1752 
1753 // NOLINTBEGIN(modernize-avoid-c-arrays)
1754 static constexpr char const INVALID_COMPUTED_WITH_STRING[] =
1755     "Computed values are not permitted in an enum with string valued members.";
1756 static constexpr char const INVALID_CONST_MEMBER[] =
1757     "'const' enum member initializers can only contain literal values and other computed enum values.";
1758 static constexpr char const INVALID_CONST_NAN[] =
1759     "'const' enum member initializer was evaluated to disallowed value 'NaN'.";
1760 static constexpr char const INVALID_CONST_INF[] =
1761     "'const' enum member initializer was evaluated to a non-finite value.";
1762 // NOLINTEND(modernize-avoid-c-arrays)
1763 
InferEnumVariableType(varbinder::EnumVariable * variable,double * value,bool * initNext,bool * isLiteralEnum,bool isConstEnum) const1764 void TSAnalyzer::InferEnumVariableType(varbinder::EnumVariable *variable, double *value, bool *initNext,
1765                                        bool *isLiteralEnum, bool isConstEnum) const
1766 {
1767     TSChecker *checker = GetTSChecker();
1768     const ir::Expression *init = variable->Declaration()->Node()->AsTSEnumMember()->Init();
1769 
1770     if (init == nullptr && *initNext) {
1771         checker->ThrowTypeError("Enum member must have initializer.", variable->Declaration()->Node()->Start());
1772     }
1773 
1774     if (init == nullptr && !*initNext) {
1775         variable->SetValue(++(*value));
1776         AddEnumValueDeclaration(checker, *value, variable);
1777         return;
1778     }
1779 
1780     ASSERT(init);
1781     if (IsComputedEnumMember(init) && *isLiteralEnum) {
1782         checker->ThrowTypeError(INVALID_COMPUTED_WITH_STRING, init->Start());
1783     }
1784 
1785     varbinder::EnumMemberResult res = EvaluateEnumMember(checker, variable, init);
1786     if (std::holds_alternative<util::StringView>(res)) {
1787         *isLiteralEnum = true;
1788         variable->SetTsType(checker->GlobalStringType());
1789         *initNext = true;
1790         return;
1791     }
1792 
1793     if (std::holds_alternative<bool>(res)) {
1794         if (isConstEnum) {
1795             checker->ThrowTypeError(INVALID_CONST_MEMBER, init->Start());
1796         }
1797 
1798         *initNext = true;
1799         return;
1800     }
1801 
1802     ASSERT(std::holds_alternative<double>(res));
1803     variable->SetValue(res);
1804 
1805     *value = std::get<double>(res);
1806     if (isConstEnum && std::isnan(*value)) {
1807         checker->ThrowTypeError(INVALID_CONST_NAN, init->Start());
1808     }
1809 
1810     if (isConstEnum && std::isinf(*value)) {
1811         checker->ThrowTypeError(INVALID_CONST_INF, init->Start());
1812     }
1813 
1814     *initNext = false;
1815     AddEnumValueDeclaration(checker, *value, variable);
1816 }
1817 
InferType(checker::TSChecker * checker,bool isConst,ir::TSEnumDeclaration * st) const1818 checker::Type *TSAnalyzer::InferType(checker::TSChecker *checker, bool isConst, ir::TSEnumDeclaration *st) const
1819 {
1820     double value = -1.0;
1821 
1822     varbinder::LocalScope *enumScope = checker->Scope()->AsLocalScope();
1823 
1824     bool initNext = false;
1825     bool isLiteralEnum = false;
1826     size_t localsSize = enumScope->Decls().size();
1827 
1828     for (size_t i = 0; i < localsSize; i++) {
1829         const util::StringView &currentName = enumScope->Decls()[i]->Name();
1830         varbinder::Variable *currentVar = enumScope->FindLocal(currentName, varbinder::ResolveBindingOptions::BINDINGS);
1831         ASSERT(currentVar && currentVar->IsEnumVariable());
1832         InferEnumVariableType(currentVar->AsEnumVariable(), &value, &initNext, &isLiteralEnum, isConst);
1833     }
1834 
1835     checker::Type *enumType = checker->Allocator()->New<checker::EnumLiteralType>(
1836         st->Key()->Name(), checker->Scope(),
1837         isLiteralEnum ? checker::EnumLiteralType::EnumLiteralTypeKind::LITERAL
1838                       : checker::EnumLiteralType::EnumLiteralTypeKind::NUMERIC);
1839 
1840     return enumType;
1841 }
1842 
Check(ir::TSEnumDeclaration * st) const1843 checker::Type *TSAnalyzer::Check(ir::TSEnumDeclaration *st) const
1844 {
1845     TSChecker *checker = GetTSChecker();
1846     varbinder::Variable *enumVar = st->Key()->Variable();
1847     ASSERT(enumVar);
1848 
1849     if (enumVar->TsType() == nullptr) {
1850         checker::ScopeContext scopeCtx(checker, st->Scope());
1851         checker::Type *enumType = InferType(checker, st->IsConst(), st);
1852         enumType->SetVariable(enumVar);
1853         enumVar->SetTsType(enumType);
1854     }
1855 
1856     return nullptr;
1857 }
1858 
Check(ir::TSFunctionType * node) const1859 checker::Type *TSAnalyzer::Check(ir::TSFunctionType *node) const
1860 {
1861     TSChecker *checker = GetTSChecker();
1862     checker::ScopeContext scopeCtx(checker, node->Scope());
1863 
1864     auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
1865     checker->CheckFunctionParameterDeclarations(node->Params(), signatureInfo);
1866     node->ReturnType()->Check(checker);
1867     auto *callSignature =
1868         checker->Allocator()->New<checker::Signature>(signatureInfo, node->ReturnType()->GetType(checker));
1869 
1870     return checker->CreateFunctionTypeWithSignature(callSignature);
1871 }
1872 
Check(ir::TSIndexedAccessType * node) const1873 checker::Type *TSAnalyzer::Check(ir::TSIndexedAccessType *node) const
1874 {
1875     TSChecker *checker = GetTSChecker();
1876     node->objectType_->Check(checker);
1877     node->indexType_->Check(checker);
1878     checker::Type *resolved = node->GetType(checker);
1879 
1880     if (resolved != nullptr) {
1881         return nullptr;
1882     }
1883 
1884     checker::Type *indexType = checker->CheckTypeCached(node->indexType_);
1885 
1886     if (!indexType->HasTypeFlag(checker::TypeFlag::STRING_LIKE | checker::TypeFlag::NUMBER_LIKE)) {
1887         checker->ThrowTypeError({"Type ", indexType, " cannot be used as index type"}, node->IndexType()->Start());
1888     }
1889 
1890     if (indexType->IsNumberType()) {
1891         checker->ThrowTypeError("Type has no matching signature for type 'number'", node->Start());
1892     }
1893 
1894     checker->ThrowTypeError("Type has no matching signature for type 'string'", node->Start());
1895     return nullptr;
1896 }
1897 
Check(ir::TSInterfaceBody * expr) const1898 checker::Type *TSAnalyzer::Check(ir::TSInterfaceBody *expr) const
1899 {
1900     TSChecker *checker = GetTSChecker();
1901     for (auto *it : expr->Body()) {
1902         it->Check(checker);
1903     }
1904 
1905     return nullptr;
1906 }
1907 
CheckInheritedPropertiesAreIdentical(checker::TSChecker * checker,checker::InterfaceType * type,const lexer::SourcePosition & locInfo)1908 static void CheckInheritedPropertiesAreIdentical(checker::TSChecker *checker, checker::InterfaceType *type,
1909                                                  const lexer::SourcePosition &locInfo)
1910 {
1911     checker->GetBaseTypes(type);
1912 
1913     size_t constexpr BASE_SIZE_LIMIT = 2;
1914     if (type->Bases().size() < BASE_SIZE_LIMIT) {
1915         return;
1916     }
1917 
1918     checker->ResolveDeclaredMembers(type);
1919 
1920     checker::InterfacePropertyMap properties;
1921 
1922     for (auto *it : type->Properties()) {
1923         properties.insert({it->Name(), {it, type}});
1924     }
1925 
1926     for (auto *base : type->Bases()) {
1927         checker->ResolveStructuredTypeMembers(base);
1928         ArenaVector<varbinder::LocalVariable *> inheritedProperties(checker->Allocator()->Adapter());
1929         base->AsInterfaceType()->CollectProperties(&inheritedProperties);
1930 
1931         for (auto *inheritedProp : inheritedProperties) {
1932             auto res = properties.find(inheritedProp->Name());
1933             if (res == properties.end()) {
1934                 properties.insert({inheritedProp->Name(), {inheritedProp, base->AsInterfaceType()}});
1935             } else if (res->second.second != type) {
1936                 checker::Type *sourceType = checker->GetTypeOfVariable(inheritedProp);
1937                 checker::Type *targetType = checker->GetTypeOfVariable(res->second.first);
1938                 checker->IsTypeIdenticalTo(sourceType, targetType,
1939                                            {"Interface '", type, "' cannot simultaneously extend types '",
1940                                             res->second.second, "' and '", base->AsInterfaceType(), "'."},
1941                                            locInfo);
1942             }
1943         }
1944     }
1945 }
1946 
Check(ir::TSInterfaceDeclaration * st) const1947 checker::Type *TSAnalyzer::Check(ir::TSInterfaceDeclaration *st) const
1948 {
1949     TSChecker *checker = GetTSChecker();
1950     varbinder::Variable *var = st->Id()->Variable();
1951     ASSERT(var->Declaration()->Node() && var->Declaration()->Node()->IsTSInterfaceDeclaration());
1952 
1953     if (st == var->Declaration()->Node()) {
1954         checker::Type *resolvedType = var->TsType();
1955 
1956         if (resolvedType == nullptr) {
1957             checker::ObjectDescriptor *desc =
1958                 checker->Allocator()->New<checker::ObjectDescriptor>(checker->Allocator());
1959             resolvedType =
1960                 checker->Allocator()->New<checker::InterfaceType>(checker->Allocator(), st->Id()->Name(), desc);
1961             resolvedType->SetVariable(var);
1962             var->SetTsType(resolvedType);
1963         }
1964 
1965         checker::InterfaceType *resolvedInterface = resolvedType->AsObjectType()->AsInterfaceType();
1966         CheckInheritedPropertiesAreIdentical(checker, resolvedInterface, st->Id()->Start());
1967 
1968         for (auto *base : resolvedInterface->Bases()) {
1969             checker->IsTypeAssignableTo(
1970                 resolvedInterface, base,
1971                 {"Interface '", st->Id()->Name(), "' incorrectly extends interface '", base, "'"}, st->Id()->Start());
1972         }
1973 
1974         checker->CheckIndexConstraints(resolvedInterface);
1975     }
1976 
1977     st->Body()->Check(checker);
1978 
1979     return nullptr;
1980 }
1981 
Check(ir::TSLiteralType * node) const1982 checker::Type *TSAnalyzer::Check(ir::TSLiteralType *node) const
1983 {
1984     TSChecker *checker = GetTSChecker();
1985     node->GetType(checker);
1986     return nullptr;
1987 }
1988 
Check(ir::TSNamedTupleMember * node) const1989 checker::Type *TSAnalyzer::Check(ir::TSNamedTupleMember *node) const
1990 {
1991     TSChecker *checker = GetTSChecker();
1992     node->ElementType()->Check(checker);
1993     return nullptr;
1994 }
1995 
Check(ir::TSNeverKeyword * node) const1996 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSNeverKeyword *node) const
1997 {
1998     return nullptr;
1999 }
2000 
Check(ir::TSNullKeyword * node) const2001 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSNullKeyword *node) const
2002 {
2003     return nullptr;
2004 }
2005 
Check(ir::TSNumberKeyword * node) const2006 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSNumberKeyword *node) const
2007 {
2008     return nullptr;
2009 }
2010 
Check(ir::TSParenthesizedType * node) const2011 checker::Type *TSAnalyzer::Check(ir::TSParenthesizedType *node) const
2012 {
2013     TSChecker *checker = GetTSChecker();
2014     node->type_->Check(checker);
2015     return nullptr;
2016 }
2017 
Check(ir::TSQualifiedName * expr) const2018 checker::Type *TSAnalyzer::Check(ir::TSQualifiedName *expr) const
2019 {
2020     TSChecker *checker = GetTSChecker();
2021     checker::Type *baseType = checker->CheckNonNullType(expr->Left()->Check(checker), expr->Left()->Start());
2022     varbinder::Variable *prop = checker->GetPropertyOfType(baseType, expr->Right()->Name());
2023 
2024     if (prop != nullptr) {
2025         return checker->GetTypeOfVariable(prop);
2026     }
2027 
2028     if (baseType->IsObjectType()) {
2029         checker::ObjectType *objType = baseType->AsObjectType();
2030 
2031         if (objType->StringIndexInfo() != nullptr) {
2032             return objType->StringIndexInfo()->GetType();
2033         }
2034     }
2035 
2036     checker->ThrowTypeError({"Property ", expr->Right()->Name(), " does not exist on this type."},
2037                             expr->Right()->Start());
2038     return nullptr;
2039 }
2040 
Check(ir::TSStringKeyword * node) const2041 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSStringKeyword *node) const
2042 {
2043     return nullptr;
2044 }
2045 
Check(ir::TSTupleType * node) const2046 checker::Type *TSAnalyzer::Check(ir::TSTupleType *node) const
2047 {
2048     TSChecker *checker = GetTSChecker();
2049     for (auto *it : node->ElementType()) {
2050         it->Check(checker);
2051     }
2052 
2053     node->GetType(checker);
2054     return nullptr;
2055 }
2056 
Check(ir::TSTypeAliasDeclaration * st) const2057 checker::Type *TSAnalyzer::Check(ir::TSTypeAliasDeclaration *st) const
2058 {
2059     TSChecker *checker = GetTSChecker();
2060     st->TypeAnnotation()->Check(checker);
2061     return nullptr;
2062 }
2063 
Check(ir::TSTypeLiteral * node) const2064 checker::Type *TSAnalyzer::Check(ir::TSTypeLiteral *node) const
2065 {
2066     TSChecker *checker = GetTSChecker();
2067 
2068     for (auto *it : node->Members()) {
2069         it->Check(checker);
2070     }
2071 
2072     checker::Type *type = node->GetType(checker);
2073     checker->CheckIndexConstraints(type);
2074 
2075     return nullptr;
2076 }
2077 
Check(ir::TSTypeQuery * node) const2078 checker::Type *TSAnalyzer::Check(ir::TSTypeQuery *node) const
2079 {
2080     TSChecker *checker = GetTSChecker();
2081     if (node->TsType() != nullptr) {
2082         return node->TsType();
2083     }
2084 
2085     node->SetTsType(node->exprName_->Check(checker));
2086     return node->TsType();
2087 }
2088 
Check(ir::TSTypeReference * node) const2089 checker::Type *TSAnalyzer::Check(ir::TSTypeReference *node) const
2090 {
2091     TSChecker *checker = GetTSChecker();
2092     node->GetType(checker);
2093     return nullptr;
2094 }
2095 
Check(ir::TSUndefinedKeyword * node) const2096 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSUndefinedKeyword *node) const
2097 {
2098     return nullptr;
2099 }
2100 
Check(ir::TSUnionType * node) const2101 checker::Type *TSAnalyzer::Check(ir::TSUnionType *node) const
2102 {
2103     TSChecker *checker = GetTSChecker();
2104     for (auto *it : node->Types()) {
2105         it->Check(checker);
2106     }
2107 
2108     node->GetType(checker);
2109     return nullptr;
2110 }
2111 
Check(ir::TSUnknownKeyword * node) const2112 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSUnknownKeyword *node) const
2113 {
2114     return nullptr;
2115 }
2116 
Check(ir::TSVoidKeyword * node) const2117 checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSVoidKeyword *node) const
2118 {
2119     return nullptr;
2120 }
2121 }  // namespace ark::es2panda::checker
2122