• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ETSAnalyzer.h"
17 
18 #include "varbinder/ETSBinder.h"
19 #include "checker/ETSchecker.h"
20 #include "checker/ets/castingContext.h"
21 #include "checker/ets/typeRelationContext.h"
22 #include "util/helpers.h"
23 
24 #include <memory>
25 
26 namespace panda::es2panda::checker {
27 
GetETSChecker() const28 ETSChecker *ETSAnalyzer::GetETSChecker() const
29 {
30     return static_cast<ETSChecker *>(GetChecker());
31 }
32 
33 // from as folder
Check(ir::NamedType * node) const34 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::NamedType *node) const
35 {
36     UNREACHABLE();
37 }
38 
Check(ir::PrefixAssertionExpression * expr) const39 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::PrefixAssertionExpression *expr) const
40 {
41     UNREACHABLE();
42 }
43 // from base folder
Check(ir::CatchClause * st) const44 checker::Type *ETSAnalyzer::Check(ir::CatchClause *st) const
45 {
46     ETSChecker *checker = GetETSChecker();
47     checker::ETSObjectType *exceptionType = checker->GlobalETSObjectType();
48 
49     ir::Identifier *paramIdent = st->Param()->AsIdentifier();
50 
51     if (paramIdent->TypeAnnotation() != nullptr) {
52         checker::Type *catchParamAnnotationType = paramIdent->TypeAnnotation()->GetType(checker);
53 
54         exceptionType = checker->CheckExceptionOrErrorType(catchParamAnnotationType, st->Param()->Start());
55     }
56 
57     paramIdent->Variable()->SetTsType(exceptionType);
58 
59     st->Body()->Check(checker);
60 
61     st->SetTsType(exceptionType);
62     return exceptionType;
63 }
64 
Check(ir::ClassDefinition * node) const65 checker::Type *ETSAnalyzer::Check(ir::ClassDefinition *node) const
66 {
67     ETSChecker *checker = GetETSChecker();
68     if (node->TsType() == nullptr) {
69         checker->BuildClassProperties(node);
70     }
71 
72     checker->CheckClassDefinition(node);
73     return nullptr;
74 }
75 
Check(ir::ClassProperty * st) const76 checker::Type *ETSAnalyzer::Check(ir::ClassProperty *st) const
77 {
78     ASSERT(st->Id() != nullptr);
79     ETSChecker *checker = GetETSChecker();
80 
81     if (st->TsType() != nullptr) {
82         return st->TsType();
83     }
84 
85     checker::SavedCheckerContext savedContext(checker, checker->Context().Status(),
86                                               checker->Context().ContainingClass(),
87                                               checker->Context().ContainingSignature());
88 
89     if (st->IsStatic()) {
90         checker->AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT);
91     }
92 
93     st->SetTsType(checker->CheckVariableDeclaration(st->Id(), st->TypeAnnotation(), st->Value(), st->Modifiers()));
94 
95     return st->TsType();
96 }
97 
Check(ir::ClassStaticBlock * st) const98 checker::Type *ETSAnalyzer::Check(ir::ClassStaticBlock *st) const
99 {
100     ETSChecker *checker = GetETSChecker();
101 
102     if (checker->HasStatus(checker::CheckerStatus::INNER_CLASS)) {
103         checker->ThrowTypeError("Static initializer is not allowed in inner class.", st->Start());
104     }
105 
106     auto *func = st->Function();
107     st->SetTsType(checker->BuildFunctionSignature(func));
108     checker::ScopeContext scopeCtx(checker, func->Scope());
109     checker::SavedCheckerContext savedContext(checker, checker->Context().Status(),
110                                               checker->Context().ContainingClass());
111     checker->AddStatus(checker::CheckerStatus::IN_STATIC_BLOCK | checker::CheckerStatus::IN_STATIC_CONTEXT);
112     func->Body()->Check(checker);
113     return st->TsType();
114 }
115 
Check(ir::Decorator * st) const116 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::Decorator *st) const
117 {
118     UNREACHABLE();
119 }
120 
Check(ir::MetaProperty * expr) const121 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::MetaProperty *expr) const
122 {
123     UNREACHABLE();
124 }
125 
CheckExtensionIsShadowedInCurrentClassOrInterface(checker::ETSChecker * checker,checker::ETSObjectType * objType,ir::ScriptFunction * extensionFunc,checker::Signature * signature)126 static void CheckExtensionIsShadowedInCurrentClassOrInterface(checker::ETSChecker *checker,
127                                                               checker::ETSObjectType *objType,
128                                                               ir::ScriptFunction *extensionFunc,
129                                                               checker::Signature *signature)
130 {
131     const auto methodName = extensionFunc->Id()->Name();
132     // Only check if there are class and interfaces' instance methods which would shadow instance extension method
133     auto *const variable = objType->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>(methodName);
134     if (variable == nullptr) {
135         return;
136     }
137 
138     const auto *const funcType = variable->TsType()->AsETSFunctionType();
139     for (auto *funcSignature : funcType->CallSignatures()) {
140         signature->SetReturnType(funcSignature->ReturnType());
141         if (!checker->Relation()->IsIdenticalTo(signature, funcSignature)) {
142             continue;
143         }
144 
145         checker->ReportWarning({"extension is shadowed by a instance member function '", funcType->Name(),
146                                 funcSignature, "' in class ", objType->Name()},
147                                extensionFunc->Body()->Start());
148         return;
149     }
150 }
151 
CheckExtensionIsShadowedByMethod(checker::ETSChecker * checker,checker::ETSObjectType * objType,ir::ScriptFunction * extensionFunc,checker::Signature * signature)152 static void CheckExtensionIsShadowedByMethod(checker::ETSChecker *checker, checker::ETSObjectType *objType,
153                                              ir::ScriptFunction *extensionFunc, checker::Signature *signature)
154 {
155     if (objType == nullptr) {
156         return;
157     }
158 
159     CheckExtensionIsShadowedInCurrentClassOrInterface(checker, objType, extensionFunc, signature);
160 
161     for (auto *interface : objType->Interfaces()) {
162         CheckExtensionIsShadowedByMethod(checker, interface, extensionFunc, signature);
163     }
164 
165     CheckExtensionIsShadowedByMethod(checker, objType->SuperType(), extensionFunc, signature);
166 }
167 
CheckExtensionMethod(checker::ETSChecker * checker,ir::ScriptFunction * extensionFunc,ir::MethodDefinition * node)168 static void CheckExtensionMethod(checker::ETSChecker *checker, ir::ScriptFunction *extensionFunc,
169                                  ir::MethodDefinition *node)
170 {
171     auto *const classType = ETSChecker::GetApparentType(extensionFunc->Signature()->Params()[0]->TsType());
172     if (!classType->IsETSObjectType() ||
173         (!classType->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::CLASS) &&
174          !classType->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::INTERFACE))) {
175         checker->ThrowTypeError("Extension function can only defined for class and interface type.", node->Start());
176     }
177 
178     checker->AddStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD);
179 
180     checker::SignatureInfo *originalExtensionSigInfo = checker->Allocator()->New<checker::SignatureInfo>(
181         extensionFunc->Signature()->GetSignatureInfo(), checker->Allocator());
182     originalExtensionSigInfo->minArgCount -= 1;
183     originalExtensionSigInfo->params.erase(originalExtensionSigInfo->params.begin());
184     checker::Signature *originalExtensionSigature =
185         checker->CreateSignature(originalExtensionSigInfo, extensionFunc->Signature()->ReturnType(), extensionFunc);
186 
187     CheckExtensionIsShadowedByMethod(checker, classType->AsETSObjectType(), extensionFunc, originalExtensionSigature);
188 }
189 
DoBodyTypeChecking(ETSChecker * checker,ir::MethodDefinition * node,ir::ScriptFunction * scriptFunc)190 void DoBodyTypeChecking(ETSChecker *checker, ir::MethodDefinition *node, ir::ScriptFunction *scriptFunc)
191 {
192     if (scriptFunc->HasBody() && (node->IsNative() || node->IsAbstract() || node->IsDeclare())) {
193         checker->ThrowTypeError("Native, Abstract and Declare methods cannot have body.", scriptFunc->Body()->Start());
194     }
195 
196     if (scriptFunc->IsAsyncFunc()) {
197         auto *retType = static_cast<checker::ETSObjectType *>(scriptFunc->Signature()->ReturnType());
198         if (retType->AssemblerName() != checker->GlobalBuiltinPromiseType()->AssemblerName()) {
199             checker->ThrowTypeError("Return type of async function must be 'Promise'.", scriptFunc->Start());
200         }
201     } else if (scriptFunc->HasBody() && !scriptFunc->IsExternal()) {
202         checker::ScopeContext scopeCtx(checker, scriptFunc->Scope());
203         checker::SavedCheckerContext savedContext(checker, checker->Context().Status(),
204                                                   checker->Context().ContainingClass());
205         checker->Context().SetContainingSignature(checker->GetSignatureFromMethodDefinition(node));
206 
207         if (node->IsStatic() && !node->IsConstructor() &&
208             !checker->Context().ContainingClass()->HasObjectFlag(checker::ETSObjectFlags::GLOBAL)) {
209             checker->AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT);
210         }
211 
212         if (node->IsConstructor()) {
213             checker->AddStatus(checker::CheckerStatus::IN_CONSTRUCTOR);
214         }
215 
216         if (node->IsExtensionMethod()) {
217             CheckExtensionMethod(checker, scriptFunc, node);
218         }
219 
220         scriptFunc->Body()->Check(checker);
221 
222         // In case of inferred function's return type set it forcedly to all return statements;
223         if (scriptFunc->Signature()->HasSignatureFlag(checker::SignatureFlags::INFERRED_RETURN_TYPE) &&
224             scriptFunc->ReturnTypeAnnotation() == nullptr && scriptFunc->Body() != nullptr &&
225             scriptFunc->Body()->IsStatement()) {
226             scriptFunc->Body()->AsStatement()->SetReturnType(checker, scriptFunc->Signature()->ReturnType());
227         }
228 
229         checker->Context().SetContainingSignature(nullptr);
230     }
231 }
232 
CheckGetterSetterTypeConstrains(ETSChecker * checker,ir::ScriptFunction * scriptFunc)233 void CheckGetterSetterTypeConstrains(ETSChecker *checker, ir::ScriptFunction *scriptFunc)
234 {
235     if (scriptFunc->IsSetter() && (scriptFunc->Signature()->ReturnType() != checker->GlobalBuiltinVoidType())) {
236         checker->ThrowTypeError("Setter must have void return type", scriptFunc->Start());
237     }
238 
239     if (scriptFunc->IsGetter() && (scriptFunc->Signature()->ReturnType() == checker->GlobalBuiltinVoidType())) {
240         checker->ThrowTypeError("Getter must return a value", scriptFunc->Start());
241     }
242 
243     auto const name = scriptFunc->Id()->Name();
244     if (name.Is(compiler::Signatures::GET_INDEX_METHOD)) {
245         if (scriptFunc->Signature()->ReturnType() == checker->GlobalBuiltinVoidType()) {
246             checker->ThrowTypeError(std::string {ir::INDEX_ACCESS_ERROR_1} + std::string {name.Utf8()} +
247                                         std::string {"' shouldn't have void return type."},
248                                     scriptFunc->Start());
249         }
250     } else if (name.Is(compiler::Signatures::SET_INDEX_METHOD)) {
251         if (scriptFunc->Signature()->ReturnType() != checker->GlobalBuiltinVoidType()) {
252             checker->ThrowTypeError(std::string {ir::INDEX_ACCESS_ERROR_1} + std::string {name.Utf8()} +
253                                         std::string {"' should have void return type."},
254                                     scriptFunc->Start());
255         }
256     }
257 }
258 
Check(ir::MethodDefinition * node) const259 checker::Type *ETSAnalyzer::Check(ir::MethodDefinition *node) const
260 {
261     ETSChecker *checker = GetETSChecker();
262     auto *scriptFunc = node->Function();
263     if (scriptFunc->IsProxy()) {
264         return nullptr;
265     }
266 
267     // NOTE: aszilagyi. make it correctly check for open function not have body
268     if (!scriptFunc->HasBody() && !(node->IsAbstract() || node->IsNative() || node->IsDeclare() ||
269                                     checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) {
270         checker->ThrowTypeError("Only abstract or native methods can't have body.", scriptFunc->Start());
271     }
272 
273     if (scriptFunc->ReturnTypeAnnotation() == nullptr &&
274         (node->IsNative() || (node->IsDeclare() && !node->IsConstructor()))) {
275         checker->ThrowTypeError("Native and Declare methods should have explicit return type.", scriptFunc->Start());
276     }
277 
278     if (node->TsType() == nullptr) {
279         node->SetTsType(checker->BuildMethodSignature(node));
280     }
281 
282     this->CheckMethodModifiers(node);
283 
284     if (node->IsNative() && scriptFunc->ReturnTypeAnnotation() == nullptr) {
285         checker->ThrowTypeError("'Native' method should have explicit return type", scriptFunc->Start());
286     }
287 
288     if (node->IsNative() && (scriptFunc->IsGetter() || scriptFunc->IsSetter())) {
289         checker->ThrowTypeError("'Native' modifier is invalid for Accessors", scriptFunc->Start());
290     }
291 
292     DoBodyTypeChecking(checker, node, scriptFunc);
293     CheckGetterSetterTypeConstrains(checker, scriptFunc);
294 
295     checker->CheckOverride(node->TsType()->AsETSFunctionType()->FindSignature(node->Function()));
296 
297     for (auto *it : node->Overloads()) {
298         it->Check(checker);
299     }
300 
301     if (scriptFunc->IsRethrowing()) {
302         checker->CheckRethrowingFunction(scriptFunc);
303     }
304 
305     return node->TsType();
306 }
307 
CheckMethodModifiers(ir::MethodDefinition * node) const308 void ETSAnalyzer::CheckMethodModifiers(ir::MethodDefinition *node) const
309 {
310     ETSChecker *checker = GetETSChecker();
311     auto const notValidInAbstract = ir::ModifierFlags::NATIVE | ir::ModifierFlags::PRIVATE |
312                                     ir::ModifierFlags::OVERRIDE | ir::ModifierFlags::FINAL | ir::ModifierFlags::STATIC;
313 
314     if (node->IsAbstract() && (node->flags_ & notValidInAbstract) != 0U) {
315         checker->ThrowTypeError(
316             "Invalid method modifier(s): an abstract method can't have private, override, static, final or native "
317             "modifier.",
318             node->Start());
319     }
320 
321     if ((node->IsAbstract() || (!node->Function()->HasBody() && !node->IsNative() && !node->IsDeclare())) &&
322         !(checker->HasStatus(checker::CheckerStatus::IN_ABSTRACT) ||
323           checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) {
324         checker->ThrowTypeError("Non abstract class has abstract method.", node->Start());
325     }
326 
327     auto const notValidInFinal = ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::STATIC | ir::ModifierFlags::NATIVE;
328 
329     if (node->IsFinal() && (node->flags_ & notValidInFinal) != 0U) {
330         checker->ThrowTypeError(
331             "Invalid method modifier(s): a final method can't have abstract, static or native modifier.",
332             node->Start());
333     }
334 
335     auto const notValidInStatic = ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::FINAL | ir::ModifierFlags::OVERRIDE;
336 
337     if (node->IsStatic() && (node->flags_ & notValidInStatic) != 0U) {
338         checker->ThrowTypeError(
339             "Invalid method modifier(s): a static method can't have abstract, final or override modifier.",
340             node->Start());
341     }
342 }
343 
Check(ir::Property * expr) const344 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::Property *expr) const
345 {
346     UNREACHABLE();
347 }
348 
Check(ir::ScriptFunction * node) const349 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ScriptFunction *node) const
350 {
351     UNREACHABLE();
352 }
353 
Check(ir::SpreadElement * expr) const354 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::SpreadElement *expr) const
355 {
356     UNREACHABLE();
357 }
358 
Check(ir::TemplateElement * expr) const359 checker::Type *ETSAnalyzer::Check(ir::TemplateElement *expr) const
360 {
361     ETSChecker *checker = GetETSChecker();
362     expr->SetTsType(checker->CreateETSStringLiteralType(expr->Raw()));
363     return expr->TsType();
364 }
365 
Check(ir::TSIndexSignature * node) const366 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSIndexSignature *node) const
367 {
368     UNREACHABLE();
369 }
370 
Check(ir::TSMethodSignature * node) const371 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSMethodSignature *node) const
372 {
373     UNREACHABLE();
374 }
375 
Check(ir::TSPropertySignature * node) const376 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSPropertySignature *node) const
377 {
378     UNREACHABLE();
379 }
380 
Check(ir::TSSignatureDeclaration * node) const381 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSSignatureDeclaration *node) const
382 {
383     UNREACHABLE();
384 }
385 // from ets folder
Check(ir::ETSScript * node) const386 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSScript *node) const
387 {
388     UNREACHABLE();
389 }
390 
Check(ir::ETSClassLiteral * expr) const391 checker::Type *ETSAnalyzer::Check(ir::ETSClassLiteral *expr) const
392 {
393     ETSChecker *checker = GetETSChecker();
394     checker->ThrowTypeError("Class literal is not yet supported.", expr->expr_->Start());
395 
396     expr->expr_->Check(checker);
397     auto *exprType = expr->expr_->GetType(checker);
398 
399     if (exprType->IsETSVoidType()) {
400         checker->ThrowTypeError("Invalid .class reference", expr->expr_->Start());
401     }
402 
403     ArenaVector<checker::Type *> typeArgTypes(checker->Allocator()->Adapter());
404     typeArgTypes.push_back(exprType);  // NOTE: Box it if it's a primitive type
405 
406     checker::InstantiationContext ctx(checker, checker->GlobalBuiltinTypeType(), typeArgTypes, expr->range_.start);
407     expr->SetTsType(ctx.Result());
408     return expr->TsType();
409 }
410 
Check(ir::ETSFunctionType * node) const411 checker::Type *ETSAnalyzer::Check(ir::ETSFunctionType *node) const
412 {
413     ETSChecker *checker = GetETSChecker();
414     checker->CreateFunctionalInterfaceForFunctionType(node);
415     auto *interfaceType =
416         checker->CreateETSObjectType(node->FunctionalInterface()->Id()->Name(), node->FunctionalInterface(),
417                                      checker::ETSObjectFlags::FUNCTIONAL_INTERFACE);
418     interfaceType->SetSuperType(checker->GlobalETSObjectType());
419 
420     auto *invokeFunc = node->FunctionalInterface()->Body()->Body()[0]->AsMethodDefinition()->Function();
421     auto *signatureInfo = checker->Allocator()->New<checker::SignatureInfo>(checker->Allocator());
422 
423     for (auto *it : invokeFunc->Params()) {
424         auto *const param = it->AsETSParameterExpression();
425         if (param->IsRestParameter()) {
426             auto *restIdent = param->Ident();
427 
428             ASSERT(restIdent->Variable());
429             signatureInfo->restVar = restIdent->Variable()->AsLocalVariable();
430 
431             ASSERT(param->TypeAnnotation());
432             signatureInfo->restVar->SetTsType(checker->GetTypeFromTypeAnnotation(param->TypeAnnotation()));
433 
434             auto arrayType = signatureInfo->restVar->TsType()->AsETSArrayType();
435             checker->CreateBuiltinArraySignature(arrayType, arrayType->Rank());
436         } else {
437             auto *paramIdent = param->Ident();
438 
439             ASSERT(paramIdent->Variable());
440             varbinder::Variable *paramVar = paramIdent->Variable();
441 
442             ASSERT(param->TypeAnnotation());
443             paramVar->SetTsType(checker->GetTypeFromTypeAnnotation(param->TypeAnnotation()));
444             signatureInfo->params.push_back(paramVar->AsLocalVariable());
445             ++signatureInfo->minArgCount;
446         }
447     }
448 
449     invokeFunc->ReturnTypeAnnotation()->Check(checker);
450     auto *signature =
451         checker->Allocator()->New<checker::Signature>(signatureInfo, node->ReturnType()->GetType(checker), invokeFunc);
452     signature->SetOwnerVar(invokeFunc->Id()->Variable()->AsLocalVariable());
453     signature->AddSignatureFlag(checker::SignatureFlags::FUNCTIONAL_INTERFACE_SIGNATURE);
454     signature->SetOwner(interfaceType);
455 
456     auto *funcType = checker->CreateETSFunctionType(signature);
457     invokeFunc->SetSignature(signature);
458     invokeFunc->Id()->Variable()->SetTsType(funcType);
459     interfaceType->AddProperty<checker::PropertyType::INSTANCE_METHOD>(invokeFunc->Id()->Variable()->AsLocalVariable());
460     node->FunctionalInterface()->SetTsType(interfaceType);
461 
462     auto *thisVar = invokeFunc->Scope()->ParamScope()->Params().front();
463     thisVar->SetTsType(interfaceType);
464     checker->BuildFunctionalInterfaceName(node);
465 
466     node->SetTsType(interfaceType);
467     return interfaceType;
468 }
469 
Check(ir::ETSImportDeclaration * node) const470 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSImportDeclaration *node) const
471 {
472     UNREACHABLE();
473 }
474 
Check(ir::ETSLaunchExpression * expr) const475 checker::Type *ETSAnalyzer::Check(ir::ETSLaunchExpression *expr) const
476 {
477     ETSChecker *checker = GetETSChecker();
478     expr->expr_->Check(checker);
479     auto *const launchPromiseType =
480         checker->GlobalBuiltinPromiseType()
481             ->Instantiate(checker->Allocator(), checker->Relation(), checker->GetGlobalTypesHolder())
482             ->AsETSObjectType();
483     launchPromiseType->AddTypeFlag(checker::TypeFlag::GENERIC);
484 
485     // Launch expression returns a Promise<T> type, so we need to insert the expression's type
486     // as type parameter for the Promise class.
487 
488     auto *exprType =
489         expr->expr_->TsType()->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) && !expr->expr_->TsType()->IsETSVoidType()
490             ? checker->PrimitiveTypeAsETSBuiltinType(expr->expr_->TsType())
491             : expr->expr_->TsType();
492     checker::Substitution *substitution = checker->NewSubstitution();
493     ASSERT(launchPromiseType->TypeArguments().size() == 1);
494     checker::ETSChecker::EmplaceSubstituted(
495         substitution, launchPromiseType->TypeArguments()[0]->AsETSTypeParameter()->GetOriginal(), exprType);
496 
497     expr->SetTsType(launchPromiseType->Substitute(checker->Relation(), substitution));
498     return expr->TsType();
499 }
500 
Check(ir::ETSNewArrayInstanceExpression * expr) const501 checker::Type *ETSAnalyzer::Check(ir::ETSNewArrayInstanceExpression *expr) const
502 {
503     ETSChecker *checker = GetETSChecker();
504 
505     auto *elementType = expr->typeReference_->GetType(checker);
506     checker->ValidateArrayIndex(expr->dimension_, true);
507 
508     if (!elementType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) && !elementType->IsNullish() &&
509         !elementType->HasTypeFlag(TypeFlag::GENERIC) && !elementType->HasTypeFlag(TypeFlag::ETS_ARRAY) &&
510         elementType->ToAssemblerName().str() != "Ball") {
511         // Check only valid for ETS_PRIMITIVE and IsNullish, GENERIC and ETS_ARRAY are workaround checks for stdlib
512         // Ball is workaround for koala ui lib
513         if (elementType->IsETSObjectType()) {
514             auto *calleeObj = elementType->AsETSObjectType();
515             if (!calleeObj->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT)) {
516                 // A workaround check for new Interface[...] in test cases
517                 expr->defaultConstructorSignature_ =
518                     checker->CollectParameterlessConstructor(calleeObj->ConstructSignatures(), expr->Start());
519                 checker->ValidateSignatureAccessibility(calleeObj, nullptr, expr->defaultConstructorSignature_,
520                                                         expr->Start());
521             }
522         }
523     }
524     expr->SetTsType(checker->CreateETSArrayType(elementType));
525     checker->CreateBuiltinArraySignature(expr->TsType()->AsETSArrayType(), 1);
526     return expr->TsType();
527 }
528 
Check(ir::ETSNewClassInstanceExpression * expr) const529 checker::Type *ETSAnalyzer::Check(ir::ETSNewClassInstanceExpression *expr) const
530 {
531     ETSChecker *checker = GetETSChecker();
532     checker::Type *calleeType = expr->GetTypeRef()->Check(checker);
533 
534     if (!calleeType->IsETSObjectType()) {
535         checker->ThrowTypeError("This expression is not constructible.", expr->Start());
536     }
537 
538     auto *calleeObj = calleeType->AsETSObjectType();
539     expr->SetTsType(calleeObj);
540 
541     if (expr->ClassDefinition() != nullptr) {
542         if (!calleeObj->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT) && calleeObj->GetDeclNode()->IsFinal()) {
543             checker->ThrowTypeError({"Class ", calleeObj->Name(), " cannot be both 'abstract' and 'final'."},
544                                     calleeObj->GetDeclNode()->Start());
545         }
546 
547         bool fromInterface = calleeObj->HasObjectFlag(checker::ETSObjectFlags::INTERFACE);
548         auto *classType = checker->BuildAnonymousClassProperties(
549             expr->ClassDefinition(), fromInterface ? checker->GlobalETSObjectType() : calleeObj);
550         if (fromInterface) {
551             classType->AddInterface(calleeObj);
552             calleeObj = checker->GlobalETSObjectType();
553         }
554         expr->ClassDefinition()->SetTsType(classType);
555         checker->CheckClassDefinition(expr->ClassDefinition());
556         checker->CheckInnerClassMembers(classType);
557         expr->SetTsType(classType);
558     } else if (calleeObj->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT)) {
559         checker->ThrowTypeError({calleeObj->Name(), " is abstract therefore cannot be instantiated."}, expr->Start());
560     }
561 
562     if (calleeType->IsETSDynamicType() && !calleeType->AsETSDynamicType()->HasDecl()) {
563         auto lang = calleeType->AsETSDynamicType()->Language();
564         expr->SetSignature(checker->ResolveDynamicCallExpression(expr->GetTypeRef(), expr->GetArguments(), lang, true));
565     } else {
566         auto *signature = checker->ResolveConstructExpression(calleeObj, expr->GetArguments(), expr->Start());
567 
568         checker->CheckObjectLiteralArguments(signature, expr->GetArguments());
569         checker->AddUndefinedParamsForDefaultParams(signature, expr->arguments_, checker);
570 
571         checker->ValidateSignatureAccessibility(calleeObj, nullptr, signature, expr->Start());
572 
573         ASSERT(signature->Function() != nullptr);
574 
575         if (signature->Function()->IsThrowing() || signature->Function()->IsRethrowing()) {
576             checker->CheckThrowingStatements(expr);
577         }
578 
579         if (calleeType->IsETSDynamicType()) {
580             ASSERT(signature->Function()->IsDynamic());
581             auto lang = calleeType->AsETSDynamicType()->Language();
582             expr->SetSignature(
583                 checker->ResolveDynamicCallExpression(expr->GetTypeRef(), signature->Params(), lang, true));
584         } else {
585             ASSERT(!signature->Function()->IsDynamic());
586             expr->SetSignature(signature);
587         }
588     }
589 
590     return expr->TsType();
591 }
592 
Check(ir::ETSNewMultiDimArrayInstanceExpression * expr) const593 checker::Type *ETSAnalyzer::Check(ir::ETSNewMultiDimArrayInstanceExpression *expr) const
594 {
595     ETSChecker *checker = GetETSChecker();
596     auto *elementType = expr->typeReference_->GetType(checker);
597 
598     for (auto *dim : expr->dimensions_) {
599         checker->ValidateArrayIndex(dim);
600         elementType = checker->CreateETSArrayType(elementType);
601     }
602 
603     expr->SetTsType(elementType);
604     expr->signature_ = checker->CreateBuiltinArraySignature(elementType->AsETSArrayType(), expr->dimensions_.size());
605     return expr->TsType();
606 }
607 
Check(ir::ETSPackageDeclaration * st) const608 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSPackageDeclaration *st) const
609 {
610     return nullptr;
611 }
612 
Check(ir::ETSParameterExpression * expr) const613 checker::Type *ETSAnalyzer::Check(ir::ETSParameterExpression *expr) const
614 {
615     ETSChecker *checker = GetETSChecker();
616     if (expr->TsType() == nullptr) {
617         checker::Type *paramType;
618 
619         if (expr->Ident()->TsType() != nullptr) {
620             paramType = expr->Ident()->TsType();
621         } else {
622             paramType = !expr->IsRestParameter() ? expr->Ident()->Check(checker) : expr->spread_->Check(checker);
623             if (expr->IsDefault()) {
624                 [[maybe_unused]] auto *const initType = expr->Initializer()->Check(checker);
625             }
626         }
627 
628         expr->SetTsType(paramType);
629     }
630 
631     return expr->TsType();
632 }
633 
Check(ir::ETSPrimitiveType * node) const634 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSPrimitiveType *node) const
635 {
636     return nullptr;
637 }
638 
Check(ir::ETSStructDeclaration * node) const639 checker::Type *ETSAnalyzer::Check(ir::ETSStructDeclaration *node) const
640 {
641     ETSChecker *checker = GetETSChecker();
642     node->Definition()->Check(checker);
643     return nullptr;
644 }
645 
Check(ir::ETSTuple * node) const646 checker::Type *ETSAnalyzer::Check(ir::ETSTuple *node) const
647 {
648     (void)node;
649     UNREACHABLE();
650 }
651 
Check(ir::ETSTypeReference * node) const652 checker::Type *ETSAnalyzer::Check(ir::ETSTypeReference *node) const
653 {
654     ETSChecker *checker = GetETSChecker();
655     return node->GetType(checker);
656 }
657 
Check(ir::ETSTypeReferencePart * node) const658 checker::Type *ETSAnalyzer::Check(ir::ETSTypeReferencePart *node) const
659 {
660     ETSChecker *checker = GetETSChecker();
661     return node->GetType(checker);
662 }
663 
Check(ir::ETSUnionType * node) const664 checker::Type *ETSAnalyzer::Check(ir::ETSUnionType *node) const
665 {
666     (void)node;
667     UNREACHABLE();
668 }
669 
Check(ir::ETSWildcardType * node) const670 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSWildcardType *node) const
671 {
672     UNREACHABLE();
673 }
674 
675 // compile methods for EXPRESSIONS in alphabetical order
676 
GetPreferredType(ir::ArrayExpression * expr) const677 checker::Type *ETSAnalyzer::GetPreferredType(ir::ArrayExpression *expr) const
678 {
679     return expr->preferredType_;
680 }
681 
Check(ir::ArrayExpression * expr) const682 checker::Type *ETSAnalyzer::Check(ir::ArrayExpression *expr) const
683 {
684     ETSChecker *checker = GetETSChecker();
685     if (expr->TsType() != nullptr) {
686         return expr->TsType();
687     }
688 
689     const bool isArray = (expr->preferredType_ != nullptr) && expr->preferredType_->IsETSArrayType() &&
690                          !expr->preferredType_->IsETSTupleType();
691     if (isArray) {
692         expr->preferredType_ = expr->preferredType_->AsETSArrayType()->ElementType();
693     }
694 
695     if (!expr->Elements().empty()) {
696         if (expr->preferredType_ == nullptr) {
697             expr->preferredType_ = expr->Elements()[0]->Check(checker);
698         }
699 
700         const bool isPreferredTuple = expr->preferredType_->IsETSTupleType();
701         auto *const targetElementType =
702             isPreferredTuple && !isArray ? expr->preferredType_->AsETSTupleType()->ElementType() : expr->preferredType_;
703 
704         for (std::size_t idx = 0; idx < expr->elements_.size(); ++idx) {
705             auto *const currentElement = expr->elements_[idx];
706 
707             if (currentElement->IsArrayExpression()) {
708                 expr->HandleNestedArrayExpression(checker, currentElement->AsArrayExpression(), isArray,
709                                                   isPreferredTuple, idx);
710             }
711 
712             if (currentElement->IsObjectExpression()) {
713                 currentElement->AsObjectExpression()->SetPreferredType(expr->preferredType_);
714             }
715 
716             checker::Type *elementType = currentElement->Check(checker);
717 
718             if (!elementType->IsETSArrayType() && isPreferredTuple) {
719                 auto *const compareType = expr->preferredType_->AsETSTupleType()->GetTypeAtIndex(idx);
720 
721                 if (compareType == nullptr) {
722                     checker->ThrowTypeError(
723                         {"Too many elements in array initializer for tuple with size of ",
724                          static_cast<uint32_t>(expr->preferredType_->AsETSTupleType()->GetTupleSize())},
725                         currentElement->Start());
726                 }
727 
728                 const checker::CastingContext cast(
729                     checker->Relation(), currentElement, elementType, compareType, currentElement->Start(),
730                     {"Array initializer's type is not assignable to tuple type at index: ", idx});
731 
732                 elementType = compareType;
733             }
734 
735             checker::AssignmentContext(checker->Relation(), currentElement, elementType, targetElementType,
736                                        currentElement->Start(),
737                                        {"Array element type '", elementType, "' is not assignable to explicit type '",
738                                         expr->GetPreferredType(), "'"});
739         }
740 
741         expr->SetPreferredType(targetElementType);
742     }
743 
744     if (expr->preferredType_ == nullptr) {
745         checker->ThrowTypeError("Can't resolve array type", expr->Start());
746     }
747 
748     expr->SetTsType(checker->CreateETSArrayType(expr->preferredType_));
749     auto *const arrayType = expr->TsType()->AsETSArrayType();
750     checker->CreateBuiltinArraySignature(arrayType, arrayType->Rank());
751     return expr->TsType();
752 }
753 
Check(ir::ArrowFunctionExpression * expr) const754 checker::Type *ETSAnalyzer::Check(ir::ArrowFunctionExpression *expr) const
755 {
756     ETSChecker *checker = GetETSChecker();
757     if (expr->TsType() != nullptr) {
758         return expr->TsType();
759     }
760 
761     auto *funcType = checker->BuildFunctionSignature(expr->Function(), false);
762 
763     if (expr->Function()->IsAsyncFunc()) {
764         auto *retType = static_cast<checker::ETSObjectType *>(expr->Function()->Signature()->ReturnType());
765         if (retType->AssemblerName() != checker->GlobalBuiltinPromiseType()->AssemblerName()) {
766             checker->ThrowTypeError("Return type of async lambda must be 'Promise'", expr->Function()->Start());
767         }
768     }
769 
770     checker::ScopeContext scopeCtx(checker, expr->Function()->Scope());
771 
772     if (checker->HasStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD)) {
773         /*
774         example code:
775         ```
776             class A {
777                 prop:number
778             }
779             function A.method() {
780                 let a = () => {
781                     console.println(this.prop)
782                 }
783             }
784         ```
785         here the enclosing class of arrow function should be Class A
786         */
787         checker->Context().SetContainingClass(
788             checker->Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_THIS).variable->TsType()->AsETSObjectType());
789     }
790 
791     checker::SavedCheckerContext savedContext(checker, checker->Context().Status(),
792                                               checker->Context().ContainingClass());
793     checker->AddStatus(checker::CheckerStatus::IN_LAMBDA);
794     checker->Context().SetContainingSignature(funcType->CallSignatures()[0]);
795 
796     expr->Function()->Body()->Check(checker);
797 
798     checker->Context().SetContainingSignature(nullptr);
799     checker->CheckCapturedVariables();
800 
801     for (auto [var, _] : checker->Context().CapturedVars()) {
802         (void)_;
803         expr->CapturedVars().push_back(var);
804     }
805 
806     expr->SetTsType(funcType);
807     return expr->TsType();
808 }
809 
Check(ir::AssignmentExpression * expr) const810 checker::Type *ETSAnalyzer::Check(ir::AssignmentExpression *expr) const
811 {
812     ETSChecker *checker = GetETSChecker();
813 
814     if (expr->TsType() != nullptr) {
815         return expr->TsType();
816     }
817 
818     auto *leftType = expr->Left()->Check(checker);
819     if (expr->Left()->IsMemberExpression() &&
820         expr->Left()->AsMemberExpression()->Object()->TsType()->IsETSArrayType() &&
821         expr->Left()->AsMemberExpression()->Property()->IsIdentifier() &&
822         expr->Left()->AsMemberExpression()->Property()->AsIdentifier()->Name().Is("length")) {
823         checker->ThrowTypeError("Setting the length of an array is not permitted", expr->Left()->Start());
824     }
825 
826     if (expr->Left()->IsIdentifier()) {
827         expr->target_ = expr->Left()->AsIdentifier()->Variable();
828     } else {
829         expr->target_ = expr->Left()->AsMemberExpression()->PropVar();
830     }
831 
832     if (expr->target_ != nullptr) {
833         checker->ValidateUnaryOperatorOperand(expr->target_);
834     }
835 
836     checker::Type *sourceType {};
837     ir::Expression *relationNode = expr->Right();
838     switch (expr->OperatorType()) {
839         case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL:
840         case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL:
841         case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL:
842         case lexer::TokenType::PUNCTUATOR_MOD_EQUAL:
843         case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL:
844         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL:
845         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL:
846         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL:
847         case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL:
848         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL:
849         case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL:
850         case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
851             std::tie(std::ignore, expr->operationType_) = checker->CheckBinaryOperator(
852                 expr->Left(), expr->Right(), expr, expr->OperatorType(), expr->Start(), true);
853 
854             auto unboxedLeft = checker->ETSBuiltinTypeAsPrimitiveType(leftType);
855             sourceType = unboxedLeft == nullptr ? leftType : unboxedLeft;
856 
857             relationNode = expr;
858             break;
859         }
860         case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
861             if (leftType->IsETSArrayType() && expr->Right()->IsArrayExpression()) {
862                 checker->ModifyPreferredType(expr->Right()->AsArrayExpression(), leftType);
863             }
864 
865             if (expr->Right()->IsObjectExpression()) {
866                 expr->Right()->AsObjectExpression()->SetPreferredType(leftType);
867             }
868 
869             sourceType = expr->Right()->Check(checker);
870             break;
871         }
872         default: {
873             UNREACHABLE();
874             break;
875         }
876     }
877 
878     checker::AssignmentContext(checker->Relation(), relationNode, sourceType, leftType, expr->Right()->Start(),
879                                {"Initializers type is not assignable to the target type"});
880 
881     expr->SetTsType(expr->Left()->TsType());
882     return expr->TsType();
883 }
884 
Check(ir::AwaitExpression * expr) const885 checker::Type *ETSAnalyzer::Check(ir::AwaitExpression *expr) const
886 {
887     ETSChecker *checker = GetETSChecker();
888     if (expr->TsType() != nullptr) {
889         return expr->TsType();
890     }
891 
892     checker::Type *argType = ETSChecker::GetApparentType(expr->argument_->Check(checker));
893     // Check the argument type of await expression
894     if (!argType->IsETSObjectType() ||
895         (argType->AsETSObjectType()->AssemblerName() != compiler::Signatures::BUILTIN_PROMISE)) {
896         checker->ThrowTypeError("'await' expressions require Promise object as argument.", expr->Argument()->Start());
897     }
898 
899     expr->SetTsType(argType->AsETSObjectType()->TypeArguments().at(0));
900     return expr->TsType();
901 }
902 
Check(ir::BinaryExpression * expr) const903 checker::Type *ETSAnalyzer::Check(ir::BinaryExpression *expr) const
904 {
905     ETSChecker *checker = GetETSChecker();
906     if (expr->TsType() != nullptr) {
907         return expr->TsType();
908     }
909     checker::Type *newTsType {nullptr};
910     std::tie(newTsType, expr->operationType_) =
911         checker->CheckBinaryOperator(expr->Left(), expr->Right(), expr, expr->OperatorType(), expr->Start());
912     expr->SetTsType(newTsType);
913     return expr->TsType();
914 }
915 
InitAnonymousLambdaCallee(checker::ETSChecker * checker,ir::Expression * callee,checker::Type * calleeType)916 static checker::Type *InitAnonymousLambdaCallee(checker::ETSChecker *checker, ir::Expression *callee,
917                                                 checker::Type *calleeType)
918 {
919     auto *const arrowFunc = callee->AsArrowFunctionExpression()->Function();
920     auto origParams = arrowFunc->Params();
921     auto signature = ir::FunctionSignature(nullptr, std::move(origParams), arrowFunc->ReturnTypeAnnotation());
922     auto *funcType =
923         checker->Allocator()->New<ir::ETSFunctionType>(std::move(signature), ir::ScriptFunctionFlags::NONE);
924     funcType->SetScope(arrowFunc->Scope()->AsFunctionScope()->ParamScope());
925     auto *const funcIface = funcType->Check(checker);
926     checker->Relation()->SetNode(callee);
927     checker->Relation()->IsAssignableTo(calleeType, funcIface);
928     return funcIface;
929 }
930 
ResolveCallExtensionFunction(checker::ETSFunctionType * functionType,checker::ETSChecker * checker,ir::CallExpression * expr)931 static checker::Signature *ResolveCallExtensionFunction(checker::ETSFunctionType *functionType,
932                                                         checker::ETSChecker *checker, ir::CallExpression *expr)
933 {
934     auto *memberExpr = expr->Callee()->AsMemberExpression();
935     expr->Arguments().insert(expr->Arguments().begin(), memberExpr->Object());
936     auto *signature =
937         checker->ResolveCallExpressionAndTrailingLambda(functionType->CallSignatures(), expr, expr->Start());
938     if (!signature->Function()->IsExtensionMethod()) {
939         checker->ThrowTypeError({"Property '", memberExpr->Property()->AsIdentifier()->Name(),
940                                  "' does not exist on type '", memberExpr->ObjType()->Name(), "'"},
941                                 memberExpr->Property()->Start());
942     }
943     expr->SetSignature(signature);
944     expr->SetCallee(memberExpr->Property());
945     memberExpr->Property()->AsIdentifier()->SetParent(expr);
946     expr->Arguments()[0]->SetParent(expr);
947     checker->HandleUpdatedCallExpressionNode(expr);
948     // Set TsType for new Callee(original member expression's Object)
949     expr->Callee()->Check(checker);
950     return signature;
951 }
952 
ResolveCallForETSExtensionFuncHelperType(checker::ETSExtensionFuncHelperType * type,checker::ETSChecker * checker,ir::CallExpression * expr)953 static checker::Signature *ResolveCallForETSExtensionFuncHelperType(checker::ETSExtensionFuncHelperType *type,
954                                                                     checker::ETSChecker *checker,
955                                                                     ir::CallExpression *expr)
956 {
957     checker::Signature *signature = checker->ResolveCallExpressionAndTrailingLambda(
958         type->ClassMethodType()->CallSignatures(), expr, expr->Start(), checker::TypeRelationFlag::NO_THROW);
959 
960     if (signature != nullptr) {
961         return signature;
962     }
963 
964     return ResolveCallExtensionFunction(type->ExtensionMethodType(), checker, expr);
965 }
966 
Check(ir::BlockExpression * st) const967 checker::Type *ETSAnalyzer::Check(ir::BlockExpression *st) const
968 {
969     (void)st;
970     UNREACHABLE();
971 }
972 
GetUnionTypeSignatures(ETSChecker * checker,checker::ETSUnionType * etsUnionType)973 ArenaVector<checker::Signature *> GetUnionTypeSignatures(ETSChecker *checker, checker::ETSUnionType *etsUnionType)
974 {
975     ArenaVector<checker::Signature *> callSignatures(checker->Allocator()->Adapter());
976 
977     for (auto *constituentType : etsUnionType->ConstituentTypes()) {
978         if (constituentType->IsETSObjectType()) {
979             ArenaVector<checker::Signature *> tmpCallSignatures(checker->Allocator()->Adapter());
980             tmpCallSignatures = constituentType->AsETSObjectType()
981                                     ->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>("invoke")
982                                     ->TsType()
983                                     ->AsETSFunctionType()
984                                     ->CallSignatures();
985             callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end());
986         }
987         if (constituentType->IsETSFunctionType()) {
988             ArenaVector<checker::Signature *> tmpCallSignatures(checker->Allocator()->Adapter());
989             tmpCallSignatures = constituentType->AsETSFunctionType()->CallSignatures();
990             callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end());
991         }
992         if (constituentType->IsETSUnionType()) {
993             ArenaVector<checker::Signature *> tmpCallSignatures(checker->Allocator()->Adapter());
994             tmpCallSignatures = GetUnionTypeSignatures(checker, constituentType->AsETSUnionType());
995             callSignatures.insert(callSignatures.end(), tmpCallSignatures.begin(), tmpCallSignatures.end());
996         }
997     }
998 
999     return callSignatures;
1000 }
1001 
ChooseSignatures(ETSChecker * checker,checker::Type * calleeType,bool isConstructorCall,bool isFunctionalInterface,bool isUnionTypeWithFunctionalInterface)1002 ArenaVector<checker::Signature *> &ChooseSignatures(ETSChecker *checker, checker::Type *calleeType,
1003                                                     bool isConstructorCall, bool isFunctionalInterface,
1004                                                     bool isUnionTypeWithFunctionalInterface)
1005 {
1006     static ArenaVector<checker::Signature *> unionSignatures(checker->Allocator()->Adapter());
1007     unionSignatures.clear();
1008     if (isConstructorCall) {
1009         return calleeType->AsETSObjectType()->ConstructSignatures();
1010     }
1011     if (isFunctionalInterface) {
1012         return calleeType->AsETSObjectType()
1013             ->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>("invoke")
1014             ->TsType()
1015             ->AsETSFunctionType()
1016             ->CallSignatures();
1017     }
1018     if (isUnionTypeWithFunctionalInterface) {
1019         unionSignatures = GetUnionTypeSignatures(checker, calleeType->AsETSUnionType());
1020         return unionSignatures;
1021     }
1022     return calleeType->AsETSFunctionType()->CallSignatures();
1023 }
1024 
ChooseCalleeObj(ETSChecker * checker,ir::CallExpression * expr,checker::Type * calleeType,bool isConstructorCall)1025 checker::ETSObjectType *ChooseCalleeObj(ETSChecker *checker, ir::CallExpression *expr, checker::Type *calleeType,
1026                                         bool isConstructorCall)
1027 {
1028     if (isConstructorCall) {
1029         return calleeType->AsETSObjectType();
1030     }
1031     if (expr->Callee()->IsIdentifier()) {
1032         return checker->Context().ContainingClass();
1033     }
1034     ASSERT(expr->Callee()->IsMemberExpression());
1035     return expr->Callee()->AsMemberExpression()->ObjType();
1036 }
1037 
ResolveSignature(ETSChecker * checker,ir::CallExpression * expr,checker::Type * calleeType,bool isFunctionalInterface,bool isUnionTypeWithFunctionalInterface) const1038 checker::Signature *ETSAnalyzer::ResolveSignature(ETSChecker *checker, ir::CallExpression *expr,
1039                                                   checker::Type *calleeType, bool isFunctionalInterface,
1040                                                   bool isUnionTypeWithFunctionalInterface) const
1041 {
1042     bool extensionFunctionType = expr->Callee()->IsMemberExpression() && checker->ExtensionETSFunctionType(calleeType);
1043 
1044     if (calleeType->IsETSExtensionFuncHelperType()) {
1045         return ResolveCallForETSExtensionFuncHelperType(calleeType->AsETSExtensionFuncHelperType(), checker, expr);
1046     }
1047     if (extensionFunctionType) {
1048         return ResolveCallExtensionFunction(calleeType->AsETSFunctionType(), checker, expr);
1049     }
1050     auto &signatures = ChooseSignatures(checker, calleeType, expr->IsETSConstructorCall(), isFunctionalInterface,
1051                                         isUnionTypeWithFunctionalInterface);
1052     checker::Signature *signature = checker->ResolveCallExpressionAndTrailingLambda(signatures, expr, expr->Start());
1053     if (signature->Function()->IsExtensionMethod()) {
1054         checker->ThrowTypeError({"No matching call signature"}, expr->Start());
1055     }
1056     return signature;
1057 }
1058 
GetReturnType(ir::CallExpression * expr,checker::Type * calleeType) const1059 checker::Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, checker::Type *calleeType) const
1060 {
1061     ETSChecker *checker = GetETSChecker();
1062     bool isConstructorCall = expr->IsETSConstructorCall();
1063     bool isUnionTypeWithFunctionalInterface =
1064         calleeType->IsETSUnionType() &&
1065         calleeType->AsETSUnionType()->HasObjectType(checker::ETSObjectFlags::FUNCTIONAL_INTERFACE);
1066     bool isFunctionalInterface = calleeType->IsETSObjectType() && calleeType->AsETSObjectType()->HasObjectFlag(
1067                                                                       checker::ETSObjectFlags::FUNCTIONAL_INTERFACE);
1068     bool etsExtensionFuncHelperType = calleeType->IsETSExtensionFuncHelperType();
1069 
1070     if (expr->Callee()->IsArrowFunctionExpression()) {
1071         calleeType = InitAnonymousLambdaCallee(checker, expr->Callee(), calleeType);
1072         isFunctionalInterface = true;
1073     }
1074 
1075     if (!isFunctionalInterface && !calleeType->IsETSFunctionType() && !isConstructorCall &&
1076         !etsExtensionFuncHelperType && !isUnionTypeWithFunctionalInterface) {
1077         checker->ThrowTypeError("This expression is not callable.", expr->Start());
1078     }
1079 
1080     checker::Signature *signature =
1081         ResolveSignature(checker, expr, calleeType, isFunctionalInterface, isUnionTypeWithFunctionalInterface);
1082 
1083     checker->CheckObjectLiteralArguments(signature, expr->Arguments());
1084     checker->AddUndefinedParamsForDefaultParams(signature, expr->Arguments(), checker);
1085 
1086     if (!isFunctionalInterface) {
1087         checker::ETSObjectType *calleeObj = ChooseCalleeObj(checker, expr, calleeType, isConstructorCall);
1088         checker->ValidateSignatureAccessibility(calleeObj, expr, signature, expr->Start());
1089     }
1090 
1091     ASSERT(signature->Function() != nullptr);
1092     if (signature->Function()->IsThrowing() || signature->Function()->IsRethrowing()) {
1093         checker->CheckThrowingStatements(expr);
1094     }
1095 
1096     if (signature->Function()->IsDynamic()) {
1097         ASSERT(signature->Function()->IsDynamic());
1098         auto lang = signature->Function()->Language();
1099         expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), signature->Params(), lang, false));
1100     } else {
1101         ASSERT(!signature->Function()->IsDynamic());
1102         expr->SetSignature(signature);
1103     }
1104 
1105     auto *returnType = signature->ReturnType();
1106 
1107     if (signature->HasSignatureFlag(SignatureFlags::THIS_RETURN_TYPE)) {
1108         returnType = ChooseCalleeObj(checker, expr, calleeType, isConstructorCall);
1109     }
1110 
1111     return returnType;
1112 }
1113 
Check(ir::CallExpression * expr) const1114 checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const
1115 {
1116     ETSChecker *checker = GetETSChecker();
1117     if (expr->TsType() != nullptr) {
1118         return expr->TsType();
1119     }
1120     auto *oldCallee = expr->Callee();
1121     checker::Type *calleeType = ETSChecker::GetApparentType(expr->Callee()->Check(checker));
1122     if (expr->Callee() != oldCallee) {
1123         // If it is a static invoke, the callee will be transformed from an identifier to a member expression
1124         // Type check the callee again for member expression
1125         calleeType = expr->Callee()->Check(checker);
1126     }
1127     if (!expr->IsOptional()) {
1128         checker->CheckNonNullishType(calleeType, expr->Callee()->Start());
1129     }
1130     checker::Type *returnType;
1131     if (calleeType->IsETSDynamicType() && !calleeType->AsETSDynamicType()->HasDecl()) {
1132         // Trailing lambda for js function call is not supported, check the correctness of `foo() {}`
1133         checker->EnsureValidCurlyBrace(expr);
1134         auto lang = calleeType->AsETSDynamicType()->Language();
1135         expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), expr->Arguments(), lang, false));
1136         returnType = expr->Signature()->ReturnType();
1137     } else {
1138         returnType = GetReturnType(expr, calleeType);
1139     }
1140 
1141     if (expr->Signature()->RestVar() != nullptr) {
1142         auto *const elementType = expr->Signature()->RestVar()->TsType()->AsETSArrayType()->ElementType();
1143         auto *const arrayType = checker->CreateETSArrayType(elementType)->AsETSArrayType();
1144         checker->CreateBuiltinArraySignature(arrayType, arrayType->Rank());
1145     }
1146 
1147     if (expr->Signature()->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE)) {
1148         expr->Signature()->OwnerVar()->Declaration()->Node()->Check(checker);
1149         returnType = expr->Signature()->ReturnType();
1150         // NOTE(vpukhov): #14902 substituted signature is not updated
1151     }
1152     expr->SetOptionalType(returnType);
1153     if (expr->IsOptional() && checker->MayHaveNulllikeValue(expr->Callee()->Check(checker))) {
1154         checker->Relation()->SetNode(expr);
1155         returnType = checker->CreateOptionalResultType(returnType);
1156         checker->Relation()->SetNode(nullptr);
1157     }
1158     expr->SetTsType(returnType);
1159     expr->SetUncheckedType(checker->GuaranteedTypeForUncheckedCallReturn(expr->Signature()));
1160     return expr->TsType();
1161 }
1162 
Check(ir::ChainExpression * expr) const1163 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ChainExpression *expr) const
1164 {
1165     UNREACHABLE();
1166 }
1167 
Check(ir::ClassExpression * expr) const1168 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ClassExpression *expr) const
1169 {
1170     UNREACHABLE();
1171 }
1172 
Check(ir::ConditionalExpression * expr) const1173 checker::Type *ETSAnalyzer::Check(ir::ConditionalExpression *expr) const
1174 {
1175     ETSChecker *checker = GetETSChecker();
1176     if (expr->TsType() != nullptr) {
1177         return expr->TsType();
1178     }
1179 
1180     checker->CheckTruthinessOfType(expr->Test());
1181 
1182     checker::Type *consequentType = expr->consequent_->Check(checker);
1183     checker::Type *alternateType = expr->alternate_->Check(checker);
1184 
1185     auto *primitiveConsequentType = checker->ETSBuiltinTypeAsPrimitiveType(consequentType);
1186     auto *primitiveAlterType = checker->ETSBuiltinTypeAsPrimitiveType(alternateType);
1187 
1188     if (primitiveConsequentType != nullptr && primitiveAlterType != nullptr) {
1189         if (checker->IsTypeIdenticalTo(consequentType, alternateType)) {
1190             expr->SetTsType(checker->GetNonConstantTypeFromPrimitiveType(consequentType));
1191         } else if (checker->IsTypeIdenticalTo(primitiveConsequentType, primitiveAlterType)) {
1192             checker->FlagExpressionWithUnboxing(expr->consequent_->TsType(), primitiveConsequentType,
1193                                                 expr->consequent_);
1194             checker->FlagExpressionWithUnboxing(expr->alternate_->TsType(), primitiveAlterType, expr->alternate_);
1195 
1196             expr->SetTsType(primitiveConsequentType);
1197         } else if (primitiveConsequentType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC) &&
1198                    primitiveAlterType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) {
1199             checker->FlagExpressionWithUnboxing(expr->consequent_->TsType(), primitiveConsequentType,
1200                                                 expr->consequent_);
1201             checker->FlagExpressionWithUnboxing(expr->alternate_->TsType(), primitiveAlterType, expr->alternate_);
1202 
1203             expr->SetTsType(
1204                 checker->ApplyConditionalOperatorPromotion(checker, primitiveConsequentType, primitiveAlterType));
1205         } else {
1206             checker->ThrowTypeError("Type error", expr->Range().start);
1207         }
1208     } else {
1209         if (!(consequentType->IsETSArrayType() || alternateType->IsETSArrayType()) &&
1210             !(checker->IsReferenceType(consequentType) && checker->IsReferenceType(alternateType))) {
1211             checker->ThrowTypeError("Type error", expr->Range().start);
1212         } else {
1213             checker->Relation()->SetNode(expr->consequent_);
1214             auto builtinConseqType = checker->PrimitiveTypeAsETSBuiltinType(consequentType);
1215             auto builtinAlternateType = checker->PrimitiveTypeAsETSBuiltinType(alternateType);
1216 
1217             if (builtinConseqType == nullptr) {
1218                 builtinConseqType = consequentType;
1219             }
1220 
1221             if (builtinAlternateType == nullptr) {
1222                 builtinAlternateType = alternateType;
1223             }
1224 
1225             expr->SetTsType(checker->CreateETSUnionType(builtinConseqType, builtinAlternateType));
1226         }
1227     }
1228 
1229     return expr->TsType();
1230 }
1231 
Check(ir::DirectEvalExpression * expr) const1232 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::DirectEvalExpression *expr) const
1233 {
1234     UNREACHABLE();
1235 }
1236 
Check(ir::FunctionExpression * expr) const1237 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::FunctionExpression *expr) const
1238 {
1239     UNREACHABLE();
1240 }
1241 
Check(ir::Identifier * expr) const1242 checker::Type *ETSAnalyzer::Check(ir::Identifier *expr) const
1243 {
1244     ETSChecker *checker = GetETSChecker();
1245     if (expr->TsType() != nullptr) {
1246         return expr->TsType();
1247     }
1248 
1249     expr->SetTsType(checker->ResolveIdentifier(expr));
1250     return expr->TsType();
1251 }
1252 
Check(ir::ImportExpression * expr) const1253 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ImportExpression *expr) const
1254 {
1255     UNREACHABLE();
1256 }
1257 
Check(ir::MemberExpression * expr) const1258 checker::Type *ETSAnalyzer::Check(ir::MemberExpression *expr) const
1259 {
1260     ETSChecker *checker = GetETSChecker();
1261     if (expr->TsType() != nullptr) {
1262         return expr->TsType();
1263     }
1264 
1265     auto *const leftType = checker->GetApparentType(expr->Object()->Check(checker));
1266 
1267     if (expr->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) {
1268         if (expr->IsOptional() && !leftType->IsNullish()) {
1269             checker->ThrowTypeError("The type of the object reference must be a nullish array or Record type",
1270                                     expr->Object()->Start());
1271         }
1272 
1273         if (!expr->IsOptional() && leftType->IsNullish()) {
1274             checker->ThrowTypeError("The type of the object reference must be a non-nullish array or Record type",
1275                                     expr->Object()->Start());
1276         }
1277     }
1278 
1279     auto *const baseType = expr->IsOptional() ? checker->GetNonNullishType(leftType) : leftType;
1280     if (!expr->IsOptional()) {
1281         checker->CheckNonNullishType(leftType, expr->Object()->Start());
1282     }
1283 
1284     if (expr->IsComputed()) {
1285         return expr->AdjustType(checker, expr->CheckComputed(checker, baseType));
1286     }
1287 
1288     if (baseType->IsETSArrayType() && expr->Property()->AsIdentifier()->Name().Is("length")) {
1289         return expr->AdjustType(checker, checker->GlobalIntType());
1290     }
1291 
1292     if (baseType->IsETSObjectType()) {
1293         expr->SetObjectType(baseType->AsETSObjectType());
1294         auto [resType, resVar] = expr->ResolveObjectMember(checker);
1295         expr->SetPropVar(resVar);
1296         return expr->AdjustType(checker, resType);
1297     }
1298 
1299     if (baseType->IsETSEnumType() || baseType->IsETSStringEnumType()) {
1300         auto [memberType, memberVar] = expr->ResolveEnumMember(checker, baseType);
1301         expr->SetPropVar(memberVar);
1302         return expr->AdjustType(checker, memberType);
1303     }
1304 
1305     if (baseType->IsETSUnionType()) {
1306         return expr->AdjustType(checker, expr->CheckUnionMember(checker, baseType));
1307     }
1308 
1309     if (baseType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
1310         checker->Relation()->SetNode(expr);
1311         expr->SetObjectType(checker->PrimitiveTypeAsETSBuiltinType(baseType)->AsETSObjectType());
1312         checker->AddBoxingUnboxingFlagsToNode(expr, expr->ObjType());
1313         auto [resType, resVar] = expr->ResolveObjectMember(checker);
1314         expr->SetPropVar(resVar);
1315         return expr->AdjustType(checker, resType);
1316     }
1317 
1318     checker->ThrowTypeError({"Cannot access property of non-object or non-enum type"}, expr->Object()->Start());
1319 }
1320 
Check(ir::NewExpression * expr) const1321 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::NewExpression *expr) const
1322 {
1323     UNREACHABLE();
1324 }
PreferredType(ir::ObjectExpression * expr) const1325 checker::Type *ETSAnalyzer::PreferredType(ir::ObjectExpression *expr) const
1326 {
1327     return expr->preferredType_;
1328 }
1329 
Check(ir::ObjectExpression * expr) const1330 checker::Type *ETSAnalyzer::Check(ir::ObjectExpression *expr) const
1331 {
1332     ETSChecker *checker = GetETSChecker();
1333     if (expr->TsType() != nullptr) {
1334         return expr->TsType();
1335     }
1336 
1337     if (expr->PreferredType() == nullptr) {
1338         checker->ThrowTypeError({"need to specify target type for class composite"}, expr->Start());
1339     }
1340     if (!expr->PreferredType()->IsETSObjectType()) {
1341         checker->ThrowTypeError({"target type for class composite needs to be an object type"}, expr->Start());
1342     }
1343 
1344     if (expr->PreferredType()->IsETSDynamicType()) {
1345         for (ir::Expression *propExpr : expr->Properties()) {
1346             ASSERT(propExpr->IsProperty());
1347             ir::Property *prop = propExpr->AsProperty();
1348             ir::Expression *value = prop->Value();
1349             value->Check(checker);
1350             ASSERT(value->TsType());
1351         }
1352 
1353         expr->SetTsType(expr->PreferredType());
1354         return expr->PreferredType();
1355     }
1356 
1357     checker::ETSObjectType *objType = expr->PreferredType()->AsETSObjectType();
1358     if (objType->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT | checker::ETSObjectFlags::INTERFACE)) {
1359         checker->ThrowTypeError({"target type for class composite ", objType->Name(), " is not instantiable"},
1360                                 expr->Start());
1361     }
1362 
1363     bool haveEmptyConstructor = false;
1364     for (checker::Signature *sig : objType->ConstructSignatures()) {
1365         if (sig->Params().empty()) {
1366             haveEmptyConstructor = true;
1367             checker->ValidateSignatureAccessibility(objType, nullptr, sig, expr->Start());
1368             break;
1369         }
1370     }
1371     if (!haveEmptyConstructor) {
1372         checker->ThrowTypeError({"type ", objType->Name(), " has no parameterless constructor"}, expr->Start());
1373     }
1374 
1375     for (ir::Expression *propExpr : expr->Properties()) {
1376         ASSERT(propExpr->IsProperty());
1377         ir::Property *prop = propExpr->AsProperty();
1378         ir::Expression *key = prop->Key();
1379         ir::Expression *value = prop->Value();
1380 
1381         util::StringView pname;
1382         if (key->IsStringLiteral()) {
1383             pname = key->AsStringLiteral()->Str();
1384         } else if (key->IsIdentifier()) {
1385             pname = key->AsIdentifier()->Name();
1386         } else {
1387             checker->ThrowTypeError({"key in class composite should be either identifier or string literal"},
1388                                     expr->Start());
1389         }
1390         varbinder::LocalVariable *lv = objType->GetProperty(pname, checker::PropertySearchFlags::SEARCH_INSTANCE_FIELD |
1391                                                                        checker::PropertySearchFlags::SEARCH_IN_BASE);
1392         if (lv == nullptr) {
1393             checker->ThrowTypeError({"type ", objType->Name(), " has no property named ", pname}, propExpr->Start());
1394         }
1395         checker->ValidatePropertyAccess(lv, objType, propExpr->Start());
1396         if (lv->HasFlag(varbinder::VariableFlags::READONLY)) {
1397             checker->ThrowTypeError({"cannot assign to readonly property ", pname}, propExpr->Start());
1398         }
1399 
1400         auto *propType = checker->GetTypeOfVariable(lv);
1401         key->SetTsType(propType);
1402 
1403         if (value->IsObjectExpression()) {
1404             value->AsObjectExpression()->SetPreferredType(propType);
1405         }
1406         value->SetTsType(value->Check(checker));
1407         checker::AssignmentContext(checker->Relation(), value, value->TsType(), propType, value->Start(),
1408                                    {"value type is not assignable to the property type"});
1409     }
1410 
1411     expr->SetTsType(objType);
1412     return objType;
1413 }
1414 
Check(ir::OmittedExpression * expr) const1415 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::OmittedExpression *expr) const
1416 {
1417     UNREACHABLE();
1418 }
1419 
Check(ir::OpaqueTypeNode * expr) const1420 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::OpaqueTypeNode *expr) const
1421 {
1422     UNREACHABLE();
1423 }
1424 
Check(ir::SequenceExpression * expr) const1425 checker::Type *ETSAnalyzer::Check(ir::SequenceExpression *expr) const
1426 {
1427     ETSChecker *checker = GetETSChecker();
1428     if (expr->TsType() != nullptr) {
1429         return expr->TsType();
1430     }
1431 
1432     for (auto *it : expr->Sequence()) {
1433         it->Check(checker);
1434     }
1435     return nullptr;
1436 }
1437 
Check(ir::SuperExpression * expr) const1438 checker::Type *ETSAnalyzer::Check(ir::SuperExpression *expr) const
1439 {
1440     ETSChecker *checker = GetETSChecker();
1441     if (expr->TsType() != nullptr) {
1442         return expr->TsType();
1443     }
1444 
1445     expr->SetTsType(checker->CheckThisOrSuperAccess(expr, checker->Context().ContainingClass()->SuperType(), "super"));
1446     return expr->TsType();
1447 }
1448 
Check(ir::TaggedTemplateExpression * expr) const1449 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TaggedTemplateExpression *expr) const
1450 {
1451     UNREACHABLE();
1452 }
1453 
Check(ir::TemplateLiteral * expr) const1454 checker::Type *ETSAnalyzer::Check(ir::TemplateLiteral *expr) const
1455 {
1456     ETSChecker *checker = GetETSChecker();
1457     if (expr->TsType() != nullptr) {
1458         return expr->TsType();
1459     }
1460 
1461     if (expr->Quasis().size() != expr->Expressions().size() + 1U) {
1462         checker->ThrowTypeError("Invalid string template expression", expr->Start());
1463     }
1464 
1465     for (auto *it : expr->Expressions()) {
1466         it->Check(checker);
1467     }
1468 
1469     for (auto *it : expr->Quasis()) {
1470         it->Check(checker);
1471     }
1472 
1473     expr->SetTsType(checker->GlobalBuiltinETSStringType());
1474     return expr->TsType();
1475 }
1476 
Check(ir::ThisExpression * expr) const1477 checker::Type *ETSAnalyzer::Check(ir::ThisExpression *expr) const
1478 {
1479     ETSChecker *checker = GetETSChecker();
1480     if (expr->TsType() != nullptr) {
1481         return expr->TsType();
1482     }
1483 
1484     /*
1485     example code:
1486     ```
1487         class A {
1488             prop
1489         }
1490         function A.method() {
1491             let a = () => {
1492                 console.println(this.prop)
1493             }
1494         }
1495         is identical to
1496         function method(this: A) {
1497             let a = () => {
1498                 console.println(this.prop)
1499             }
1500         }
1501     ```
1502     here when "this" is used inside an extension function, we need to bind "this" to the first
1503     parameter(MANDATORY_PARAM_THIS), and capture the paramter's variable other than containing class's variable
1504     */
1505     auto *variable = checker->AsETSChecker()->Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_THIS).variable;
1506     if (checker->HasStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD)) {
1507         ASSERT(variable != nullptr);
1508         expr->SetTsType(variable->TsType());
1509     } else {
1510         expr->SetTsType(checker->CheckThisOrSuperAccess(expr, checker->Context().ContainingClass(), "this"));
1511     }
1512 
1513     if (checker->HasStatus(checker::CheckerStatus::IN_LAMBDA)) {
1514         if (checker->HasStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD)) {
1515             checker->Context().AddCapturedVar(variable, expr->Start());
1516         } else {
1517             checker->Context().AddCapturedVar(checker->Context().ContainingClass()->Variable(), expr->Start());
1518         }
1519     }
1520 
1521     return expr->TsType();
1522 }
1523 
ProcessExclamationMark(ETSChecker * checker,ir::UnaryExpression * expr,checker::Type * operandType)1524 void ProcessExclamationMark(ETSChecker *checker, ir::UnaryExpression *expr, checker::Type *operandType)
1525 {
1526     if (checker->IsNullLikeOrVoidExpression(expr->Argument())) {
1527         auto tsType = checker->CreateETSBooleanType(true);
1528         tsType->AddTypeFlag(checker::TypeFlag::CONSTANT);
1529         expr->SetTsType(tsType);
1530         return;
1531     }
1532 
1533     if (operandType == nullptr || !operandType->IsConditionalExprType()) {
1534         checker->ThrowTypeError("Bad operand type, the type of the operand must be boolean type.",
1535                                 expr->Argument()->Start());
1536     }
1537 
1538     auto exprRes = operandType->ResolveConditionExpr();
1539     if (std::get<0>(exprRes)) {
1540         auto tsType = checker->CreateETSBooleanType(!std::get<1>(exprRes));
1541         tsType->AddTypeFlag(checker::TypeFlag::CONSTANT);
1542         expr->SetTsType(tsType);
1543         return;
1544     }
1545 
1546     expr->SetTsType(checker->GlobalETSBooleanType());
1547 }
1548 
SetTsTypeForUnaryExpression(ETSChecker * checker,ir::UnaryExpression * expr,checker::Type * operandType,checker::Type * argType)1549 void SetTsTypeForUnaryExpression(ETSChecker *checker, ir::UnaryExpression *expr, checker::Type *operandType,
1550                                  checker::Type *argType)
1551 {
1552     switch (expr->OperatorType()) {
1553         case lexer::TokenType::PUNCTUATOR_MINUS:
1554         case lexer::TokenType::PUNCTUATOR_PLUS: {
1555             if (operandType == nullptr || !operandType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) {
1556                 checker->ThrowTypeError("Bad operand type, the type of the operand must be numeric type.",
1557                                         expr->Argument()->Start());
1558             }
1559 
1560             if (operandType->HasTypeFlag(checker::TypeFlag::CONSTANT) &&
1561                 expr->OperatorType() == lexer::TokenType::PUNCTUATOR_MINUS) {
1562                 expr->SetTsType(checker->NegateNumericType(operandType, expr));
1563                 break;
1564             }
1565 
1566             expr->SetTsType(operandType);
1567             break;
1568         }
1569         case lexer::TokenType::PUNCTUATOR_TILDE: {
1570             if (operandType == nullptr || !operandType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) {
1571                 checker->ThrowTypeError("Bad operand type, the type of the operand must be numeric type.",
1572                                         expr->Argument()->Start());
1573             }
1574 
1575             if (operandType->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
1576                 expr->SetTsType(checker->BitwiseNegateNumericType(operandType, expr));
1577                 break;
1578             }
1579 
1580             expr->SetTsType(checker->SelectGlobalIntegerTypeForNumeric(operandType));
1581             break;
1582         }
1583         case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: {
1584             ProcessExclamationMark(checker, expr, operandType);
1585             break;
1586         }
1587         case lexer::TokenType::PUNCTUATOR_DOLLAR_DOLLAR: {
1588             expr->SetTsType(argType);
1589             break;
1590         }
1591         default: {
1592             UNREACHABLE();
1593             break;
1594         }
1595     }
1596 }
1597 
Check(ir::UnaryExpression * expr) const1598 checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const
1599 {
1600     ETSChecker *checker = GetETSChecker();
1601 
1602     if (expr->TsType() != nullptr) {
1603         return expr->TsType();
1604     }
1605 
1606     auto argType = expr->argument_->Check(checker);
1607     const auto isCondExpr = expr->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK;
1608     checker::Type *operandType = checker->ApplyUnaryOperatorPromotion(argType, true, true, isCondExpr);
1609     auto unboxedOperandType = isCondExpr ? checker->ETSBuiltinTypeAsConditionalType(argType)
1610                                          : checker->ETSBuiltinTypeAsPrimitiveType(argType);
1611 
1612     if (argType != nullptr && argType->IsETSBigIntType() && argType->HasTypeFlag(checker::TypeFlag::BIGINT_LITERAL)) {
1613         switch (expr->OperatorType()) {
1614             case lexer::TokenType::PUNCTUATOR_MINUS: {
1615                 checker::Type *type = checker->CreateETSBigIntLiteralType(argType->AsETSBigIntType()->GetValue());
1616 
1617                 // We do not need this const anymore as we are negating the bigint object in runtime
1618                 type->RemoveTypeFlag(checker::TypeFlag::CONSTANT);
1619                 expr->argument_->SetTsType(type);
1620                 expr->SetTsType(type);
1621                 return expr->TsType();
1622             }
1623             default:
1624                 // Handled below
1625                 // NOTE(kkonsw): handle other unary operators for bigint literals
1626                 break;
1627         }
1628     }
1629 
1630     if (argType != nullptr && argType->IsETSBigIntType()) {
1631         switch (expr->OperatorType()) {
1632             case lexer::TokenType::PUNCTUATOR_MINUS:
1633             case lexer::TokenType::PUNCTUATOR_PLUS:
1634             case lexer::TokenType::PUNCTUATOR_TILDE: {
1635                 expr->SetTsType(argType);
1636                 return expr->TsType();
1637             }
1638             default:
1639                 break;
1640         }
1641     }
1642 
1643     SetTsTypeForUnaryExpression(checker, expr, operandType, argType);
1644 
1645     if ((argType != nullptr) && argType->IsETSObjectType() && (unboxedOperandType != nullptr) &&
1646         unboxedOperandType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
1647         expr->Argument()->AddBoxingUnboxingFlags(checker->GetUnboxingFlag(unboxedOperandType));
1648     }
1649 
1650     return expr->TsType();
1651 }
1652 
Check(ir::UpdateExpression * expr) const1653 checker::Type *ETSAnalyzer::Check(ir::UpdateExpression *expr) const
1654 {
1655     ETSChecker *checker = GetETSChecker();
1656     if (expr->TsType() != nullptr) {
1657         return expr->TsType();
1658     }
1659 
1660     checker::Type *operandType = expr->argument_->Check(checker);
1661     if (expr->Argument()->IsIdentifier()) {
1662         checker->ValidateUnaryOperatorOperand(expr->Argument()->AsIdentifier()->Variable());
1663     } else if (expr->Argument()->IsTSAsExpression()) {
1664         if (auto *const asExprVar = expr->Argument()->AsTSAsExpression()->Variable(); asExprVar != nullptr) {
1665             checker->ValidateUnaryOperatorOperand(asExprVar);
1666         }
1667     } else {
1668         ASSERT(expr->Argument()->IsMemberExpression());
1669         varbinder::LocalVariable *propVar = expr->argument_->AsMemberExpression()->PropVar();
1670         if (propVar != nullptr) {
1671             checker->ValidateUnaryOperatorOperand(propVar);
1672         }
1673     }
1674 
1675     if (operandType->IsETSBigIntType()) {
1676         expr->SetTsType(operandType);
1677         return expr->TsType();
1678     }
1679 
1680     auto unboxedType = checker->ETSBuiltinTypeAsPrimitiveType(operandType);
1681     if (unboxedType == nullptr || !unboxedType->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) {
1682         checker->ThrowTypeError("Bad operand type, the type of the operand must be numeric type.",
1683                                 expr->Argument()->Start());
1684     }
1685 
1686     if (operandType->IsETSObjectType()) {
1687         expr->Argument()->AddBoxingUnboxingFlags(checker->GetUnboxingFlag(unboxedType) |
1688                                                  checker->GetBoxingFlag(unboxedType));
1689     }
1690 
1691     expr->SetTsType(operandType);
1692     return expr->TsType();
1693 }
1694 
Check(ir::YieldExpression * expr) const1695 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::YieldExpression *expr) const
1696 {
1697     UNREACHABLE();
1698 }
1699 // compile methods for LITERAL EXPRESSIONS in alphabetical order
Check(ir::BigIntLiteral * expr) const1700 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::BigIntLiteral *expr) const
1701 {
1702     ETSChecker *checker = GetETSChecker();
1703     expr->SetTsType(checker->CreateETSBigIntLiteralType(expr->Str()));
1704     return expr->TsType();
1705 }
1706 
Check(ir::BooleanLiteral * expr) const1707 checker::Type *ETSAnalyzer::Check(ir::BooleanLiteral *expr) const
1708 {
1709     ETSChecker *checker = GetETSChecker();
1710     if (expr->TsType() == nullptr) {
1711         expr->SetTsType(checker->CreateETSBooleanType(expr->Value()));
1712     }
1713     return expr->TsType();
1714 }
1715 
Check(ir::CharLiteral * expr) const1716 checker::Type *ETSAnalyzer::Check(ir::CharLiteral *expr) const
1717 {
1718     ETSChecker *checker = GetETSChecker();
1719     if (expr->TsType() == nullptr) {
1720         expr->SetTsType(checker->Allocator()->New<checker::CharType>(expr->Char()));
1721     }
1722     return expr->TsType();
1723 }
1724 
Check(ir::NullLiteral * expr) const1725 checker::Type *ETSAnalyzer::Check(ir::NullLiteral *expr) const
1726 {
1727     ETSChecker *checker = GetETSChecker();
1728     if (expr->TsType() == nullptr) {
1729         expr->SetTsType(checker->GlobalETSNullType());
1730     }
1731     return expr->TsType();
1732 }
1733 
Check(ir::NumberLiteral * expr) const1734 checker::Type *ETSAnalyzer::Check(ir::NumberLiteral *expr) const
1735 {
1736     ETSChecker *checker = GetETSChecker();
1737     if (expr->Number().IsInt()) {
1738         expr->SetTsType(checker->CreateIntType(expr->Number().GetInt()));
1739         return expr->TsType();
1740     }
1741 
1742     if (expr->Number().IsLong()) {
1743         expr->SetTsType(checker->CreateLongType(expr->Number().GetLong()));
1744         return expr->TsType();
1745     }
1746 
1747     if (expr->Number().IsFloat()) {
1748         expr->SetTsType(checker->CreateFloatType(expr->Number().GetFloat()));
1749         return expr->TsType();
1750     }
1751 
1752     expr->SetTsType(checker->CreateDoubleType(expr->Number().GetDouble()));
1753     return expr->TsType();
1754 }
1755 
Check(ir::RegExpLiteral * expr) const1756 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::RegExpLiteral *expr) const
1757 {
1758     UNREACHABLE();
1759 }
1760 
Check(ir::StringLiteral * expr) const1761 checker::Type *ETSAnalyzer::Check(ir::StringLiteral *expr) const
1762 {
1763     ETSChecker *checker = GetETSChecker();
1764     if (expr->TsType() == nullptr) {
1765         expr->SetTsType(checker->CreateETSStringLiteralType(expr->Str()));
1766     }
1767     return expr->TsType();
1768 }
1769 
Check(ir::UndefinedLiteral * expr) const1770 checker::Type *ETSAnalyzer::Check(ir::UndefinedLiteral *expr) const
1771 {
1772     (void)expr;
1773     UNREACHABLE();
1774 }
1775 
1776 // compile methods for MODULE-related nodes in alphabetical order
Check(ir::ExportAllDeclaration * st) const1777 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ExportAllDeclaration *st) const
1778 {
1779     UNREACHABLE();
1780 }
1781 
Check(ir::ExportDefaultDeclaration * st) const1782 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ExportDefaultDeclaration *st) const
1783 {
1784     UNREACHABLE();
1785 }
1786 
Check(ir::ExportNamedDeclaration * st) const1787 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ExportNamedDeclaration *st) const
1788 {
1789     UNREACHABLE();
1790 }
1791 
Check(ir::ExportSpecifier * st) const1792 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ExportSpecifier *st) const
1793 {
1794     UNREACHABLE();
1795 }
1796 
Check(ir::ImportDeclaration * st) const1797 checker::Type *ETSAnalyzer::Check(ir::ImportDeclaration *st) const
1798 {
1799     ETSChecker *checker = GetETSChecker();
1800     checker::Type *type = nullptr;
1801     for (auto *spec : st->Specifiers()) {
1802         if (spec->IsImportNamespaceSpecifier()) {
1803             type = spec->AsImportNamespaceSpecifier()->Check(checker);
1804         }
1805     }
1806 
1807     return type;
1808 }
1809 
Check(ir::ImportDefaultSpecifier * st) const1810 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ImportDefaultSpecifier *st) const
1811 {
1812     UNREACHABLE();
1813 }
1814 
CreateSyntheticType(ETSChecker * checker,util::StringView const & syntheticName,checker::ETSObjectType * lastObjectType,ir::Identifier * id)1815 checker::ETSObjectType *CreateSyntheticType(ETSChecker *checker, util::StringView const &syntheticName,
1816                                             checker::ETSObjectType *lastObjectType, ir::Identifier *id)
1817 {
1818     auto *syntheticObjType = checker->Allocator()->New<checker::ETSObjectType>(
1819         checker->Allocator(), syntheticName, syntheticName, id, checker::ETSObjectFlags::NO_OPTS);
1820 
1821     auto *classDecl = checker->Allocator()->New<varbinder::ClassDecl>(syntheticName);
1822     varbinder::LocalVariable *var =
1823         checker->Allocator()->New<varbinder::LocalVariable>(classDecl, varbinder::VariableFlags::CLASS);
1824     var->SetTsType(syntheticObjType);
1825     lastObjectType->AddProperty<checker::PropertyType::STATIC_FIELD>(var);
1826     syntheticObjType->SetEnclosingType(lastObjectType);
1827     return syntheticObjType;
1828 }
1829 
Check(ir::ImportNamespaceSpecifier * st) const1830 checker::Type *ETSAnalyzer::Check(ir::ImportNamespaceSpecifier *st) const
1831 {
1832     ETSChecker *checker = GetETSChecker();
1833     if (st->Local()->Name().Empty()) {
1834         return nullptr;
1835     }
1836 
1837     if (st->Local()->AsIdentifier()->TsType() != nullptr) {
1838         return st->Local()->TsType();
1839     }
1840 
1841     auto *importDecl = st->Parent()->AsETSImportDeclaration();
1842     auto importPath = importDecl->Source()->Str();
1843 
1844     if (importDecl->IsPureDynamic()) {
1845         auto *type = checker->GlobalBuiltinDynamicType(importDecl->Language());
1846         checker->SetrModuleObjectTsType(st->Local(), type);
1847         return type;
1848     }
1849 
1850     std::string packageName =
1851         (importDecl->Module() == nullptr) ? importPath.Mutf8() : importDecl->Module()->Str().Mutf8();
1852 
1853     std::replace(packageName.begin(), packageName.end(), '/', '.');
1854     util::UString packagePath(packageName, checker->Allocator());
1855     std::vector<util::StringView> syntheticNames = checker->GetNameForSynteticObjectType(packagePath.View());
1856 
1857     ASSERT(!syntheticNames.empty());
1858 
1859     auto assemblerName = syntheticNames[0];
1860     if (importDecl->Module() != nullptr) {
1861         assemblerName = util::UString(assemblerName.Mutf8().append(".").append(compiler::Signatures::ETS_GLOBAL),
1862                                       checker->Allocator())
1863                             .View();
1864     }
1865 
1866     auto *moduleObjectType =
1867         checker->Allocator()->New<checker::ETSObjectType>(checker->Allocator(), syntheticNames[0], assemblerName,
1868                                                           st->Local()->AsIdentifier(), checker::ETSObjectFlags::CLASS);
1869 
1870     auto *rootDecl = checker->Allocator()->New<varbinder::ClassDecl>(syntheticNames[0]);
1871     varbinder::LocalVariable *rootVar =
1872         checker->Allocator()->New<varbinder::LocalVariable>(rootDecl, varbinder::VariableFlags::NONE);
1873     rootVar->SetTsType(moduleObjectType);
1874 
1875     syntheticNames.erase(syntheticNames.begin());
1876     checker::ETSObjectType *lastObjectType(moduleObjectType);
1877 
1878     for (const auto &syntheticName : syntheticNames) {
1879         lastObjectType = CreateSyntheticType(checker, syntheticName, lastObjectType, st->Local()->AsIdentifier());
1880     }
1881 
1882     checker->SetPropertiesForModuleObject(
1883         lastObjectType,
1884         (importDecl->Module() != nullptr)
1885             ? util::UString(importPath.Mutf8() + importDecl->Module()->Str().Mutf8(), checker->Allocator()).View()
1886             : importPath);
1887     checker->SetrModuleObjectTsType(st->Local(), lastObjectType);
1888 
1889     return moduleObjectType;
1890 }
1891 
Check(ir::ImportSpecifier * st) const1892 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ImportSpecifier *st) const
1893 {
1894     UNREACHABLE();
1895 }
1896 // compile methods for STATEMENTS in alphabetical order
Check(ir::AssertStatement * st) const1897 checker::Type *ETSAnalyzer::Check(ir::AssertStatement *st) const
1898 {
1899     ETSChecker *checker = GetETSChecker();
1900     checker->CheckTruthinessOfType(st->test_);
1901 
1902     if (st->Second() != nullptr) {
1903         auto *msgType = st->second_->Check(checker);
1904 
1905         if (!msgType->IsETSStringType()) {
1906             checker->ThrowTypeError("Assert message must be string", st->Second()->Start());
1907         }
1908     }
1909 
1910     return nullptr;
1911 }
1912 
Check(ir::BlockStatement * st) const1913 checker::Type *ETSAnalyzer::Check(ir::BlockStatement *st) const
1914 {
1915     ETSChecker *checker = GetETSChecker();
1916     checker::ScopeContext scopeCtx(checker, st->Scope());
1917 
1918     for (auto *it : st->Statements()) {
1919         it->Check(checker);
1920     }
1921 
1922     for (auto [stmt, trailing_block] : st->trailingBlocks_) {
1923         auto iterator = std::find(st->Statements().begin(), st->Statements().end(), stmt);
1924         ASSERT(iterator != st->Statements().end());
1925         st->Statements().insert(iterator + 1, trailing_block);
1926         trailing_block->Check(checker);
1927     }
1928 
1929     return nullptr;
1930 }
1931 
Check(ir::BreakStatement * st) const1932 checker::Type *ETSAnalyzer::Check(ir::BreakStatement *st) const
1933 {
1934     ETSChecker *checker = GetETSChecker();
1935     st->target_ = checker->FindJumpTarget(st->Type(), st, st->Ident());
1936     return nullptr;
1937 }
1938 
Check(ir::ClassDeclaration * st) const1939 checker::Type *ETSAnalyzer::Check(ir::ClassDeclaration *st) const
1940 {
1941     ETSChecker *checker = GetETSChecker();
1942     st->Definition()->Check(checker);
1943     return nullptr;
1944 }
1945 
Check(ir::ContinueStatement * st) const1946 checker::Type *ETSAnalyzer::Check(ir::ContinueStatement *st) const
1947 {
1948     ETSChecker *checker = GetETSChecker();
1949     st->target_ = checker->FindJumpTarget(st->Type(), st, st->Ident());
1950     return nullptr;
1951 }
1952 
Check(ir::DebuggerStatement * st) const1953 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::DebuggerStatement *st) const
1954 {
1955     UNREACHABLE();
1956 }
1957 
Check(ir::DoWhileStatement * st) const1958 checker::Type *ETSAnalyzer::Check(ir::DoWhileStatement *st) const
1959 {
1960     ETSChecker *checker = GetETSChecker();
1961     checker::ScopeContext scopeCtx(checker, st->Scope());
1962 
1963     checker->CheckTruthinessOfType(st->Test());
1964     st->Body()->Check(checker);
1965 
1966     return nullptr;
1967 }
1968 
Check(ir::EmptyStatement * st) const1969 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::EmptyStatement *st) const
1970 {
1971     return nullptr;
1972 }
1973 
Check(ir::ExpressionStatement * st) const1974 checker::Type *ETSAnalyzer::Check(ir::ExpressionStatement *st) const
1975 {
1976     ETSChecker *checker = GetETSChecker();
1977     return st->GetExpression()->Check(checker);
1978 }
1979 
Check(ir::ForInStatement * st) const1980 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ForInStatement *st) const
1981 {
1982     UNREACHABLE();
1983 }
1984 
1985 // NOLINTBEGIN(modernize-avoid-c-arrays)
1986 static constexpr char const INVALID_SOURCE_EXPR_TYPE[] =
1987     "'For-of' statement source expression should be either a string or an array.";
1988 static constexpr char const INVALID_CONST_ASSIGNMENT[] = "Cannot assign a value to a constant variable ";
1989 static constexpr char const ITERATOR_TYPE_ABSENT[] = "Cannot obtain iterator type in 'for-of' statement.";
1990 // NOLINTEND(modernize-avoid-c-arrays)
1991 
GetIteratorType(ETSChecker * checker,checker::Type * elemType,ir::AstNode * left)1992 checker::Type *GetIteratorType(ETSChecker *checker, checker::Type *elemType, ir::AstNode *left)
1993 {
1994     // Just to avoid extra nested level(s)
1995     auto const getIterType = [checker, elemType](ir::VariableDeclarator *const declarator) -> checker::Type * {
1996         if (declarator->TsType() == nullptr) {
1997             if (auto *resolved = checker->FindVariableInFunctionScope(declarator->Id()->AsIdentifier()->Name());
1998                 resolved != nullptr) {
1999                 resolved->SetTsType(elemType);
2000                 return elemType;
2001             }
2002         } else {
2003             return declarator->TsType();
2004         }
2005         return nullptr;
2006     };
2007 
2008     checker::Type *iterType = nullptr;
2009     if (left->IsIdentifier()) {
2010         if (auto *const variable = left->AsIdentifier()->Variable(); variable != nullptr) {
2011             if (variable->Declaration()->IsConstDecl()) {
2012                 checker->ThrowTypeError({INVALID_CONST_ASSIGNMENT, variable->Name()},
2013                                         variable->Declaration()->Node()->Start());
2014             }
2015         }
2016         iterType = left->AsIdentifier()->TsType();
2017     } else if (left->IsVariableDeclaration()) {
2018         if (auto const &declarators = left->AsVariableDeclaration()->Declarators(); !declarators.empty()) {
2019             iterType = getIterType(declarators.front());
2020         }
2021     }
2022 
2023     if (iterType == nullptr) {
2024         checker->ThrowTypeError(ITERATOR_TYPE_ABSENT, left->Start());
2025     }
2026     return iterType;
2027 }
2028 
Check(ir::ForOfStatement * st) const2029 checker::Type *ETSAnalyzer::Check(ir::ForOfStatement *st) const
2030 {
2031     ETSChecker *checker = GetETSChecker();
2032     checker::ScopeContext scopeCtx(checker, st->Scope());
2033 
2034     checker::Type *const exprType = st->Right()->Check(checker);
2035     checker::Type *elemType;
2036 
2037     if (exprType == nullptr || (!exprType->IsETSArrayType() && !exprType->IsETSStringType())) {
2038         checker->ThrowTypeError(INVALID_SOURCE_EXPR_TYPE, st->Right()->Start());
2039     } else if (exprType->IsETSStringType()) {
2040         elemType = checker->GetGlobalTypesHolder()->GlobalCharType();
2041     } else {
2042         elemType = exprType->AsETSArrayType()->ElementType()->Instantiate(checker->Allocator(), checker->Relation(),
2043                                                                           checker->GetGlobalTypesHolder());
2044         elemType->RemoveTypeFlag(checker::TypeFlag::CONSTANT);
2045     }
2046 
2047     st->Left()->Check(checker);
2048     checker::Type *iterType = GetIteratorType(checker, elemType, st->Left());
2049     auto *const relation = checker->Relation();
2050     relation->SetFlags(checker::TypeRelationFlag::ASSIGNMENT_CONTEXT);
2051     relation->SetNode(checker->AllocNode<ir::SuperExpression>());  // Dummy node to avoid assertion!
2052 
2053     if (!relation->IsAssignableTo(elemType, iterType)) {
2054         std::stringstream ss {};
2055         ss << "Source element type '";
2056         elemType->ToString(ss);
2057         ss << "' is not assignable to the loop iterator type '";
2058         iterType->ToString(ss);
2059         ss << "'.";
2060         checker->ThrowTypeError(ss.str(), st->Start());
2061     }
2062 
2063     relation->SetNode(nullptr);
2064     relation->SetFlags(checker::TypeRelationFlag::NONE);
2065 
2066     st->Body()->Check(checker);
2067 
2068     return nullptr;
2069 }
2070 
Check(ir::ForUpdateStatement * st) const2071 checker::Type *ETSAnalyzer::Check(ir::ForUpdateStatement *st) const
2072 {
2073     ETSChecker *checker = GetETSChecker();
2074     checker::ScopeContext scopeCtx(checker, st->Scope());
2075 
2076     if (st->Init() != nullptr) {
2077         st->Init()->Check(checker);
2078     }
2079 
2080     if (st->Test() != nullptr) {
2081         checker->CheckTruthinessOfType(st->Test());
2082     }
2083 
2084     if (st->Update() != nullptr) {
2085         st->Update()->Check(checker);
2086     }
2087 
2088     st->Body()->Check(checker);
2089 
2090     return nullptr;
2091 }
2092 
Check(ir::FunctionDeclaration * st) const2093 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::FunctionDeclaration *st) const
2094 {
2095     UNREACHABLE();
2096 }
2097 
Check(ir::IfStatement * st) const2098 checker::Type *ETSAnalyzer::Check(ir::IfStatement *st) const
2099 {
2100     ETSChecker *checker = GetETSChecker();
2101     checker->CheckTruthinessOfType(st->test_);
2102 
2103     st->consequent_->Check(checker);
2104 
2105     if (st->Alternate() != nullptr) {
2106         st->alternate_->Check(checker);
2107     }
2108 
2109     return nullptr;
2110 }
2111 
Check(ir::LabelledStatement * st) const2112 checker::Type *ETSAnalyzer::Check(ir::LabelledStatement *st) const
2113 {
2114     ETSChecker *checker = GetETSChecker();
2115     st->body_->Check(checker);
2116     return nullptr;
2117 }
2118 
CheckArgumentVoidType(checker::Type * & funcReturnType,ETSChecker * checker,const std::string & name,ir::ReturnStatement * st)2119 void CheckArgumentVoidType(checker::Type *&funcReturnType, ETSChecker *checker, const std::string &name,
2120                            ir::ReturnStatement *st)
2121 {
2122     if (name.find(compiler::Signatures::ETS_MAIN_WITH_MANGLE_BEGIN) != std::string::npos) {
2123         if (funcReturnType == checker->GlobalBuiltinVoidType()) {
2124             funcReturnType = checker->GlobalVoidType();
2125         } else if (!funcReturnType->IsETSVoidType() && !funcReturnType->IsIntType()) {
2126             checker->ThrowTypeError("Bad return type, main enable only void or int type.", st->Start());
2127         }
2128     }
2129 }
2130 
CheckReturnType(ETSChecker * checker,checker::Type * funcReturnType,checker::Type * argumentType,ir::Expression * stArgument)2131 void CheckReturnType(ETSChecker *checker, checker::Type *funcReturnType, checker::Type *argumentType,
2132                      ir::Expression *stArgument)
2133 {
2134     if (funcReturnType->IsETSVoidType() || funcReturnType == checker->GlobalBuiltinVoidType()) {
2135         if (argumentType != checker->GlobalVoidType() && argumentType != checker->GlobalBuiltinVoidType()) {
2136             checker->ThrowTypeError("Unexpected return value, enclosing method return type is void.",
2137                                     stArgument->Start());
2138         }
2139     } else {
2140         checker::AssignmentContext(checker->Relation(), stArgument, argumentType, funcReturnType, stArgument->Start(),
2141                                    {"Return statement type is not compatible with the enclosing method's return type."},
2142                                    checker::TypeRelationFlag::DIRECT_RETURN);
2143     }
2144 }
2145 
InferReturnType(ETSChecker * checker,ir::ScriptFunction * containingFunc,checker::Type * & funcReturnType,ir::Expression * stArgument)2146 void InferReturnType(ETSChecker *checker, ir::ScriptFunction *containingFunc, checker::Type *&funcReturnType,
2147                      ir::Expression *stArgument)
2148 {
2149     //  First (or single) return statement in the function:
2150     funcReturnType = stArgument == nullptr
2151                          ? containingFunc->IsEntryPoint() ? checker->GlobalVoidType() : checker->GlobalBuiltinVoidType()
2152                          : stArgument->Check(checker);
2153     if (funcReturnType->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
2154         // remove CONSTANT type modifier if exists
2155         funcReturnType =
2156             funcReturnType->Instantiate(checker->Allocator(), checker->Relation(), checker->GetGlobalTypesHolder());
2157         funcReturnType->RemoveTypeFlag(checker::TypeFlag::CONSTANT);
2158     }
2159     /*
2160     when st_argment is ArrowFunctionExpression, need infer type for st_argment
2161     example code:
2162     ```
2163     return () => {}
2164     ```
2165     */
2166     if (stArgument != nullptr && stArgument->IsArrowFunctionExpression()) {
2167         auto arrowFunc = stArgument->AsArrowFunctionExpression();
2168         auto typeAnnotation = arrowFunc->CreateTypeAnnotation(checker);
2169         funcReturnType = typeAnnotation->GetType(checker);
2170         checker::AssignmentContext(checker->Relation(), arrowFunc, arrowFunc->TsType(), funcReturnType,
2171                                    stArgument->Start(),
2172                                    {"Return statement type is not compatible with the enclosing method's return type."},
2173                                    checker::TypeRelationFlag::DIRECT_RETURN);
2174     }
2175 
2176     containingFunc->Signature()->SetReturnType(funcReturnType);
2177     containingFunc->Signature()->RemoveSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE);
2178     checker->VarBinder()->AsETSBinder()->BuildFunctionName(containingFunc);
2179 
2180     if (stArgument != nullptr && stArgument->IsObjectExpression()) {
2181         stArgument->AsObjectExpression()->SetPreferredType(funcReturnType);
2182     }
2183 }
2184 
ProcessReturnStatements(ETSChecker * checker,ir::ScriptFunction * containingFunc,checker::Type * & funcReturnType,ir::ReturnStatement * st,ir::Expression * stArgument)2185 void ProcessReturnStatements(ETSChecker *checker, ir::ScriptFunction *containingFunc, checker::Type *&funcReturnType,
2186                              ir::ReturnStatement *st, ir::Expression *stArgument)
2187 {
2188     funcReturnType = containingFunc->Signature()->ReturnType();
2189 
2190     if (stArgument == nullptr) {
2191         // previous return statement(s) have value
2192         if (!funcReturnType->IsETSVoidType() && funcReturnType != checker->GlobalBuiltinVoidType()) {
2193             checker->ThrowTypeError("All return statements in the function should be empty or have a value.",
2194                                     st->Start());
2195         }
2196     } else {
2197         //  previous return statement(s) don't have any value
2198         if (funcReturnType->IsETSVoidType() || funcReturnType == checker->GlobalBuiltinVoidType()) {
2199             checker->ThrowTypeError("All return statements in the function should be empty or have a value.",
2200                                     stArgument->Start());
2201         }
2202 
2203         const auto name = containingFunc->Scope()->InternalName().Mutf8();
2204         if (name.find(compiler::Signatures::ETS_MAIN_WITH_MANGLE_BEGIN) != std::string::npos) {
2205             if (funcReturnType == checker->GlobalBuiltinVoidType()) {
2206                 funcReturnType = checker->GlobalVoidType();
2207             } else if (!funcReturnType->IsETSVoidType() && !funcReturnType->IsIntType()) {
2208                 checker->ThrowTypeError("Bad return type, main enable only void or int type.", st->Start());
2209             }
2210         }
2211 
2212         if (stArgument->IsObjectExpression()) {
2213             stArgument->AsObjectExpression()->SetPreferredType(funcReturnType);
2214         }
2215 
2216         if (stArgument->IsMemberExpression()) {
2217             checker->SetArrayPreferredTypeForNestedMemberExpressions(stArgument->AsMemberExpression(), funcReturnType);
2218         }
2219 
2220         checker::Type *argumentType = stArgument->Check(checker);
2221         // remove CONSTANT type modifier if exists
2222         if (argumentType->HasTypeFlag(checker::TypeFlag::CONSTANT)) {
2223             argumentType =
2224                 argumentType->Instantiate(checker->Allocator(), checker->Relation(), checker->GetGlobalTypesHolder());
2225             argumentType->RemoveTypeFlag(checker::TypeFlag::CONSTANT);
2226         }
2227 
2228         auto *const relation = checker->Relation();
2229         relation->SetNode(stArgument);
2230 
2231         if (!relation->IsIdenticalTo(funcReturnType, argumentType)) {
2232             checker->ResolveReturnStatement(funcReturnType, argumentType, containingFunc, st);
2233         }
2234 
2235         relation->SetNode(nullptr);
2236         relation->SetFlags(checker::TypeRelationFlag::NONE);
2237     }
2238 }
2239 
GetFunctionReturnType(ir::ReturnStatement * st,ir::ScriptFunction * containingFunc) const2240 checker::Type *ETSAnalyzer::GetFunctionReturnType(ir::ReturnStatement *st, ir::ScriptFunction *containingFunc) const
2241 {
2242     ASSERT(containingFunc->ReturnTypeAnnotation() != nullptr || containingFunc->Signature()->ReturnType() != nullptr);
2243 
2244     ETSChecker *checker = GetETSChecker();
2245     checker::Type *funcReturnType = nullptr;
2246 
2247     if (auto *const returnTypeAnnotation = containingFunc->ReturnTypeAnnotation(); returnTypeAnnotation != nullptr) {
2248         if (returnTypeAnnotation->IsTSThisType() &&
2249             (st->Argument() == nullptr || !st->Argument()->IsThisExpression())) {
2250             checker->ThrowTypeError(
2251                 "The only allowed return value is 'this' if the method's return type is the 'this' type", st->Start());
2252         }
2253 
2254         // Case when function's return type is defined explicitly:
2255         funcReturnType = checker->GetTypeFromTypeAnnotation(returnTypeAnnotation);
2256 
2257         if (st->argument_ == nullptr) {
2258             if (!funcReturnType->IsETSVoidType() && funcReturnType != checker->GlobalBuiltinVoidType()) {
2259                 checker->ThrowTypeError("Missing return value.", st->Start());
2260             }
2261             funcReturnType =
2262                 containingFunc->IsEntryPoint() ? checker->GlobalVoidType() : checker->GlobalBuiltinVoidType();
2263         } else {
2264             const auto name = containingFunc->Scope()->InternalName().Mutf8();
2265             CheckArgumentVoidType(funcReturnType, checker, name, st);
2266 
2267             if (st->argument_->IsObjectExpression()) {
2268                 st->argument_->AsObjectExpression()->SetPreferredType(funcReturnType);
2269             }
2270             if (st->argument_->IsMemberExpression()) {
2271                 checker->SetArrayPreferredTypeForNestedMemberExpressions(st->argument_->AsMemberExpression(),
2272                                                                          funcReturnType);
2273             }
2274 
2275             if (st->argument_->IsArrayExpression()) {
2276                 st->argument_->AsArrayExpression()->SetPreferredType(funcReturnType);
2277             }
2278 
2279             checker::Type *argumentType = st->argument_->Check(checker);
2280 
2281             CheckReturnType(checker, funcReturnType, argumentType, st->argument_);
2282         }
2283     } else {
2284         //  Case when function's return type should be inferred from return statement(s):
2285         if (containingFunc->Signature()->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE)) {
2286             InferReturnType(checker, containingFunc, funcReturnType, st->argument_);
2287         } else {
2288             //  All subsequent return statements:
2289             ProcessReturnStatements(checker, containingFunc, funcReturnType, st, st->argument_);
2290         }
2291     }
2292 
2293     if ((st->argument_ != nullptr) && st->argument_->IsArrayExpression()) {
2294         checker->ModifyPreferredType(st->argument_->AsArrayExpression(), funcReturnType);
2295         st->argument_->Check(checker);
2296     }
2297 
2298     return funcReturnType;
2299 }
2300 
Check(ir::ReturnStatement * st) const2301 checker::Type *ETSAnalyzer::Check(ir::ReturnStatement *st) const
2302 {
2303     ETSChecker *checker = GetETSChecker();
2304 
2305     ir::AstNode *ancestor = util::Helpers::FindAncestorGivenByType(st, ir::AstNodeType::SCRIPT_FUNCTION);
2306     ASSERT(ancestor && ancestor->IsScriptFunction());
2307     auto *containingFunc = ancestor->AsScriptFunction();
2308 
2309     if (containingFunc->IsConstructor()) {
2310         if (st->argument_ != nullptr) {
2311             checker->ThrowTypeError("Return statement with expression isn't allowed in constructor.", st->Start());
2312         }
2313         return nullptr;
2314     }
2315 
2316     st->returnType_ = GetFunctionReturnType(st, containingFunc);
2317     return nullptr;
2318 }
2319 
Check(ir::SwitchCaseStatement * st) const2320 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::SwitchCaseStatement *st) const
2321 {
2322     UNREACHABLE();
2323 }
2324 
Check(ir::SwitchStatement * st) const2325 checker::Type *ETSAnalyzer::Check(ir::SwitchStatement *st) const
2326 {
2327     ETSChecker *checker = GetETSChecker();
2328     checker::ScopeContext scopeCtx(checker, st->scope_);
2329     st->discriminant_->Check(checker);
2330     checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(checker->Relation(),
2331                                                                     checker::TypeRelationFlag::NONE);
2332     // NOTE (user): check exhaustive Switch
2333     checker->CheckSwitchDiscriminant(st->discriminant_);
2334     auto *comparedExprType = st->discriminant_->TsType();
2335     auto unboxedDiscType = (st->Discriminant()->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::UNBOXING_FLAG) != 0U
2336                                ? checker->ETSBuiltinTypeAsPrimitiveType(comparedExprType)
2337                                : comparedExprType;
2338 
2339     bool validCaseType;
2340 
2341     for (auto *it : st->Cases()) {
2342         if (it->Test() != nullptr) {
2343             auto *caseType = it->Test()->Check(checker);
2344             validCaseType = true;
2345             if (caseType->HasTypeFlag(checker::TypeFlag::CHAR)) {
2346                 validCaseType = comparedExprType->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL);
2347             } else if (caseType->IsETSEnumType() && st->Discriminant()->TsType()->IsETSEnumType()) {
2348                 validCaseType =
2349                     st->Discriminant()->TsType()->AsETSEnumType()->IsSameEnumType(caseType->AsETSEnumType());
2350             } else if (caseType->IsETSStringEnumType() && st->Discriminant()->TsType()->IsETSStringEnumType()) {
2351                 validCaseType = st->Discriminant()->TsType()->AsETSStringEnumType()->IsSameEnumType(
2352                     caseType->AsETSStringEnumType());
2353             } else {
2354                 checker::AssignmentContext(
2355                     checker->Relation(), st->discriminant_, caseType, unboxedDiscType, it->Test()->Start(),
2356                     {"Switch case type ", caseType, " is not comparable to discriminant type ", comparedExprType},
2357                     (comparedExprType->IsETSObjectType() ? checker::TypeRelationFlag::NO_WIDENING
2358                                                          : checker::TypeRelationFlag::NO_UNBOXING) |
2359                         checker::TypeRelationFlag::NO_BOXING);
2360             }
2361 
2362             if (!validCaseType) {
2363                 checker->ThrowTypeError(
2364                     {"Switch case type ", caseType, " is not comparable to discriminant type ", comparedExprType},
2365                     it->Test()->Start());
2366             }
2367         }
2368 
2369         for (auto *caseStmt : it->Consequent()) {
2370             caseStmt->Check(checker);
2371         }
2372     }
2373 
2374     checker->CheckForSameSwitchCases(&st->cases_);
2375 
2376     return nullptr;
2377 }
2378 
Check(ir::ThrowStatement * st) const2379 checker::Type *ETSAnalyzer::Check(ir::ThrowStatement *st) const
2380 {
2381     ETSChecker *checker = GetETSChecker();
2382     auto *argType = st->argument_->Check(checker);
2383     checker->CheckExceptionOrErrorType(argType, st->Start());
2384 
2385     if (checker->Relation()->IsAssignableTo(argType, checker->GlobalBuiltinExceptionType())) {
2386         checker->CheckThrowingStatements(st);
2387     }
2388     return nullptr;
2389 }
2390 
Check(ir::TryStatement * st) const2391 checker::Type *ETSAnalyzer::Check(ir::TryStatement *st) const
2392 {
2393     ETSChecker *checker = GetETSChecker();
2394     std::vector<checker::ETSObjectType *> exceptions;
2395     st->Block()->Check(checker);
2396 
2397     for (auto *catchClause : st->CatchClauses()) {
2398         auto exceptionType = catchClause->Check(checker);
2399         if ((exceptionType != nullptr) && (catchClause->Param() != nullptr)) {
2400             auto *clauseType = exceptionType->AsETSObjectType();
2401 
2402             for (auto *exception : exceptions) {
2403                 checker->Relation()->IsIdenticalTo(clauseType, exception);
2404                 if (checker->Relation()->IsTrue()) {
2405                     checker->ThrowTypeError("Redeclaration of exception type", catchClause->Start());
2406                 }
2407             }
2408 
2409             exceptions.push_back(clauseType);
2410         }
2411     }
2412 
2413     bool defaultCatchFound = false;
2414 
2415     for (auto *catchClause : st->CatchClauses()) {
2416         if (defaultCatchFound) {
2417             checker->ThrowTypeError("Default catch clause should be the last in the try statement",
2418                                     catchClause->Start());
2419         }
2420 
2421         defaultCatchFound = catchClause->IsDefaultCatchClause();
2422     }
2423 
2424     if (st->HasFinalizer()) {
2425         st->finalizer_->Check(checker);
2426     }
2427 
2428     return nullptr;
2429 }
2430 
Check(ir::VariableDeclarator * st) const2431 checker::Type *ETSAnalyzer::Check(ir::VariableDeclarator *st) const
2432 {
2433     ETSChecker *checker = GetETSChecker();
2434     ASSERT(st->Id()->IsIdentifier());
2435     ir::ModifierFlags flags = ir::ModifierFlags::NONE;
2436 
2437     if (st->Id()->Parent()->Parent()->AsVariableDeclaration()->Kind() ==
2438         ir::VariableDeclaration::VariableDeclarationKind::CONST) {
2439         flags |= ir::ModifierFlags::CONST;
2440     }
2441 
2442     st->SetTsType(checker->CheckVariableDeclaration(st->Id()->AsIdentifier(),
2443                                                     st->Id()->AsIdentifier()->TypeAnnotation(), st->Init(), flags));
2444     return st->TsType();
2445 }
2446 
Check(ir::VariableDeclaration * st) const2447 checker::Type *ETSAnalyzer::Check(ir::VariableDeclaration *st) const
2448 {
2449     ETSChecker *checker = GetETSChecker();
2450     for (auto *it : st->Declarators()) {
2451         it->Check(checker);
2452     }
2453 
2454     return nullptr;
2455 }
2456 
Check(ir::WhileStatement * st) const2457 checker::Type *ETSAnalyzer::Check(ir::WhileStatement *st) const
2458 {
2459     ETSChecker *checker = GetETSChecker();
2460     checker::ScopeContext scopeCtx(checker, st->Scope());
2461 
2462     checker->CheckTruthinessOfType(st->Test());
2463 
2464     st->Body()->Check(checker);
2465     return nullptr;
2466 }
2467 // from ts folder
Check(ir::TSAnyKeyword * node) const2468 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSAnyKeyword *node) const
2469 {
2470     UNREACHABLE();
2471 }
2472 
Check(ir::TSArrayType * node) const2473 checker::Type *ETSAnalyzer::Check(ir::TSArrayType *node) const
2474 {
2475     ETSChecker *checker = GetETSChecker();
2476     node->elementType_->Check(checker);
2477     return nullptr;
2478 }
2479 
Check(ir::TSAsExpression * expr) const2480 checker::Type *ETSAnalyzer::Check(ir::TSAsExpression *expr) const
2481 {
2482     ETSChecker *checker = GetETSChecker();
2483 
2484     auto *const targetType = expr->TypeAnnotation()->AsTypeNode()->GetType(checker);
2485     // Object expression requires that its type be set by the context before checking. in this case, the target type
2486     // provides that context.
2487     if (expr->Expr()->IsObjectExpression()) {
2488         expr->Expr()->AsObjectExpression()->SetPreferredType(targetType);
2489     }
2490 
2491     if (expr->Expr()->IsArrayExpression()) {
2492         expr->Expr()->AsArrayExpression()->SetPreferredType(targetType);
2493     }
2494 
2495     auto *const sourceType = expr->Expr()->Check(checker);
2496 
2497     if (targetType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) &&
2498         sourceType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT | checker::TypeFlag::TYPE_PARAMETER)) {
2499         auto *const boxedTargetType = checker->PrimitiveTypeAsETSBuiltinType(targetType);
2500         if (!checker->Relation()->IsIdenticalTo(sourceType, boxedTargetType)) {
2501             expr->Expr()->AddAstNodeFlags(ir::AstNodeFlags::CHECKCAST);
2502         }
2503     }
2504 
2505     const checker::CastingContext ctx(checker->Relation(), expr->Expr(), sourceType, targetType, expr->Expr()->Start(),
2506                                       {"Cannot cast type '", sourceType, "' to '", targetType, "'"});
2507 
2508     if (sourceType->IsETSDynamicType() && targetType->IsLambdaObject()) {
2509         // NOTE: itrubachev. change targetType to created lambdaobject type.
2510         // Now targetType is not changed, only construct signature is added to it
2511         checker->BuildLambdaObjectClass(targetType->AsETSObjectType(),
2512                                         expr->TypeAnnotation()->AsETSFunctionType()->ReturnType());
2513     }
2514     expr->isUncheckedCast_ = ctx.UncheckedCast();
2515 
2516     // Make sure the array type symbol gets created for the assembler to be able to emit checkcast.
2517     // Because it might not exist, if this particular array type was never created explicitly.
2518     if (!expr->isUncheckedCast_ && targetType->IsETSArrayType()) {
2519         auto *const targetArrayType = targetType->AsETSArrayType();
2520         checker->CreateBuiltinArraySignature(targetArrayType, targetArrayType->Rank());
2521     }
2522 
2523     expr->SetTsType(targetType);
2524     return expr->TsType();
2525 }
2526 
Check(ir::TSBigintKeyword * node) const2527 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSBigintKeyword *node) const
2528 {
2529     UNREACHABLE();
2530 }
2531 
Check(ir::TSBooleanKeyword * node) const2532 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSBooleanKeyword *node) const
2533 {
2534     UNREACHABLE();
2535 }
2536 
Check(ir::TSClassImplements * expr) const2537 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSClassImplements *expr) const
2538 {
2539     UNREACHABLE();
2540 }
2541 
Check(ir::TSConditionalType * node) const2542 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSConditionalType *node) const
2543 {
2544     UNREACHABLE();
2545 }
2546 
Check(ir::TSConstructorType * node) const2547 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSConstructorType *node) const
2548 {
2549     UNREACHABLE();
2550 }
2551 
Check(ir::TSEnumDeclaration * st) const2552 checker::Type *ETSAnalyzer::Check(ir::TSEnumDeclaration *st) const
2553 {
2554     ETSChecker *checker = GetETSChecker();
2555     varbinder::Variable *enumVar = st->Key()->Variable();
2556     ASSERT(enumVar != nullptr);
2557 
2558     if (enumVar->TsType() == nullptr) {
2559         checker::Type *etsEnumType;
2560         if (auto *const itemInit = st->Members().front()->AsTSEnumMember()->Init(); itemInit->IsNumberLiteral()) {
2561             etsEnumType = checker->CreateETSEnumType(st);
2562         } else if (itemInit->IsStringLiteral()) {
2563             etsEnumType = checker->CreateETSStringEnumType(st);
2564         } else {
2565             checker->ThrowTypeError("Invalid enumeration value type.", st->Start());
2566         }
2567         st->SetTsType(etsEnumType);
2568         etsEnumType->SetVariable(enumVar);
2569         enumVar->SetTsType(etsEnumType);
2570     } else if (st->TsType() == nullptr) {
2571         st->SetTsType(enumVar->TsType());
2572     }
2573 
2574     return st->TsType();
2575 }
2576 
Check(ir::TSEnumMember * st) const2577 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSEnumMember *st) const
2578 {
2579     UNREACHABLE();
2580 }
2581 
Check(ir::TSExternalModuleReference * expr) const2582 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSExternalModuleReference *expr) const
2583 {
2584     UNREACHABLE();
2585 }
2586 
Check(ir::TSFunctionType * node) const2587 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSFunctionType *node) const
2588 {
2589     UNREACHABLE();
2590 }
2591 
Check(ir::TSImportEqualsDeclaration * st) const2592 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSImportEqualsDeclaration *st) const
2593 {
2594     UNREACHABLE();
2595 }
2596 
Check(ir::TSImportType * node) const2597 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSImportType *node) const
2598 {
2599     UNREACHABLE();
2600 }
2601 
Check(ir::TSIndexedAccessType * node) const2602 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSIndexedAccessType *node) const
2603 {
2604     UNREACHABLE();
2605 }
2606 
Check(ir::TSInferType * node) const2607 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSInferType *node) const
2608 {
2609     UNREACHABLE();
2610 }
2611 
Check(ir::TSInterfaceBody * expr) const2612 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSInterfaceBody *expr) const
2613 {
2614     UNREACHABLE();
2615 }
2616 
Check(ir::TSInterfaceDeclaration * st) const2617 checker::Type *ETSAnalyzer::Check(ir::TSInterfaceDeclaration *st) const
2618 {
2619     ETSChecker *checker = GetETSChecker();
2620 
2621     checker::ETSObjectType *interfaceType {};
2622 
2623     if (st->TsType() == nullptr) {
2624         interfaceType = checker->BuildInterfaceProperties(st);
2625         ASSERT(interfaceType != nullptr);
2626         interfaceType->SetSuperType(checker->GlobalETSObjectType());
2627         checker->CheckInvokeMethodsLegitimacy(interfaceType);
2628         st->SetTsType(interfaceType);
2629     }
2630 
2631     checker::ScopeContext scopeCtx(checker, st->Scope());
2632     auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_INTERFACE, interfaceType);
2633 
2634     for (auto *it : st->Body()->Body()) {
2635         it->Check(checker);
2636     }
2637 
2638     return nullptr;
2639 }
2640 
Check(ir::TSInterfaceHeritage * expr) const2641 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSInterfaceHeritage *expr) const
2642 {
2643     UNREACHABLE();
2644 }
2645 
Check(ir::TSIntersectionType * node) const2646 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSIntersectionType *node) const
2647 {
2648     UNREACHABLE();
2649 }
2650 
Check(ir::TSLiteralType * node) const2651 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSLiteralType *node) const
2652 {
2653     UNREACHABLE();
2654 }
2655 
Check(ir::TSMappedType * node) const2656 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSMappedType *node) const
2657 {
2658     UNREACHABLE();
2659 }
2660 
Check(ir::TSModuleBlock * st) const2661 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSModuleBlock *st) const
2662 {
2663     UNREACHABLE();
2664 }
2665 
Check(ir::TSModuleDeclaration * st) const2666 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSModuleDeclaration *st) const
2667 {
2668     UNREACHABLE();
2669 }
2670 
Check(ir::TSNamedTupleMember * node) const2671 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSNamedTupleMember *node) const
2672 {
2673     UNREACHABLE();
2674 }
2675 
Check(ir::TSNeverKeyword * node) const2676 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSNeverKeyword *node) const
2677 {
2678     UNREACHABLE();
2679 }
2680 
Check(ir::TSNonNullExpression * expr) const2681 checker::Type *ETSAnalyzer::Check(ir::TSNonNullExpression *expr) const
2682 {
2683     ETSChecker *checker = GetETSChecker();
2684     auto exprType = expr->expr_->Check(checker);
2685     if (!checker->MayHaveNulllikeValue(exprType)) {
2686         checker->ThrowTypeError("Bad operand type, the operand of the non-null expression must be a nullable type",
2687                                 expr->Expr()->Start());
2688     }
2689 
2690     expr->SetTsType(exprType->IsNullish() ? checker->GetNonNullishType(exprType) : exprType);
2691     return expr->TsType();
2692 }
2693 
Check(ir::TSNullKeyword * node) const2694 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSNullKeyword *node) const
2695 {
2696     UNREACHABLE();
2697 }
2698 
Check(ir::TSNumberKeyword * node) const2699 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSNumberKeyword *node) const
2700 {
2701     UNREACHABLE();
2702 }
2703 
Check(ir::TSObjectKeyword * node) const2704 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSObjectKeyword *node) const
2705 {
2706     UNREACHABLE();
2707 }
2708 
Check(ir::TSParameterProperty * expr) const2709 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSParameterProperty *expr) const
2710 {
2711     UNREACHABLE();
2712 }
2713 
Check(ir::TSParenthesizedType * node) const2714 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSParenthesizedType *node) const
2715 {
2716     UNREACHABLE();
2717 }
2718 
Check(ir::TSQualifiedName * expr) const2719 checker::Type *ETSAnalyzer::Check(ir::TSQualifiedName *expr) const
2720 {
2721     ETSChecker *checker = GetETSChecker();
2722     checker::Type *baseType = expr->Left()->Check(checker);
2723     if (baseType->IsETSObjectType()) {
2724         varbinder::Variable *prop =
2725             baseType->AsETSObjectType()->GetProperty(expr->Right()->Name(), checker::PropertySearchFlags::SEARCH_DECL);
2726 
2727         if (prop != nullptr) {
2728             return checker->GetTypeOfVariable(prop);
2729         }
2730     }
2731 
2732     checker->ThrowTypeError({"'", expr->Right()->Name(), "' type does not exist."}, expr->Right()->Start());
2733 }
2734 
Check(ir::TSStringKeyword * node) const2735 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSStringKeyword *node) const
2736 {
2737     UNREACHABLE();
2738 }
2739 
Check(ir::TSThisType * node) const2740 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSThisType *node) const
2741 {
2742     UNREACHABLE();
2743 }
2744 
Check(ir::TSTupleType * node) const2745 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTupleType *node) const
2746 {
2747     UNREACHABLE();
2748 }
2749 
Check(ir::TSTypeAliasDeclaration * st) const2750 checker::Type *ETSAnalyzer::Check(ir::TSTypeAliasDeclaration *st) const
2751 {
2752     ETSChecker *checker = GetETSChecker();
2753     if (st->TypeParams() != nullptr) {
2754         st->SetTypeParameterTypes(checker->CreateTypeForTypeParameters(st->TypeParams()));
2755         for (auto *const param : st->TypeParams()->Params()) {
2756             const auto *const res = st->TypeAnnotation()->FindChild([&param](const ir::AstNode *const node) {
2757                 if (!node->IsIdentifier()) {
2758                     return false;
2759                 }
2760 
2761                 return param->Name()->AsIdentifier()->Variable() == node->AsIdentifier()->Variable();
2762             });
2763 
2764             if (res == nullptr) {
2765                 checker->ThrowTypeError(
2766                     {"Type alias generic parameter '", param->Name()->Name(), "' is not used in type annotation"},
2767                     param->Start());
2768             }
2769         }
2770     }
2771 
2772     const checker::SavedTypeRelationFlagsContext savedFlagsCtx(checker->Relation(),
2773                                                                checker::TypeRelationFlag::NO_THROW_GENERIC_TYPEALIAS);
2774 
2775     st->TypeAnnotation()->Check(checker);
2776 
2777     return nullptr;
2778 }
2779 
Check(ir::TSTypeAssertion * expr) const2780 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeAssertion *expr) const
2781 {
2782     UNREACHABLE();
2783 }
2784 
Check(ir::TSTypeLiteral * node) const2785 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeLiteral *node) const
2786 {
2787     UNREACHABLE();
2788 }
2789 
Check(ir::TSTypeOperator * node) const2790 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeOperator *node) const
2791 {
2792     UNREACHABLE();
2793 }
2794 
Check(ir::TSTypeParameter * expr) const2795 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeParameter *expr) const
2796 {
2797     UNREACHABLE();
2798 }
2799 
Check(ir::TSTypeParameterDeclaration * expr) const2800 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeParameterDeclaration *expr) const
2801 {
2802     UNREACHABLE();
2803 }
2804 
Check(ir::TSTypeParameterInstantiation * expr) const2805 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeParameterInstantiation *expr) const
2806 {
2807     UNREACHABLE();
2808 }
2809 
Check(ir::TSTypePredicate * node) const2810 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypePredicate *node) const
2811 {
2812     UNREACHABLE();
2813 }
2814 
Check(ir::TSTypeQuery * node) const2815 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeQuery *node) const
2816 {
2817     UNREACHABLE();
2818 }
2819 
Check(ir::TSTypeReference * node) const2820 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeReference *node) const
2821 {
2822     UNREACHABLE();
2823 }
2824 
Check(ir::TSUndefinedKeyword * node) const2825 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSUndefinedKeyword *node) const
2826 {
2827     UNREACHABLE();
2828 }
2829 
Check(ir::TSUnionType * node) const2830 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSUnionType *node) const
2831 {
2832     UNREACHABLE();
2833 }
2834 
Check(ir::TSUnknownKeyword * node) const2835 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSUnknownKeyword *node) const
2836 {
2837     UNREACHABLE();
2838 }
2839 
Check(ir::TSVoidKeyword * node) const2840 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSVoidKeyword *node) const
2841 {
2842     UNREACHABLE();
2843 }
2844 
2845 }  // namespace panda::es2panda::checker
2846