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