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 "types/signature.h"
19 #include "util/helpers.h"
20 #include "checker/ETSchecker.h"
21 #include "checker/ets/castingContext.h"
22 #include "checker/ets/typeRelationContext.h"
23 #include "checker/types/globalTypesHolder.h"
24 #include "checker/types/ets/etsTupleType.h"
25 #include "checker/types/ets/etsAsyncFuncReturnType.h"
26 #include "evaluate/scopedDebugInfoPlugin.h"
27 #include "types/ts/undefinedType.h"
28 #include "ir/statements/namespaceDeclaration.h"
29 
30 namespace ark::es2panda::checker {
31 
GetETSChecker() const32 ETSChecker *ETSAnalyzer::GetETSChecker() const
33 {
34     return static_cast<ETSChecker *>(GetChecker());
35 }
36 
37 // from base folder
Check(ir::CatchClause *st) const38 checker::Type *ETSAnalyzer::Check(ir::CatchClause *st) const
39 {
40     ETSChecker *checker = GetETSChecker();
41     checker::ETSObjectType *exceptionType = checker->GlobalETSObjectType();
42 
43     ir::Identifier *paramIdent = st->Param()->AsIdentifier();
44 
45     if (paramIdent->TypeAnnotation() != nullptr) {
46         checker::Type *catchParamAnnotationType = paramIdent->TypeAnnotation()->GetType(checker);
47 
48         exceptionType = checker->CheckExceptionOrErrorType(catchParamAnnotationType, st->Param()->Start());
49     }
50 
51     paramIdent->Variable()->SetTsType(exceptionType);
52 
53     st->Body()->Check(checker);
54 
55     st->SetTsType(exceptionType);
56     return exceptionType;
57 }
58 
Check(ir::ClassDefinition *node) const59 checker::Type *ETSAnalyzer::Check(ir::ClassDefinition *node) const
60 {
61     ETSChecker *checker = GetETSChecker();
62 
63     if (node->TsTypeOrError() == nullptr) {
64         checker->BuildBasicClassProperties(node);
65     }
66 
67     if (!node->IsClassDefinitionChecked()) {
68         checker->CheckClassDefinition(node);
69     }
70 
71     return nullptr;
72 }
73 
Check(ir::ClassProperty *st) const74 checker::Type *ETSAnalyzer::Check(ir::ClassProperty *st) const
75 {
76     ASSERT(st->Id() != nullptr);
77     ETSChecker *checker = GetETSChecker();
78 
79     if (st->TsTypeOrError() != nullptr) {
80         return st->TsTypeOrError();
81     }
82 
83     checker::SavedCheckerContext savedContext(checker, checker->Context().Status(),
84                                               checker->Context().ContainingClass(),
85                                               checker->Context().ContainingSignature());
86 
87     if (st->IsStatic()) {
88         checker->AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT);
89     }
90 
91     st->SetTsType(checker->CheckVariableDeclaration(st->Id(), st->TypeAnnotation(), st->Value(), st->Modifiers()));
92 
93     return st->TsTypeOrError();
94 }
95 
Check(ir::ClassStaticBlock *st) const96 checker::Type *ETSAnalyzer::Check(ir::ClassStaticBlock *st) const
97 {
98     ETSChecker *checker = GetETSChecker();
99 
100     if (checker->HasStatus(checker::CheckerStatus::INNER_CLASS)) {
101         checker->LogTypeError("Static initializer is not allowed in inner class.", st->Start());
102         st->SetTsType(checker->GlobalTypeError());
103         return st->TsTypeOrError();
104     }
105 
106     auto *func = st->Function();
107     checker->BuildFunctionSignature(func);
108     if (func->Signature() == nullptr) {
109         st->SetTsType(checker->GlobalTypeError());
110         return st->TsTypeOrError();
111     }
112     st->SetTsType(checker->BuildNamedFunctionType(func));
113     checker::ScopeContext scopeCtx(checker, func->Scope());
114     checker::SavedCheckerContext savedContext(checker, checker->Context().Status(),
115                                               checker->Context().ContainingClass());
116     checker->AddStatus(checker::CheckerStatus::IN_STATIC_BLOCK | checker::CheckerStatus::IN_STATIC_CONTEXT);
117     func->Body()->Check(checker);
118     return st->TsType();
119 }
120 
121 // Satisfy the Chinese code checker
HandleNativeAndAsyncMethods(ETSChecker *checker, ir::MethodDefinition *node)122 static void HandleNativeAndAsyncMethods(ETSChecker *checker, ir::MethodDefinition *node)
123 {
124     auto *scriptFunc = node->Function();
125     if (node->IsNative()) {
126         if (scriptFunc->ReturnTypeAnnotation() == nullptr) {
127             checker->LogTypeError("'Native' method should have explicit return type", scriptFunc->Start());
128             node->SetTsType(checker->GlobalTypeError());
129         }
130         ASSERT(!scriptFunc->IsGetter() && !scriptFunc->IsSetter());
131     }
132 
133     if (IsAsyncMethod(node)) {
134         if (scriptFunc->ReturnTypeAnnotation() != nullptr) {
135             auto *asyncFuncReturnType = scriptFunc->Signature()->ReturnType();
136 
137             if (!asyncFuncReturnType->IsETSObjectType() ||
138                 asyncFuncReturnType->AsETSObjectType()->GetOriginalBaseType() != checker->GlobalBuiltinPromiseType()) {
139                 checker->LogTypeError("Return type of async function must be 'Promise'.", scriptFunc->Start());
140                 scriptFunc->Signature()->SetReturnType(checker->GlobalTypeError());
141                 return;
142             }
143         }
144 
145         if (node->Function()->HasBody()) {
146             ComposeAsyncImplMethod(checker, node);
147         }
148     }
149 }
150 
Check(ir::MethodDefinition *node) const151 checker::Type *ETSAnalyzer::Check(ir::MethodDefinition *node) const
152 {
153     ETSChecker *checker = GetETSChecker();
154 
155     auto *scriptFunc = node->Function();
156 
157     if (scriptFunc == nullptr) {
158         checker->LogTypeError("Invalid function expression", node->Start());
159         node->SetTsType(checker->GlobalTypeError());
160         return node->TsTypeOrError();
161     }
162 
163     if (scriptFunc->IsProxy()) {
164         return nullptr;
165     }
166 
167     // NOTE: aszilagyi. make it correctly check for open function not have body
168     if (!scriptFunc->HasBody() && !(node->IsAbstract() || node->IsNative() || node->IsDeclare() ||
169                                     checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) {
170         checker->LogTypeError("Only abstract or native methods can't have body.", scriptFunc->Start());
171         node->SetTsType(checker->GlobalTypeError());
172         return node->TsTypeOrError();
173     }
174 
175     if (scriptFunc->ReturnTypeAnnotation() == nullptr &&
176         (node->IsNative() || (node->IsDeclare() && !node->IsConstructor()))) {
177         checker->LogTypeError("Native and Declare methods should have explicit return type.", scriptFunc->Start());
178         node->SetTsType(checker->GlobalTypeError());
179         return node->TsTypeOrError();
180     }
181 
182     if (node->TsTypeOrError() == nullptr) {
183         node->SetTsType(checker->BuildMethodSignature(node));
184     }
185 
186     this->CheckMethodModifiers(node);
187     HandleNativeAndAsyncMethods(checker, node);
188     DoBodyTypeChecking(checker, node, scriptFunc);
189     CheckPredefinedMethodReturnType(checker, scriptFunc);
190     if (node->TsTypeOrError()->IsTypeError()) {
191         return node->TsTypeOrError();
192     }
193     // NOTE(gogabr): temporary, until we have proper bridges, see #16485
194     // Don't check overriding for synthetic functional classes.
195     if ((node->Parent()->Modifiers() & ir::ModifierFlags::FUNCTIONAL) == 0) {
196         checker->CheckOverride(node->TsType()->AsETSFunctionType()->FindSignature(node->Function()));
197     }
198 
199     for (auto *overload : node->Overloads()) {
200         overload->Check(checker);
201     }
202 
203     if (scriptFunc->IsRethrowing()) {
204         checker->CheckRethrowingFunction(scriptFunc);
205     }
206 
207     return node->TsType();
208 }
209 
CheckMethodModifiers(ir::MethodDefinition *node) const210 void ETSAnalyzer::CheckMethodModifiers(ir::MethodDefinition *node) const
211 {
212     ETSChecker *checker = GetETSChecker();
213     auto const notValidInAbstract = ir::ModifierFlags::NATIVE | ir::ModifierFlags::PRIVATE |
214                                     ir::ModifierFlags::OVERRIDE | ir::ModifierFlags::FINAL | ir::ModifierFlags::STATIC;
215 
216     if (node->IsAbstract() && (node->flags_ & notValidInAbstract) != 0U) {
217         checker->LogTypeError(
218             "Invalid method modifier(s): an abstract method can't have private, override, static, final or native "
219             "modifier.",
220             node->Start());
221         node->SetTsType(checker->GlobalTypeError());
222         return;
223     }
224 
225     if (node->Function() == nullptr) {
226         checker->LogTypeError("Invalid function expression", node->Start());
227         node->SetTsType(checker->GlobalTypeError());
228         return;
229     }
230 
231     if ((node->IsAbstract() || (!node->Function()->HasBody() && !node->IsNative() && !node->IsDeclare())) &&
232         !(checker->HasStatus(checker::CheckerStatus::IN_ABSTRACT) ||
233           checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) {
234         checker->LogTypeError("Non abstract class has abstract method.", node->Start());
235         node->SetTsType(checker->GlobalTypeError());
236     }
237 
238     auto const notValidInFinal = ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::STATIC | ir::ModifierFlags::NATIVE;
239 
240     if (node->IsFinal() && (node->flags_ & notValidInFinal) != 0U) {
241         checker->LogTypeError(
242             "Invalid method modifier(s): a final method can't have abstract, static or native modifier.",
243             node->Start());
244         node->SetTsType(checker->GlobalTypeError());
245     }
246 
247     auto const notValidInStatic = ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::FINAL | ir::ModifierFlags::OVERRIDE;
248 
249     if (node->IsStatic() && (node->flags_ & notValidInStatic) != 0U) {
250         checker->LogTypeError(
251             "Invalid method modifier(s): a static method can't have abstract, final or override modifier.",
252             node->Start());
253         node->SetTsType(checker->GlobalTypeError());
254     }
255 }
256 
Check([[maybe_unused]] ir::Property *expr) const257 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::Property *expr) const
258 {
259     return nullptr;
260 }
261 
Check([[maybe_unused]] ir::SpreadElement *expr) const262 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::SpreadElement *expr) const
263 {
264     ETSChecker *checker = GetETSChecker();
265     checker::Type *elementType =
266         expr->AsSpreadElement()->Argument()->AsIdentifier()->Check(checker)->AsETSArrayType()->ElementType();
267     expr->SetTsType(elementType);
268     return expr->TsType();
269 }
270 
Check(ir::TemplateElement *expr) const271 checker::Type *ETSAnalyzer::Check(ir::TemplateElement *expr) const
272 {
273     ETSChecker *checker = GetETSChecker();
274     expr->SetTsType(checker->CreateETSStringLiteralType(expr->Raw()));
275     return expr->TsType();
276 }
277 
Check(ir::ETSClassLiteral *expr) const278 checker::Type *ETSAnalyzer::Check(ir::ETSClassLiteral *expr) const
279 {
280     ETSChecker *checker = GetETSChecker();
281     auto *const literal = expr->Expr();
282 
283     checker->LogTypeError("Class literal is not yet supported.", literal->Start());
284     expr->SetTsType(checker->GlobalTypeError());
285     return expr->TsTypeOrError();
286 
287     auto *exprType = literal->Check(checker);
288 
289     if (exprType->IsETSVoidType()) {
290         checker->LogTypeError("Invalid .class reference", literal->Start());
291         expr->SetTsType(checker->GlobalTypeError());
292         return expr->TsTypeOrError();
293     }
294 
295     ArenaVector<checker::Type *> typeArgTypes(checker->Allocator()->Adapter());
296     typeArgTypes.push_back(exprType);  // NOTE: Box it if it's a primitive type
297 
298     checker::InstantiationContext ctx(checker, checker->GlobalBuiltinTypeType(), std::move(typeArgTypes),
299                                       expr->Range().start);
300     expr->SetTsType(ctx.Result());
301 
302     return expr->TsTypeOrError();
303 }
304 
Check(ir::ETSFunctionType *node) const305 checker::Type *ETSAnalyzer::Check(ir::ETSFunctionType *node) const
306 {
307     if (node->TsType() != nullptr) {
308         return node->TsType();
309     }
310     ETSChecker *checker = GetETSChecker();
311 
312     size_t optionalParameterIndex = node->DefaultParamIndex();
313     auto *genericInterfaceType = checker->GlobalBuiltinFunctionType(node->Params().size(), node->Flags());
314     node->SetFunctionalInterface(genericInterfaceType->GetDeclNode()->AsTSInterfaceDeclaration());
315 
316     auto *tsType = checker->GetCachedFunctionalInterface(node);
317     node->SetTsType(tsType);
318     if (tsType != nullptr) {
319         return tsType;
320     }
321 
322     auto *substitution = checker->NewSubstitution();
323     ETSObjectType *interfaceType;
324 
325     if (optionalParameterIndex == node->Params().size()) {
326         interfaceType = CreateInterfaceTypeForETSFunctionType(checker, node, genericInterfaceType, substitution);
327     } else {
328         interfaceType = CreateOptionalSignaturesForFunctionalType(checker, node, genericInterfaceType, substitution,
329                                                                   optionalParameterIndex);
330     }
331 
332     node->SetTsType(interfaceType);
333     return interfaceType;
334 }
335 
Check(ir::ETSLaunchExpression *expr) const336 checker::Type *ETSAnalyzer::Check(ir::ETSLaunchExpression *expr) const
337 {
338     ETSChecker *checker = GetETSChecker();
339     expr->expr_->Check(checker);
340     auto *const launchPromiseType =
341         checker->GlobalBuiltinPromiseType()
342             ->Instantiate(checker->Allocator(), checker->Relation(), checker->GetGlobalTypesHolder())
343             ->AsETSObjectType();
344     launchPromiseType->AddTypeFlag(checker::TypeFlag::GENERIC);
345 
346     // Launch expression returns a Promise<T> type, so we need to insert the expression's type
347     // as type parameter for the Promise class.
348 
349     auto exprType = [&checker](auto *tsType) {
350         if (tsType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
351             return checker->PrimitiveTypeAsETSBuiltinType(tsType);
352         }
353 
354         return tsType;
355     }(expr->expr_->TsType());
356 
357     checker::Substitution *substitution = checker->NewSubstitution();
358     ASSERT(launchPromiseType->TypeArguments().size() == 1);
359     checker::ETSChecker::EmplaceSubstituted(
360         substitution, launchPromiseType->TypeArguments()[0]->AsETSTypeParameter()->GetOriginal(), exprType);
361 
362     expr->SetTsType(launchPromiseType->Substitute(checker->Relation(), substitution));
363     return expr->TsType();
364 }
365 
Check(ir::ETSNewArrayInstanceExpression *expr) const366 checker::Type *ETSAnalyzer::Check(ir::ETSNewArrayInstanceExpression *expr) const
367 {
368     ETSChecker *checker = GetETSChecker();
369 
370     auto *elementType = expr->TypeReference()->GetType(checker);
371     checker->ValidateArrayIndex(expr->Dimension(), true);
372     if (!elementType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
373         if (elementType->IsETSUnionType() && !elementType->AsETSUnionType()->HasNullishType(checker)) {
374             checker->LogTypeError({"Union types in array declaration must include a nullish type."}, expr->Start());
375             expr->SetTsType(checker->GlobalTypeError());
376             return expr->TsTypeOrError();
377         }
378         if (elementType->IsETSObjectType()) {
379             auto *calleeObj = elementType->AsETSObjectType();
380             const auto flags = checker::ETSObjectFlags::ABSTRACT | checker::ETSObjectFlags::INTERFACE;
381             if (!calleeObj->HasObjectFlag(flags)) {
382                 // A workaround check for new Interface[...] in test cases
383                 expr->SetSignature(
384                     checker->CollectParameterlessConstructor(calleeObj->ConstructSignatures(), expr->Start()));
385                 checker->ValidateSignatureAccessibility(calleeObj, nullptr, expr->Signature(), expr->Start());
386             } else {
387                 checker->LogTypeError("Cannot use array creation expression with abstract classes and interfaces.",
388                                       expr->Start());
389                 expr->SetTsType(checker->GlobalTypeError());
390                 return expr->TsTypeOrError();
391             }
392         }
393     }
394     expr->SetTsType(checker->CreateETSArrayType(elementType));
395     checker->CreateBuiltinArraySignature(expr->TsType()->AsETSArrayType(), 1);
396     return expr->TsType();
397 }
398 
CheckInstantatedClass(ir::ETSNewClassInstanceExpression *expr, ETSObjectType *&calleeObj) const399 void ETSAnalyzer::CheckInstantatedClass(ir::ETSNewClassInstanceExpression *expr, ETSObjectType *&calleeObj) const
400 {
401     ETSChecker *checker = GetETSChecker();
402     if (expr->ClassDefinition() != nullptr) {
403         if (calleeObj->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT) && calleeObj->GetDeclNode()->IsFinal()) {
404             checker->LogTypeError({"Class ", calleeObj->Name(), " cannot be both 'abstract' and 'final'."},
405                                   calleeObj->GetDeclNode()->Start());
406             expr->SetTsType(checker->GlobalTypeError());
407             return;
408         }
409 
410         bool fromInterface = calleeObj->HasObjectFlag(checker::ETSObjectFlags::INTERFACE);
411         auto *classType = checker->BuildAnonymousClassProperties(
412             expr->ClassDefinition(), fromInterface ? checker->GlobalETSObjectType() : calleeObj);
413         if (fromInterface) {
414             classType->AddInterface(calleeObj);
415             calleeObj = checker->GlobalETSObjectType();
416         }
417         expr->ClassDefinition()->SetTsType(classType);
418         checker->CheckClassDefinition(expr->ClassDefinition());
419         checker->CheckInnerClassMembers(classType);
420         expr->SetTsType(classType);
421     } else if (calleeObj->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT)) {
422         checker->LogTypeError({calleeObj->Name(), " is abstract therefore cannot be instantiated."}, expr->Start());
423         expr->SetTsType(checker->GlobalTypeError());
424     }
425 
426     if (calleeObj->HasObjectFlag(ETSObjectFlags::REQUIRED) &&
427         !expr->HasAstNodeFlags(ir::AstNodeFlags::ALLOW_REQUIRED_INSTANTIATION)) {
428         checker->LogTypeError("Required type can be instantiated only with object literal",
429                               expr->GetTypeRef()->Start());
430         expr->SetTsType(checker->GlobalTypeError());
431     }
432 }
433 
Check(ir::ETSNewClassInstanceExpression *expr) const434 checker::Type *ETSAnalyzer::Check(ir::ETSNewClassInstanceExpression *expr) const
435 {
436     ETSChecker *checker = GetETSChecker();
437     auto *calleeType = GetCalleeType(checker, expr);
438     if (calleeType == nullptr) {
439         return expr->TsType();
440     }
441 
442     if (calleeType->IsTypeError()) {
443         expr->SetTsType(calleeType);
444         return expr->TsTypeOrError();
445     }
446     auto *calleeObj = calleeType->AsETSObjectType();
447     expr->SetTsType(calleeObj);
448 
449     CheckInstantatedClass(expr, calleeObj);
450 
451     if (calleeType->IsETSDynamicType() && !calleeType->AsETSDynamicType()->HasDecl()) {
452         auto lang = calleeType->AsETSDynamicType()->Language();
453         expr->SetSignature(checker->ResolveDynamicCallExpression(expr->GetTypeRef(), expr->GetArguments(), lang, true));
454     } else {
455         auto *signature = checker->ResolveConstructExpression(calleeObj, expr->GetArguments(), expr->Start());
456 
457         if (signature == nullptr) {
458             expr->SetTsType(checker->GlobalTypeError());
459             return expr->TsTypeOrError();
460         }
461 
462         checker->CheckObjectLiteralArguments(signature, expr->GetArguments());
463 
464         checker->ValidateSignatureAccessibility(calleeObj, nullptr, signature, expr->Start());
465 
466         ASSERT(signature->Function() != nullptr);
467 
468         if (signature->Function()->IsThrowing() || signature->Function()->IsRethrowing()) {
469             checker->CheckThrowingStatements(expr);
470         }
471 
472         if (calleeType->IsETSDynamicType()) {
473             ASSERT(signature->Function()->IsDynamic());
474             auto lang = calleeType->AsETSDynamicType()->Language();
475             expr->SetSignature(
476                 checker->ResolveDynamicCallExpression(expr->GetTypeRef(), signature->Params(), lang, true));
477         } else {
478             ASSERT(!signature->Function()->IsDynamic());
479             expr->SetSignature(signature);
480         }
481     }
482 
483     return expr->TsTypeOrError();
484 }
485 
Check(ir::ETSNewMultiDimArrayInstanceExpression *expr) const486 checker::Type *ETSAnalyzer::Check(ir::ETSNewMultiDimArrayInstanceExpression *expr) const
487 {
488     ETSChecker *checker = GetETSChecker();
489     auto *elementType = expr->TypeReference()->GetType(checker);
490 
491     for (auto *dim : expr->Dimensions()) {
492         checker->ValidateArrayIndex(dim, true);
493         elementType = checker->CreateETSArrayType(elementType);
494     }
495 
496     expr->SetTsType(elementType);
497     expr->SetSignature(checker->CreateBuiltinArraySignature(elementType->AsETSArrayType(), expr->Dimensions().size()));
498     return expr->TsType();
499 }
500 
Check([[maybe_unused]] ir::ETSPackageDeclaration *st) const501 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSPackageDeclaration *st) const
502 {
503     return nullptr;
504 }
505 
Check(ir::ETSParameterExpression *expr) const506 checker::Type *ETSAnalyzer::Check(ir::ETSParameterExpression *expr) const
507 {
508     ETSChecker *checker = GetETSChecker();
509     if (expr->TsTypeOrError() == nullptr) {
510         checker::Type *paramType;
511 
512         if (expr->Ident()->TsTypeOrError() != nullptr) {
513             paramType = expr->Ident()->TsTypeOrError();
514         } else {
515             paramType = !expr->IsRestParameter() ? expr->Ident()->Check(checker) : expr->spread_->Check(checker);
516             if (expr->IsDefault()) {
517                 std::cout << __LINE__ << std::endl;
518                 [[maybe_unused]] auto *const initType = expr->Initializer()->Check(checker);
519             }
520         }
521 
522         expr->SetTsType(paramType);
523     }
524 
525     return expr->TsType();
526 }
527 
Check([[maybe_unused]] ir::ETSPrimitiveType *node) const528 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSPrimitiveType *node) const
529 {
530     ETSChecker *checker = GetETSChecker();
531     return node->GetType(checker);
532 }
533 
Check(ir::ETSStructDeclaration *node) const534 checker::Type *ETSAnalyzer::Check(ir::ETSStructDeclaration *node) const
535 {
536     ETSChecker *checker = GetETSChecker();
537     node->Definition()->Check(checker);
538     return nullptr;
539 }
540 
Check(ir::ETSTypeReference *node) const541 checker::Type *ETSAnalyzer::Check(ir::ETSTypeReference *node) const
542 {
543     ETSChecker *checker = GetETSChecker();
544     return node->GetType(checker);
545 }
546 
Check(ir::ETSTypeReferencePart *node) const547 checker::Type *ETSAnalyzer::Check(ir::ETSTypeReferencePart *node) const
548 {
549     ETSChecker *checker = GetETSChecker();
550     return node->GetType(checker);
551 }
552 
Check([[maybe_unused]] ir::ETSNullType *node) const553 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSNullType *node) const
554 {
555     return nullptr;
556 }
557 
Check([[maybe_unused]] ir::ETSUndefinedType *node) const558 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSUndefinedType *node) const
559 {
560     return nullptr;
561 }
562 
Check([[maybe_unused]] ir::ETSStringLiteralType *node) const563 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSStringLiteralType *node) const
564 {
565     ETSChecker *checker = GetETSChecker();
566     return node->GetType(checker);
567 }
568 
569 // compile methods for EXPRESSIONS in alphabetical order
570 
GetPreferredType(ir::ArrayExpression *expr) const571 checker::Type *ETSAnalyzer::GetPreferredType(ir::ArrayExpression *expr) const
572 {
573     return expr->preferredType_;
574 }
575 
CheckArrayElement(ETSChecker *checker, checker::Type *elementType, std::vector<checker::Type *> targetElementType, ir::Expression *currentElement, bool &isSecondaryChosen)576 static bool CheckArrayElement(ETSChecker *checker, checker::Type *elementType,
577                               std::vector<checker::Type *> targetElementType, ir::Expression *currentElement,
578                               bool &isSecondaryChosen)
579 {
580     if ((targetElementType[0]->IsETSArrayType() &&
581          targetElementType[0]->AsETSArrayType()->ElementType()->IsETSArrayType() &&
582          !(targetElementType[0]->AsETSArrayType()->ElementType()->IsETSTupleType() &&
583            targetElementType[1] == nullptr)) ||
584         (!checker::AssignmentContext(checker->Relation(), currentElement, elementType, targetElementType[0],
585                                      currentElement->Start(),
586                                      {"Array element type '", elementType, "' is not assignable to explicit type '",
587                                       targetElementType[0], "'"},
588                                      TypeRelationFlag::NO_THROW)
589               .IsAssignable() &&
590          !(targetElementType[0]->IsETSArrayType() && currentElement->IsArrayExpression()))) {
591         if (targetElementType[1] == nullptr) {
592             checker->LogTypeError({"Array element type '", elementType, "' is not assignable to explicit type '",
593                                    targetElementType[0], "'"},
594                                   currentElement->Start());
595             return false;
596         }
597 
598         if (!(targetElementType[0]->IsETSArrayType() && currentElement->IsArrayExpression()) &&
599             !checker::AssignmentContext(checker->Relation(), currentElement, elementType, targetElementType[1],
600                                         currentElement->Start(),
601                                         {"Array element type '", elementType, "' is not assignable to explicit type '",
602                                          targetElementType[1], "'"},
603                                         TypeRelationFlag::NO_THROW)
604                  .IsAssignable()) {
605             checker->LogTypeError({"Array element type '", elementType, "' is not assignable to explicit type '",
606                                    targetElementType[1], "'"},
607                                   currentElement->Start());
608             return false;
609         }
610         isSecondaryChosen = true;
611     }
612     return true;
613 }
614 
CheckElement(ir::ArrayExpression *expr, ETSChecker *checker, std::vector<checker::Type *> targetElementType, bool isPreferredTuple)615 static bool CheckElement(ir::ArrayExpression *expr, ETSChecker *checker, std::vector<checker::Type *> targetElementType,
616                          bool isPreferredTuple)
617 {
618     bool isSecondaryChosen = false;
619     bool ok = true;
620 
621     for (std::size_t idx = 0; idx < expr->Elements().size(); ++idx) {
622         auto *const currentElement = expr->Elements()[idx];
623 
624         if (currentElement->IsArrayExpression()) {
625             if (!expr->HandleNestedArrayExpression(checker, currentElement->AsArrayExpression(), isPreferredTuple,
626                                                    idx)) {
627                 continue;
628             }
629         }
630 
631         if (currentElement->IsObjectExpression()) {
632             currentElement->AsObjectExpression()->SetPreferredType(
633                 expr->GetPreferredType()->AsETSArrayType()->ElementType());
634         }
635 
636         checker::Type *elementType = currentElement->Check(checker);
637 
638         if (!elementType->IsETSArrayType() && isPreferredTuple) {
639             auto const *const tupleType = expr->GetPreferredType()->AsETSTupleType();
640 
641             auto *compareType = tupleType->GetTypeAtIndex(idx);
642             if (compareType == nullptr) {
643                 checker->LogTypeError({"Too many elements in array initializer for tuple with size of ",
644                                        static_cast<uint32_t>(tupleType->GetTupleSize())},
645                                       currentElement->Start());
646                 ok = false;
647                 continue;
648             }
649             // clang-format off
650             if (!AssignmentContext(checker->Relation(), currentElement, elementType, compareType,
651                                    currentElement->Start(), {}, TypeRelationFlag::NO_THROW).IsAssignable()) {
652                 checker->LogTypeError({"Array initializer's type is not assignable to tuple type at index: ", idx},
653                                       currentElement->Start());
654                                       ok=false;
655                 continue;
656             }
657             // clang-format on
658 
659             elementType = compareType;
660         }
661 
662         if (targetElementType[0] == elementType) {
663             continue;
664         }
665 
666         if (!CheckArrayElement(checker, elementType, targetElementType, currentElement, isSecondaryChosen)) {
667             ok = false;
668             continue;
669         }
670     }
671 
672     return ok;
673 }
674 
Check(ir::ArrayExpression *expr) const675 checker::Type *ETSAnalyzer::Check(ir::ArrayExpression *expr) const
676 {
677     ETSChecker *checker = GetETSChecker();
678     if (expr->TsTypeOrError() != nullptr) {
679         return expr->TsTypeOrError();
680     }
681 
682     if (expr->preferredType_ != nullptr && !expr->preferredType_->IsETSArrayType() &&
683         !checker->Relation()->IsSupertypeOf(expr->preferredType_, checker->GlobalETSObjectType())) {
684         checker->LogTypeError({"Expected type for array literal should be an array type, got ", expr->preferredType_},
685                               expr->Start());
686         expr->SetTsType(checker->GlobalTypeError());
687         return expr->TsTypeOrError();
688     }
689 
690     const bool isArray = (expr->preferredType_ != nullptr) && expr->preferredType_->IsETSArrayType() &&
691                          !expr->preferredType_->IsETSTupleType();
692 
693     if (!expr->Elements().empty()) {
694         if (expr->preferredType_ == nullptr || expr->preferredType_ == checker->GlobalETSObjectType()) {
695             expr->preferredType_ = checker->CreateETSArrayType(expr->Elements()[0]->Check(checker));
696         }
697 
698         const bool isPreferredTuple = expr->preferredType_->IsETSTupleType();
699         // NOTE(aakmaev): Need to rework type inference of array literal (#19096 internal issue)
700         auto *targetElementType =
701             checker->GetNonConstantType(expr->GetPreferredType()->AsETSArrayType()->ElementType());
702         Type *targetElementTypeSecondary = nullptr;
703         if (isPreferredTuple && !isArray) {
704             targetElementTypeSecondary = expr->GetPreferredType()->AsETSTupleType()->ElementType();
705         }
706 
707         if (!CheckElement(expr, checker, {targetElementType, targetElementTypeSecondary}, isPreferredTuple)) {
708             expr->SetTsType(checker->GlobalTypeError());
709             return expr->TsTypeOrError();
710         }
711     }
712 
713     if (expr->preferredType_ == nullptr) {
714         checker->LogTypeError("Can't resolve array type", expr->Start());
715         expr->SetTsType(checker->GlobalTypeError());
716         return expr->TsTypeOrError();
717     }
718 
719     expr->SetTsType(expr->preferredType_);
720     auto *const arrayType = expr->TsType()->AsETSArrayType();
721     checker->CreateBuiltinArraySignature(arrayType, arrayType->Rank());
722     return expr->TsTypeOrError();
723 }
724 
Check(ir::ArrowFunctionExpression *expr) const725 checker::Type *ETSAnalyzer::Check(ir::ArrowFunctionExpression *expr) const
726 {
727     ETSChecker *checker = GetETSChecker();
728 
729     if (expr->TsTypeOrError() != nullptr) {
730         return expr->TsTypeOrError();
731     }
732     checker::ScopeContext scopeCtx(checker, expr->Function()->Scope());
733 
734     if (checker->HasStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD)) {
735         /*
736         example code:
737         ```
738             class A {
739                 prop:number
740             }
741             function A.method() {
742                 let a = () => {
743                     console.println(this.prop)
744                 }
745             }
746         ```
747         here the enclosing class of arrow function should be Class A
748         */
749         checker->Context().SetContainingClass(
750             checker->Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_THIS).variable->TsType()->AsETSObjectType());
751     }
752 
753     checker::SavedCheckerContext savedContext(checker, checker->Context().Status(),
754                                               checker->Context().ContainingClass());
755 
756     checker->AddStatus(checker::CheckerStatus::IN_LAMBDA);
757     checker->Context().SetContainingLambda(expr);
758 
759     checker->BuildFunctionSignature(expr->Function(), false);
760     if (expr->Function()->Signature() == nullptr) {
761         expr->SetTsType(checker->GlobalTypeError());
762         return expr->TsTypeOrError();
763     }
764     auto *signature = expr->Function()->Signature();
765 
766     checker->Context().SetContainingSignature(signature);
767     expr->Function()->Body()->Check(checker);
768 
769     ArenaVector<Signature *> signatures(checker->Allocator()->Adapter());
770     signatures.push_back(signature);
771     for (auto &sigInfo : checker->ComposeSignatureInfosForArrowFunction(expr)) {
772         auto sig = checker->ComposeSignature(expr->Function(), sigInfo, signature->ReturnType(), nullptr);
773         sig->AddSignatureFlag(signature->GetFlags());
774         signatures.push_back(sig);
775     }
776 
777     auto *funcType = checker->CreateETSFunctionType(expr->Function(), std::move(signatures), nullptr);
778     checker->Context().SetContainingSignature(nullptr);
779 
780     if (expr->Function()->IsAsyncFunc()) {
781         auto *retType = signature->ReturnType();
782         if (!retType->IsETSObjectType() ||
783             retType->AsETSObjectType()->GetOriginalBaseType() != checker->GlobalBuiltinPromiseType()) {
784             checker->LogTypeError("Return type of async lambda must be 'Promise'", expr->Function()->Start());
785             expr->SetTsType(checker->GlobalTypeError());
786             return expr->TsTypeOrError();
787         }
788     }
789 
790     expr->SetTsType(funcType);
791     return expr->TsType();
792 }
793 
IsInvalidArrayLengthAssignment(ir::AssignmentExpression *const expr, ETSChecker *checker)794 static bool IsInvalidArrayLengthAssignment(ir::AssignmentExpression *const expr, ETSChecker *checker)
795 {
796     if (expr->Left()->IsMemberExpression() &&
797         expr->Left()->AsMemberExpression()->Object()->TsType()->IsETSArrayType() &&
798         expr->Left()->AsMemberExpression()->Property()->IsIdentifier() &&
799         expr->Left()->AsMemberExpression()->Property()->AsIdentifier()->Name().Is("length")) {
800         checker->LogTypeError("Setting the length of an array is not permitted", expr->Left()->Start());
801         return true;
802     }
803     return false;
804 }
805 
GetSmartType(ir::AssignmentExpression *expr, checker::Type *leftType, checker::Type *rightType) const806 checker::Type *ETSAnalyzer::GetSmartType(ir::AssignmentExpression *expr, checker::Type *leftType,
807                                          checker::Type *rightType) const
808 {
809     ETSChecker *checker = GetETSChecker();
810     checker::Type *smartType = leftType;
811 
812     if (expr->Left()->IsIdentifier()) {
813         //  Now try to define the actual type of Identifier so that smart cast can be used in further checker processing
814         smartType = checker->ResolveSmartType(rightType, leftType);
815         auto const *const variable = expr->Target();
816 
817         //  Add/Remove/Modify smart cast for identifier
818         //  (excluding the variables defined at top-level scope or captured in lambda-functions!)
819         auto const *const variableScope = variable->GetScope();
820         auto const topLevelVariable =
821             variableScope != nullptr && (variableScope->IsGlobalScope() || (variableScope->Parent() != nullptr &&
822                                                                             variableScope->Parent()->IsGlobalScope()));
823         if (!topLevelVariable) {
824             if (checker->Relation()->IsIdenticalTo(leftType, smartType)) {
825                 checker->Context().RemoveSmartCast(variable);
826             } else {
827                 expr->Left()->SetTsType(smartType);
828                 checker->Context().SetSmartCast(variable, smartType);
829             }
830         }
831     }
832     return smartType;
833 }
834 
Check(ir::AssignmentExpression *const expr) const835 checker::Type *ETSAnalyzer::Check(ir::AssignmentExpression *const expr) const
836 {
837     if (expr->TsTypeOrError() != nullptr) {
838         return expr->TsTypeOrError();
839     }
840 
841     ETSChecker *checker = GetETSChecker();
842     auto *const leftType = expr->Left()->Check(checker);
843 
844     if (IsInvalidArrayLengthAssignment(expr, checker)) {
845         expr->SetTsType(checker->GlobalTypeError());
846         return expr->TsTypeOrError();
847     }
848 
849     if (expr->Left()->IsIdentifier()) {
850         expr->target_ = expr->Left()->AsIdentifier()->Variable();
851     } else if (expr->Left()->IsMemberExpression()) {
852         expr->target_ = expr->Left()->AsMemberExpression()->PropVar();
853     } else {
854         checker->LogTypeError("Invalid left-hand side of assignment expression", expr->Left()->Start());
855         expr->SetTsType(checker->GlobalTypeError());
856         return expr->TsTypeOrError();
857     }
858 
859     if (expr->target_ != nullptr && !expr->IsIgnoreConstAssign()) {
860         checker->ValidateUnaryOperatorOperand(expr->target_);
861     }
862 
863     auto [rightType, relationNode] = CheckAssignmentExprOperatorType(expr, leftType);
864     if (rightType == nullptr) {
865         expr->SetTsType(checker->GlobalTypeError());
866         return checker->GlobalTypeError();
867     }
868 
869     const checker::Type *targetType = checker->TryGettingFunctionTypeFromInvokeFunction(leftType);
870     const checker::Type *sourceType = checker->TryGettingFunctionTypeFromInvokeFunction(rightType);
871 
872     checker::AssignmentContext(checker->Relation(), relationNode, rightType, leftType, expr->Right()->Start(),
873                                {"Type '", sourceType, "' cannot be assigned to type '", targetType, "'"});
874 
875     checker::Type *smartType = GetSmartType(expr, leftType, rightType);
876 
877     expr->SetTsType(smartType);
878     return expr->TsTypeOrError();
879 }
880 
CheckAssignmentExprOperatorType(ir::AssignmentExpression *expr, Type *const leftType) const881 std::tuple<Type *, ir::Expression *> ETSAnalyzer::CheckAssignmentExprOperatorType(ir::AssignmentExpression *expr,
882                                                                                   Type *const leftType) const
883 {
884     ETSChecker *checker = GetETSChecker();
885     checker::Type *sourceType {};
886     ir::Expression *relationNode = expr->Right();
887     switch (expr->OperatorType()) {
888         case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL:
889         case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL:
890         case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL:
891         case lexer::TokenType::PUNCTUATOR_MOD_EQUAL:
892         case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL:
893         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL:
894         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL:
895         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL:
896         case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL:
897         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL:
898         case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL:
899         case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
900             std::tie(std::ignore, expr->operationType_) = checker->CheckBinaryOperator(
901                 expr->Left(), expr->Right(), expr, expr->OperatorType(), expr->Start(), true);
902 
903             auto unboxedLeft = checker->ETSBuiltinTypeAsPrimitiveType(leftType);
904             sourceType = unboxedLeft == nullptr ? leftType : unboxedLeft;
905 
906             relationNode = expr;
907             break;
908         }
909         case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
910             if (leftType->IsETSArrayType() && expr->Right()->IsArrayExpression()) {
911                 checker->ModifyPreferredType(expr->Right()->AsArrayExpression(), leftType);
912             }
913 
914             if (expr->Right()->IsObjectExpression()) {
915                 expr->Right()->AsObjectExpression()->SetPreferredType(leftType);
916             }
917 
918             sourceType = expr->Right()->Check(checker);
919             break;
920         }
921         default: {
922             UNREACHABLE();
923             break;
924         }
925     }
926 
927     return {sourceType, relationNode};
928 }
929 
Check(ir::AwaitExpression *expr) const930 checker::Type *ETSAnalyzer::Check(ir::AwaitExpression *expr) const
931 {
932     ETSChecker *checker = GetETSChecker();
933     if (expr->TsTypeOrError() != nullptr) {
934         return expr->TsTypeOrError();
935     }
936 
937     checker::Type *argType = checker->GetApparentType(expr->argument_->Check(checker));
938     // Check the argument type of await expression
939     if (!argType->IsETSObjectType() ||
940         (argType->AsETSObjectType()->GetOriginalBaseType() != checker->GlobalBuiltinPromiseType())) {
941         checker->LogTypeError("'await' expressions require Promise object as argument.", expr->Argument()->Start());
942         expr->SetTsType(checker->GlobalTypeError());
943         return expr->TsTypeOrError();
944     }
945 
946     Type *type = argType->AsETSObjectType()->TypeArguments().at(0);
947     expr->SetTsType(UnwrapPromiseType(type));
948     return expr->TsType();
949 }
950 
UnwrapPromiseType(checker::Type *type) const951 checker::Type *ETSAnalyzer::UnwrapPromiseType(checker::Type *type) const
952 {
953     ETSChecker *checker = GetETSChecker();
954     checker::Type *promiseType = checker->GlobalBuiltinPromiseType();
955     while (type->IsETSObjectType() && type->AsETSObjectType()->GetOriginalBaseType() == promiseType) {
956         type = type->AsETSObjectType()->TypeArguments().at(0);
957     }
958     if (!type->IsETSUnionType()) {
959         return type;
960     }
961     const auto &ctypes = type->AsETSUnionType()->ConstituentTypes();
962     auto it = std::find_if(ctypes.begin(), ctypes.end(), [promiseType](checker::Type *t) {
963         return t == promiseType || (t->IsETSObjectType() && t->AsETSObjectType()->GetBaseType() == promiseType);
964     });
965     if (it == ctypes.end()) {
966         return type;
967     }
968     ArenaVector<Type *> newCTypes(ctypes);
969     do {
970         size_t index = it - ctypes.begin();
971         newCTypes[index] = UnwrapPromiseType(ctypes[index]);
972         ++it;
973         it = std::find_if(it, ctypes.end(), [promiseType](checker::Type *t) {
974             return t == promiseType || t->AsETSObjectType()->GetBaseType() == promiseType;
975         });
976     } while (it != ctypes.end());
977     return checker->CreateETSUnionType(std::move(newCTypes));
978 }
979 
Check(ir::BinaryExpression *expr) const980 checker::Type *ETSAnalyzer::Check(ir::BinaryExpression *expr) const
981 {
982     if (expr->TsTypeOrError() != nullptr) {
983         return expr->TsTypeOrError();
984     }
985 
986     ETSChecker *checker = GetETSChecker();
987     checker::Type *newTsType {nullptr};
988     std::tie(newTsType, expr->operationType_) =
989         checker->CheckBinaryOperator(expr->Left(), expr->Right(), expr, expr->OperatorType(), expr->Start());
990     expr->SetTsType(newTsType);
991 
992     checker->Context().CheckBinarySmartCastCondition(expr);
993 
994     return expr->TsTypeOrError();
995 }
996 
Check(ir::BlockExpression *st) const997 checker::Type *ETSAnalyzer::Check(ir::BlockExpression *st) const
998 {
999     ETSChecker *checker = GetETSChecker();
1000     checker::ScopeContext scopeCtx(checker, st->Scope());
1001 
1002     if (st->TsTypeOrError() == nullptr) {
1003         // NOLINTNEXTLINE(modernize-loop-convert)
1004         for (std::size_t idx = 0; idx < st->Statements().size(); idx++) {
1005             st->Statements()[idx]->Check(checker);
1006         }
1007 
1008         auto lastStmt = st->Statements().back();
1009         ASSERT(lastStmt->IsExpressionStatement());
1010         st->SetTsType(lastStmt->AsExpressionStatement()->GetExpression()->TsType());
1011     }
1012 
1013     return st->TsTypeOrError();
1014 }
1015 
ResolveSignature(ETSChecker *checker, ir::CallExpression *expr, checker::Type *calleeType, bool isFunctionalInterface, bool isUnionTypeWithFunctionalInterface) const1016 checker::Signature *ETSAnalyzer::ResolveSignature(ETSChecker *checker, ir::CallExpression *expr,
1017                                                   checker::Type *calleeType, bool isFunctionalInterface,
1018                                                   bool isUnionTypeWithFunctionalInterface) const
1019 {
1020     bool extensionFunctionType = expr->Callee()->IsMemberExpression() && checker->ExtensionETSFunctionType(calleeType);
1021 
1022     if (calleeType->IsETSExtensionFuncHelperType()) {
1023         return ResolveCallForETSExtensionFuncHelperType(calleeType->AsETSExtensionFuncHelperType(), checker, expr);
1024     }
1025     if (extensionFunctionType) {
1026         return ResolveCallExtensionFunction(calleeType->AsETSFunctionType(), checker, expr);
1027     }
1028     auto &signatures = ChooseSignatures(checker, calleeType, expr->IsETSConstructorCall(), isFunctionalInterface,
1029                                         isUnionTypeWithFunctionalInterface);
1030     // Remove static signatures if the callee is a member expression and the object is initialized
1031     if (expr->Callee()->IsMemberExpression() &&
1032         !expr->Callee()->AsMemberExpression()->Object()->TsType()->IsETSEnumType() &&
1033         (expr->Callee()->AsMemberExpression()->Object()->IsSuperExpression() ||
1034          (expr->Callee()->AsMemberExpression()->Object()->IsIdentifier() &&
1035           expr->Callee()->AsMemberExpression()->Object()->AsIdentifier()->Variable()->HasFlag(
1036               varbinder::VariableFlags::INITIALIZED)))) {
1037         signatures.erase(
1038             std::remove_if(signatures.begin(), signatures.end(),
1039                            [](checker::Signature *signature) { return signature->Function()->IsStatic(); }),
1040             signatures.end());
1041     }
1042 
1043     checker::Signature *signature = checker->ResolveCallExpressionAndTrailingLambda(signatures, expr, expr->Start());
1044     if (signature == nullptr) {
1045         return nullptr;
1046     }
1047 
1048     if (signature->Function()->IsExtensionMethod()) {
1049         checker->LogTypeError({"No matching call signature"}, expr->Start());
1050         return nullptr;
1051     }
1052     return signature;
1053 }
1054 
GetReturnType(ir::CallExpression *expr, checker::Type *calleeType) const1055 checker::Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, checker::Type *calleeType) const
1056 {
1057     ETSChecker *checker = GetETSChecker();
1058 
1059     if (calleeType->IsTypeError()) {
1060         return checker->GlobalTypeError();
1061     }
1062 
1063     bool isConstructorCall = expr->IsETSConstructorCall();
1064     bool isUnionTypeWithFunctionalInterface =
1065         calleeType->IsETSUnionType() &&
1066         calleeType->AsETSUnionType()->HasObjectType(checker::ETSObjectFlags::FUNCTIONAL_INTERFACE);
1067     bool isFunctionalInterface = calleeType->IsETSObjectType() && calleeType->AsETSObjectType()->HasObjectFlag(
1068                                                                       checker::ETSObjectFlags::FUNCTIONAL_INTERFACE);
1069     bool etsExtensionFuncHelperType = calleeType->IsETSExtensionFuncHelperType();
1070 
1071     if (expr->Callee()->IsArrowFunctionExpression()) {
1072         calleeType = InitAnonymousLambdaCallee(checker, expr->Callee(), calleeType);
1073         isFunctionalInterface = true;
1074     }
1075 
1076     if (!isFunctionalInterface && !calleeType->IsETSFunctionType() && !isConstructorCall &&
1077         !etsExtensionFuncHelperType && !isUnionTypeWithFunctionalInterface) {
1078         checker->LogTypeError({"Type '", calleeType, "' has no call signatures."}, expr->Start());
1079         return checker->GlobalTypeError();
1080     }
1081 
1082     checker::Signature *signature =
1083         ResolveSignature(checker, expr, calleeType, isFunctionalInterface, isUnionTypeWithFunctionalInterface);
1084     if (signature == nullptr) {
1085         return checker->GlobalTypeError();
1086     }
1087 
1088     checker->CheckObjectLiteralArguments(signature, expr->Arguments());
1089 
1090     if (!isFunctionalInterface) {
1091         checker::ETSObjectType *calleeObj = ChooseCalleeObj(checker, expr, calleeType, isConstructorCall);
1092         checker->ValidateSignatureAccessibility(calleeObj, expr, signature, expr->Start());
1093     }
1094 
1095     ASSERT(signature->Function() != nullptr);
1096     if (signature->Function()->IsThrowing() || signature->Function()->IsRethrowing()) {
1097         checker->CheckThrowingStatements(expr);
1098     }
1099 
1100     if (signature->Function()->IsDynamic()) {
1101         ASSERT(signature->Function()->IsDynamic());
1102         auto lang = signature->Function()->Language();
1103         expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), signature->Params(), lang, false));
1104     } else {
1105         ASSERT(!signature->Function()->IsDynamic());
1106         expr->SetSignature(signature);
1107     }
1108 
1109     auto *returnType = signature->ReturnType();
1110 
1111     if (signature->HasSignatureFlag(SignatureFlags::THIS_RETURN_TYPE)) {
1112         returnType = ChooseCalleeObj(checker, expr, calleeType, isConstructorCall);
1113     }
1114 
1115     return returnType;
1116 }
1117 
CheckAbstractCall(ETSChecker *checker, ir::CallExpression *expr)1118 static void CheckAbstractCall(ETSChecker *checker, ir::CallExpression *expr)
1119 {
1120     if (expr->Callee()->IsMemberExpression()) {
1121         auto obj = expr->Callee()->AsMemberExpression()->Object();
1122         if (obj != nullptr && obj->IsSuperExpression()) {
1123             if ((expr->Signature() != nullptr) && (expr->Signature()->HasSignatureFlag(SignatureFlags::ABSTRACT))) {
1124                 checker->LogTypeError("Cannot call abstract method!", expr->Start());
1125                 expr->SetTsType(checker->GlobalTypeError());
1126             }
1127         }
1128     }
1129 }
1130 
CheckCallee(ETSChecker *checker, ir::CallExpression *expr)1131 static void CheckCallee(ETSChecker *checker, ir::CallExpression *expr)
1132 {
1133     checker->CheckNonNullish(expr->Callee());
1134     if (expr->Callee()->IsMemberExpression() && expr->Callee()->AsMemberExpression()->Object() != nullptr &&
1135         expr->Callee()->AsMemberExpression()->Object()->TsType()->IsETSObjectType() &&
1136         expr->Callee()->AsMemberExpression()->Object()->TsType()->AsETSObjectType()->HasObjectFlag(
1137             ETSObjectFlags::READONLY)) {
1138         checker->LogTypeError("Cannot call readonly type methods.", expr->Start());
1139         expr->SetTsType(checker->GlobalTypeError());
1140     }
1141 }
1142 
GetCallExpressionReturnType(ir::CallExpression *expr, checker::Type *calleeType) const1143 checker::Type *ETSAnalyzer::GetCallExpressionReturnType(ir::CallExpression *expr, checker::Type *calleeType) const
1144 {
1145     ETSChecker *checker = GetETSChecker();
1146     checker::Type *returnType = nullptr;
1147     if (calleeType->IsETSDynamicType() && !calleeType->AsETSDynamicType()->HasDecl()) {
1148         // Trailing lambda for js function call is not supported, check the correctness of `foo() {}`
1149         checker->EnsureValidCurlyBrace(expr);
1150         auto lang = calleeType->AsETSDynamicType()->Language();
1151         expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), expr->Arguments(), lang, false));
1152         returnType = expr->Signature()->ReturnType();
1153     } else {
1154         returnType = GetReturnType(expr, calleeType);
1155     }
1156 
1157     if (returnType->IsTypeError()) {
1158         return checker->GlobalTypeError();
1159     }
1160 
1161     if (expr->Signature()->RestVar() != nullptr) {
1162         auto *const elementType = expr->Signature()->RestVar()->TsType()->AsETSArrayType()->ElementType();
1163         auto *const arrayType = checker->CreateETSArrayType(elementType)->AsETSArrayType();
1164         checker->CreateBuiltinArraySignature(arrayType, arrayType->Rank());
1165     }
1166 
1167     if (expr->Signature()->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE)) {
1168         checker::SavedCheckerContext savedCtx(checker, checker->Context().Status(), expr->Signature()->Owner());
1169         expr->Signature()->OwnerVar()->Declaration()->Node()->Check(checker);
1170         if (expr->Signature()->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE) &&
1171             expr->Signature()->Function()->HasBody()) {
1172             checker::ScopeContext scopeCtx(checker, expr->Signature()->Function()->Body()->Scope());
1173             checker->CollectReturnStatements(expr->Signature()->Function());
1174         }
1175         returnType = expr->Signature()->ReturnType();
1176         // NOTE(vpukhov): #14902 substituted signature is not updated
1177     }
1178 
1179     return returnType;
1180 }
1181 
Check(ir::CallExpression *expr) const1182 checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const
1183 {
1184     ETSChecker *checker = GetETSChecker();
1185     if (expr->TsTypeOrError() != nullptr) {
1186         return expr->TsTypeOrError();
1187     }
1188     ASSERT(!expr->IsOptional());
1189 
1190     auto *oldCallee = expr->Callee();
1191     checker::Type *calleeType = checker->GetApparentType(expr->Callee()->Check(checker));
1192     if (calleeType->IsTypeError()) {
1193         expr->SetTsType(checker->GlobalTypeError());
1194         return expr->TsTypeOrError();
1195     }
1196 
1197     if (expr->Callee() != oldCallee) {
1198         // If it is a static invoke, the callee will be transformed from an identifier to a member expression
1199         // Type check the callee again for member expression
1200         calleeType = checker->GetApparentType(expr->Callee()->Check(checker));
1201     }
1202 
1203     CheckCallee(checker, expr);
1204 
1205     checker::Type *returnType = GetCallExpressionReturnType(expr, calleeType);
1206     if (returnType->IsTypeError()) {
1207         expr->SetTsType(returnType);
1208         return returnType;
1209     }
1210 
1211     expr->SetTsType(returnType);
1212     expr->SetUncheckedType(checker->GuaranteedTypeForUncheckedCallReturn(expr->Signature()));
1213     if (expr->UncheckedType() != nullptr) {
1214         checker->ComputeApparentType(returnType);
1215     }
1216 
1217     if (returnType->IsTypeError()) {
1218         expr->SetTsType(returnType);
1219         return expr->TsTypeOrError();
1220     }
1221 
1222     CheckVoidTypeExpression(checker, expr);
1223     CheckAbstractCall(checker, expr);
1224     return expr->TsTypeOrError();
1225 }
1226 
HandleTestedTypes(SmartCastTypes testedTypes, ETSChecker *checker)1227 static void HandleTestedTypes(SmartCastTypes testedTypes, ETSChecker *checker)
1228 {
1229     if (testedTypes.has_value()) {
1230         for (auto [variable, consequentType, _] : *testedTypes) {
1231             checker->ApplySmartCast(variable, consequentType);
1232         }
1233     }
1234 }
1235 
Check(ir::ConditionalExpression *expr) const1236 checker::Type *ETSAnalyzer::Check(ir::ConditionalExpression *expr) const
1237 {
1238     if (expr->TsTypeOrError() != nullptr) {
1239         return expr->TsTypeOrError();
1240     }
1241 
1242     ETSChecker *const checker = GetETSChecker();
1243 
1244     SmartCastArray smartCasts = checker->Context().EnterTestExpression();
1245     checker->CheckTruthinessOfType(expr->Test());
1246     SmartCastTypes testedTypes = checker->Context().ExitTestExpression();
1247     HandleTestedTypes(testedTypes, checker);
1248 
1249     auto *consequent = expr->Consequent();
1250     auto *consequentType = consequent->Check(checker);
1251 
1252     if (consequentType->IsETSEnumType()) {
1253         consequent->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::BOX_TO_ENUM);
1254         consequentType = consequentType->AsETSEnumType()->GetDecl()->BoxedClass()->TsType();
1255     }
1256     SmartCastArray consequentSmartCasts = checker->Context().CloneSmartCasts();
1257     checker->Context().RestoreSmartCasts(smartCasts);
1258 
1259     if (testedTypes.has_value()) {
1260         for (auto [variable, _, alternateType] : *testedTypes) {
1261             checker->ApplySmartCast(variable, alternateType);
1262         }
1263     }
1264 
1265     auto *alternate = expr->Alternate();
1266     auto *alternateType = alternate->Check(checker);
1267 
1268     if (alternateType->IsETSEnumType()) {
1269         alternate->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::BOX_TO_ENUM);
1270         alternateType = alternateType->AsETSEnumType()->GetDecl()->BoxedClass()->TsType();
1271     }
1272 
1273     // Here we need to combine types from consequent and alternate if blocks.
1274     checker->Context().CombineSmartCasts(consequentSmartCasts);
1275 
1276     if (checker->IsTypeIdenticalTo(consequentType, alternateType)) {
1277         expr->SetTsType(checker->GetNonConstantType(consequentType));
1278     } else {
1279         //  If possible and required update number literal type to the proper value (identical to left-side type)
1280         if (alternate->IsNumberLiteral() &&
1281             checker->AdjustNumberLiteralType(alternate->AsNumberLiteral(), alternateType, consequentType)) {
1282             expr->SetTsType(consequentType);
1283         } else if (consequent->IsNumberLiteral() &&
1284                    checker->AdjustNumberLiteralType(consequent->AsNumberLiteral(), consequentType, alternateType)) {
1285             expr->SetTsType(alternateType);
1286         } else {
1287             expr->SetTsType(checker->CreateETSUnionType({consequentType, alternateType}));
1288             if (expr->TsType()->IsETSReferenceType()) {
1289                 checker->MaybeBoxExpression(expr->Consequent());
1290                 checker->MaybeBoxExpression(expr->Alternate());
1291             }
1292         }
1293     }
1294 
1295     return expr->TsType();
1296 }
1297 
Check(ir::Identifier *expr) const1298 checker::Type *ETSAnalyzer::Check(ir::Identifier *expr) const
1299 {
1300     if (expr->TsTypeOrError() == nullptr) {
1301         ETSChecker *checker = GetETSChecker();
1302 
1303         auto *identType = checker->ResolveIdentifier(expr);
1304         if (expr->Variable() != nullptr && (expr->Parent() == nullptr || !expr->Parent()->IsAssignmentExpression() ||
1305                                             expr != expr->Parent()->AsAssignmentExpression()->Left())) {
1306             if (auto *const smartType = checker->Context().GetSmartCast(expr->Variable()); smartType != nullptr) {
1307                 identType = smartType;
1308             }
1309         }
1310         expr->SetTsType(identType);
1311 
1312         checker->Context().CheckIdentifierSmartCastCondition(expr);
1313     }
1314     return expr->TsTypeOrError();
1315 }
1316 
SearchReExportsType(ETSObjectType *baseType, ir::MemberExpression *expr, util::StringView &aliasName, ETSChecker *checker)1317 std::pair<checker::Type *, util::StringView> SearchReExportsType(ETSObjectType *baseType, ir::MemberExpression *expr,
1318                                                                  util::StringView &aliasName, ETSChecker *checker)
1319 {
1320     std::pair<ETSObjectType *, util::StringView> ret {};
1321 
1322     for (auto *const item : baseType->ReExports()) {
1323         auto name = item->GetReExportAliasValue(aliasName);
1324         if (name == aliasName && item->IsReExportHaveAliasValue(name)) {
1325             break;
1326         }
1327 
1328         if (item->GetProperty(name, PropertySearchFlags::SEARCH_ALL) != nullptr) {
1329             if (ret.first != nullptr) {
1330                 checker->LogTypeError({"Ambiguous reference to '", aliasName, "'"}, expr->Start());
1331                 expr->SetTsType(checker->GlobalTypeError());
1332                 return ret;
1333             }
1334             ret = {item, name};
1335         }
1336 
1337         if (auto reExportType = SearchReExportsType(item, expr, name, checker); reExportType.first != nullptr) {
1338             return reExportType;
1339         }
1340     }
1341 
1342     return ret;
1343 }
1344 
TypeErrorOnMissingProperty(ir::MemberExpression *expr, checker::Type *baseType, checker::ETSChecker *checker)1345 static void TypeErrorOnMissingProperty(ir::MemberExpression *expr, checker::Type *baseType,
1346                                        checker::ETSChecker *checker)
1347 {
1348     checker->LogTypeError(
1349         {"Property '", expr->Property()->AsIdentifier()->Name(), "' does not exist on type '", baseType, "'"},
1350         expr->Object()->Start());
1351     expr->SetTsType(checker->GlobalTypeError());
1352 }
1353 
Check(ir::MemberExpression *expr) const1354 checker::Type *ETSAnalyzer::Check(ir::MemberExpression *expr) const
1355 {
1356     if (expr->TsTypeOrError() != nullptr) {
1357         return expr->TsTypeOrError();
1358     }
1359     ASSERT(!expr->IsOptional());
1360 
1361     ETSChecker *checker = GetETSChecker();
1362     auto *baseType = checker->GetNonConstantType(checker->GetApparentType(expr->Object()->Check(checker)));
1363     //  Note: don't use possible smart cast to null-like types.
1364     //        Such situation should be correctly resolved in the subsequent lowering.
1365     if (baseType->DefinitelyETSNullish() && expr->Object()->IsIdentifier()) {
1366         baseType = expr->Object()->AsIdentifier()->Variable()->TsType();
1367     }
1368 
1369     if (baseType->IsETSObjectType() && !baseType->AsETSObjectType()->ReExports().empty() &&
1370         baseType->AsETSObjectType()->GetProperty(expr->Property()->AsIdentifier()->Name(),
1371                                                  PropertySearchFlags::SEARCH_ALL) == nullptr) {
1372         if (auto reExportType = SearchReExportsType(baseType->AsETSObjectType(), expr,
1373                                                     expr->Property()->AsIdentifier()->Name(), checker);
1374             reExportType.first != nullptr) {
1375             baseType = reExportType.first;
1376             expr->object_->AsIdentifier()->SetTsType(baseType);
1377             expr->property_->AsIdentifier()->SetName(reExportType.second);
1378         }
1379     }
1380 
1381     if (!checker->CheckNonNullish(expr->Object())) {
1382         expr->SetTsType(checker->GlobalTypeError());
1383         return expr->TsType();
1384     }
1385 
1386     if (expr->IsComputed()) {
1387         return expr->AdjustType(checker, expr->CheckComputed(checker, baseType));
1388     }
1389 
1390     if (baseType->IsETSArrayType()) {
1391         if (expr->Property()->AsIdentifier()->Name().Is("length")) {
1392             return expr->AdjustType(checker, checker->GlobalIntType());
1393         }
1394 
1395         return expr->SetAndAdjustType(checker, checker->GlobalETSObjectType());
1396     }
1397 
1398     if (baseType->IsETSObjectType()) {
1399         return expr->SetAndAdjustType(checker, baseType->AsETSObjectType());
1400     }
1401 
1402     if (baseType->IsETSEnumType()) {
1403         auto [memberType, memberVar] = expr->ResolveEnumMember(checker, baseType);
1404         expr->SetPropVar(memberVar);
1405         expr->Property()->SetTsType(memberType == nullptr ? checker->GlobalTypeError() : memberType);
1406         return expr->AdjustType(checker, expr->Property()->TsTypeOrError());
1407     }
1408 
1409     if (baseType->IsETSUnionType()) {
1410         return expr->AdjustType(checker, expr->CheckUnionMember(checker, baseType));
1411     }
1412     TypeErrorOnMissingProperty(expr, baseType, checker);
1413     return expr->TsTypeOrError();
1414 }
1415 
PreferredType(ir::ObjectExpression *expr) const1416 checker::Type *ETSAnalyzer::PreferredType(ir::ObjectExpression *expr) const
1417 {
1418     return expr->preferredType_;
1419 }
1420 
ValidatePreferredType(ir::ObjectExpression *expr, ETSChecker *checker)1421 static bool ValidatePreferredType(ir::ObjectExpression *expr, ETSChecker *checker)
1422 {
1423     auto preferredType = expr->PreferredType();
1424     if (preferredType == nullptr) {
1425         checker->LogTypeError({"need to specify target type for class composite"}, expr->Start());
1426         return false;
1427     }
1428 
1429     if (!preferredType->IsETSObjectType()) {
1430         checker->LogTypeError(
1431             {"Target type for class composite needs to be an object type, found '", preferredType, "'"}, expr->Start());
1432         return false;
1433     }
1434 
1435     return true;
1436 }
1437 
Check(ir::ObjectExpression *expr) const1438 checker::Type *ETSAnalyzer::Check(ir::ObjectExpression *expr) const
1439 {
1440     ETSChecker *checker = GetETSChecker();
1441     if (expr->TsTypeOrError() != nullptr) {
1442         return expr->TsTypeOrError();
1443     }
1444 
1445     if (!ValidatePreferredType(expr, checker)) {
1446         expr->SetTsType(checker->GlobalTypeError());
1447         return expr->TsTypeOrError();
1448     }
1449 
1450     if (expr->PreferredType()->IsETSDynamicType()) {
1451         for (ir::Expression *propExpr : expr->Properties()) {
1452             ASSERT(propExpr->IsProperty());
1453             ir::Property *prop = propExpr->AsProperty();
1454             ir::Expression *value = prop->Value();
1455             value->Check(checker);
1456             ASSERT(value->TsType());
1457         }
1458 
1459         expr->SetTsType(expr->PreferredType());
1460         return expr->PreferredType();
1461     }
1462 
1463     checker::ETSObjectType *objType = expr->PreferredType()->AsETSObjectType();
1464     if (objType->HasObjectFlag(checker::ETSObjectFlags::INTERFACE)) {
1465         // Object literal of interface tpye
1466         // Further interfaceObjectLiteralLowering phase will resolve interface type
1467         // and create corresponding anonymous class and class type
1468         // Here we just set the type to pass the checker
1469         CheckObjectExprProps(expr, checker::PropertySearchFlags::SEARCH_INSTANCE_METHOD |
1470                                        checker::PropertySearchFlags::SEARCH_IN_INTERFACES);
1471         expr->SetTsType(objType);
1472         return objType;
1473     }
1474 
1475     if (objType->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT)) {
1476         checker->LogTypeError({"target type for class composite ", objType->Name(), " is not instantiable"},
1477                               expr->Start());
1478         expr->SetTsType(checker->GlobalTypeError());
1479         return expr->TsTypeOrError();
1480     }
1481 
1482     if (expr->PreferredType()->ToAssemblerName().str() == "escompat.Record" ||
1483         expr->PreferredType()->ToAssemblerName().str() == "escompat.Map") {
1484         // 7.6.3 Object Literal of Record Type
1485         // Record is an alias to Map
1486         // Here we just set the type to pass the checker
1487         // See Record Lowering for details
1488         expr->SetTsType(objType);
1489         return objType;
1490     }
1491 
1492     bool haveEmptyConstructor = false;
1493     for (checker::Signature *sig : objType->ConstructSignatures()) {
1494         if (sig->Params().empty()) {
1495             haveEmptyConstructor = true;
1496             checker->ValidateSignatureAccessibility(objType, nullptr, sig, expr->Start());
1497             break;
1498         }
1499     }
1500     if (!haveEmptyConstructor) {
1501         checker->LogTypeError({"type ", objType->Name(), " has no parameterless constructor"}, expr->Start());
1502         expr->SetTsType(checker->GlobalTypeError());
1503         return expr->TsTypeOrError();
1504     }
1505 
1506     CheckObjectExprProps(expr, checker::PropertySearchFlags::SEARCH_INSTANCE_FIELD |
1507                                    checker::PropertySearchFlags::SEARCH_IN_BASE |
1508                                    checker::PropertySearchFlags::SEARCH_INSTANCE_METHOD);
1509 
1510     expr->SetTsType(objType);
1511     return objType;
1512 }
1513 
CheckObjectExprProps(const ir::ObjectExpression *expr, checker::PropertySearchFlags searchFlags) const1514 void ETSAnalyzer::CheckObjectExprProps(const ir::ObjectExpression *expr, checker::PropertySearchFlags searchFlags) const
1515 {
1516     ETSChecker *checker = GetETSChecker();
1517     checker::ETSObjectType *objType = expr->PreferredType()->AsETSObjectType();
1518 
1519     for (ir::Expression *propExpr : expr->Properties()) {
1520         ASSERT(propExpr->IsProperty());
1521         ir::Property *prop = propExpr->AsProperty();
1522         ir::Expression *key = prop->Key();
1523         ir::Expression *value = prop->Value();
1524 
1525         util::StringView pname;
1526         if (key->IsStringLiteral()) {
1527             pname = key->AsStringLiteral()->Str();
1528         } else if (key->IsIdentifier()) {
1529             pname = key->AsIdentifier()->Name();
1530         } else {
1531             checker->LogTypeError({"key in class composite should be either identifier or string literal"},
1532                                   expr->Start());
1533             return;
1534         }
1535         varbinder::LocalVariable *lv = objType->GetProperty(pname, searchFlags);
1536         if (lv == nullptr) {
1537             checker->LogTypeError({"type ", objType->Name(), " has no property named ", pname}, propExpr->Start());
1538             return;
1539         }
1540         checker->ValidatePropertyAccess(lv, objType, propExpr->Start());
1541 
1542         if (key->IsIdentifier()) {
1543             key->AsIdentifier()->SetVariable(lv);
1544         }
1545 
1546         auto *propType = checker->GetTypeOfVariable(lv);
1547         key->SetTsType(propType);
1548 
1549         if (value->IsObjectExpression()) {
1550             value->AsObjectExpression()->SetPreferredType(propType);
1551         }
1552         value->SetTsType(value->Check(checker));
1553 
1554         auto *const valueType = value->TsType();
1555         const checker::Type *sourceType = checker->TryGettingFunctionTypeFromInvokeFunction(valueType);
1556         const checker::Type *targetType = checker->TryGettingFunctionTypeFromInvokeFunction(propType);
1557 
1558         checker::AssignmentContext(
1559             checker->Relation(), value, valueType, propType, value->Start(),
1560             {"Type '", sourceType, "' is not compatible with type '", targetType, "' at property '", pname, "'"});
1561     }
1562 
1563     if (objType->HasObjectFlag(ETSObjectFlags::REQUIRED)) {
1564         checker->ValidateObjectLiteralForRequiredType(objType, expr);
1565     }
1566 }
1567 
Check(ir::OpaqueTypeNode *expr) const1568 checker::Type *ETSAnalyzer::Check(ir::OpaqueTypeNode *expr) const
1569 {
1570     return expr->TsType();
1571 }
1572 
Check(ir::SequenceExpression *expr) const1573 checker::Type *ETSAnalyzer::Check(ir::SequenceExpression *expr) const
1574 {
1575     ETSChecker *checker = GetETSChecker();
1576     if (expr->TsTypeOrError() != nullptr) {
1577         return expr->TsTypeOrError();
1578     }
1579 
1580     for (auto *it : expr->Sequence()) {
1581         it->Check(checker);
1582     }
1583     ASSERT(!expr->Sequence().empty());
1584     expr->SetTsType(expr->Sequence().back()->TsType());
1585     return nullptr;
1586 }
1587 
Check(ir::SuperExpression *expr) const1588 checker::Type *ETSAnalyzer::Check(ir::SuperExpression *expr) const
1589 {
1590     ETSChecker *checker = GetETSChecker();
1591     if (expr->TsTypeOrError() != nullptr) {
1592         return expr->TsTypeOrError();
1593     }
1594 
1595     expr->SetTsType(checker->CheckThisOrSuperAccess(expr, checker->Context().ContainingClass()->SuperType(), "super"));
1596     return expr->TsType();
1597 }
1598 
Check(ir::TemplateLiteral *expr) const1599 checker::Type *ETSAnalyzer::Check(ir::TemplateLiteral *expr) const
1600 {
1601     ETSChecker *checker = GetETSChecker();
1602     if (expr->TsTypeOrError() != nullptr) {
1603         return expr->TsTypeOrError();
1604     }
1605 
1606     if (expr->Quasis().size() != expr->Expressions().size() + 1U) {
1607         checker->LogTypeError("Invalid string template expression", expr->Start());
1608         expr->SetTsType(checker->GlobalTypeError());
1609         return expr->TsTypeOrError();
1610     }
1611 
1612     for (auto *it : expr->Expressions()) {
1613         it->Check(checker);
1614     }
1615 
1616     for (auto *it : expr->Quasis()) {
1617         it->Check(checker);
1618     }
1619 
1620     expr->SetTsType(checker->GlobalBuiltinETSStringType());
1621     return expr->TsType();
1622 }
1623 
Check(ir::ThisExpression *expr) const1624 checker::Type *ETSAnalyzer::Check(ir::ThisExpression *expr) const
1625 {
1626     ETSChecker *checker = GetETSChecker();
1627     if (expr->TsTypeOrError() != nullptr) {
1628         return expr->TsTypeOrError();
1629     }
1630 
1631     /*
1632     example code:
1633     ```
1634         class A {
1635             prop
1636         }
1637         function A.method() {
1638             let a = () => {
1639                 console.println(this.prop)
1640             }
1641         }
1642         is identical to
1643         function method(this: A) {
1644             let a = () => {
1645                 console.println(this.prop)
1646             }
1647         }
1648     ```
1649     here when "this" is used inside an extension function, we need to bind "this" to the first
1650     parameter(MANDATORY_PARAM_THIS), and capture the parameter's variable other than containing class's variable
1651     */
1652     auto *variable = checker->AsETSChecker()->Scope()->Find(varbinder::VarBinder::MANDATORY_PARAM_THIS).variable;
1653     if (checker->HasStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD)) {
1654         ASSERT(variable != nullptr);
1655         expr->SetTsType(variable->TsType());
1656     } else {
1657         expr->SetTsType(checker->CheckThisOrSuperAccess(expr, checker->Context().ContainingClass(), "this"));
1658     }
1659 
1660     return expr->TsType();
1661 }
1662 
1663 // Get string literal type as potential typeof result type with respect to spec p.7.17
GetTypeOfStringType(checker::Type *argType, ETSChecker *checker)1664 static checker::Type *GetTypeOfStringType(checker::Type *argType, ETSChecker *checker)
1665 {
1666     if (auto unboxed = checker->MaybePrimitiveBuiltinType(argType);
1667         unboxed->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
1668         switch (checker->TypeKind(unboxed)) {
1669             case TypeFlag::ETS_BOOLEAN: {
1670                 return checker->CreateETSStringLiteralType("boolean");
1671             }
1672             case TypeFlag::BYTE:
1673             case TypeFlag::CHAR:
1674             case TypeFlag::SHORT:
1675             case TypeFlag::INT:
1676             case TypeFlag::LONG:
1677             case TypeFlag::FLOAT:
1678             case TypeFlag::DOUBLE: {
1679                 return checker->CreateETSStringLiteralType("number");
1680             }
1681             default:
1682                 UNREACHABLE();
1683         }
1684     }
1685     if (argType->IsETSUndefinedType()) {
1686         return checker->CreateETSStringLiteralType(util::StringView("undefined"));
1687     }
1688     if (argType->IsETSArrayType() || argType->IsETSNullType()) {
1689         return checker->CreateETSStringLiteralType(util::StringView("object"));
1690     }
1691     if (argType->IsETSIntEnumType()) {
1692         return checker->CreateETSStringLiteralType(util::StringView("number"));
1693     }
1694     if (argType->IsETSStringType() || argType->IsETSStringEnumType()) {
1695         return checker->CreateETSStringLiteralType(util::StringView("string"));
1696     }
1697     if (argType->IsETSBigIntType()) {
1698         return checker->CreateETSStringLiteralType(util::StringView("bigint"));
1699     }
1700     if (argType->IsETSFunctionType()) {
1701         return checker->CreateETSStringLiteralType(util::StringView("function"));
1702     }
1703 
1704     return checker->GlobalBuiltinETSStringType();
1705 }
1706 
ComputeTypeOfType(ETSChecker *checker, checker::Type *argType)1707 static checker::Type *ComputeTypeOfType(ETSChecker *checker, checker::Type *argType)
1708 {
1709     checker::Type *ret = nullptr;
1710     ArenaVector<checker::Type *> types(checker->Allocator()->Adapter());
1711     if (argType->IsETSUnionType()) {
1712         for (auto *it : argType->AsETSUnionType()->ConstituentTypes()) {
1713             checker::Type *elType = ComputeTypeOfType(checker, it);
1714             types.push_back(elType);
1715         }
1716         ret = checker->CreateETSUnionType(std::move(types));
1717     } else {
1718         ret = GetTypeOfStringType(argType, checker);
1719     }
1720     return ret;
1721 }
1722 
Check([[maybe_unused]] ir::TypeofExpression *expr) const1723 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TypeofExpression *expr) const
1724 {
1725     ETSChecker *checker = GetETSChecker();
1726     if (expr->TsTypeOrError() != nullptr) {
1727         return expr->TsTypeOrError();
1728     }
1729 
1730     expr->Argument()->Check(checker);
1731     expr->SetTsType(ComputeTypeOfType(checker, expr->Argument()->TsType()));
1732     return expr->TsType();
1733 }
1734 
Check(ir::UnaryExpression *expr) const1735 checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const
1736 {
1737     ETSChecker *checker = GetETSChecker();
1738 
1739     if (expr->TsTypeOrError() != nullptr) {
1740         return expr->TsTypeOrError();
1741     }
1742 
1743     auto argType = expr->argument_->Check(checker);
1744     const auto isCondExpr = expr->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK;
1745     checker::Type *operandType = checker->ApplyUnaryOperatorPromotion(argType, true, true, isCondExpr);
1746     auto unboxedOperandType = isCondExpr ? checker->ETSBuiltinTypeAsConditionalType(argType)
1747                                          : checker->ETSBuiltinTypeAsPrimitiveType(argType);
1748 
1749     if (argType != nullptr && argType->IsETSBigIntType() && argType->HasTypeFlag(checker::TypeFlag::BIGINT_LITERAL)) {
1750         switch (expr->OperatorType()) {
1751             case lexer::TokenType::PUNCTUATOR_MINUS: {
1752                 checker::Type *type = checker->CreateETSBigIntLiteralType(argType->AsETSBigIntType()->GetValue());
1753 
1754                 // We do not need this const anymore as we are negating the bigint object in runtime
1755                 type->RemoveTypeFlag(checker::TypeFlag::CONSTANT);
1756                 expr->argument_->SetTsType(type);
1757                 expr->SetTsType(type);
1758                 return expr->TsType();
1759             }
1760             default:
1761                 // Handled below
1762                 // NOTE(kkonsw): handle other unary operators for bigint literals
1763                 break;
1764         }
1765     }
1766 
1767     if (argType != nullptr && argType->IsETSBigIntType()) {
1768         switch (expr->OperatorType()) {
1769             case lexer::TokenType::PUNCTUATOR_MINUS:
1770             case lexer::TokenType::PUNCTUATOR_PLUS:
1771             case lexer::TokenType::PUNCTUATOR_TILDE: {
1772                 expr->SetTsType(argType);
1773                 return expr->TsType();
1774             }
1775             default:
1776                 break;
1777         }
1778     }
1779 
1780     if (argType != nullptr && argType->IsETSEnumType()) {
1781         expr->Argument()->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF);
1782     }
1783     SetTsTypeForUnaryExpression(checker, expr, operandType);
1784 
1785     if ((argType != nullptr) && argType->IsETSObjectType() && (unboxedOperandType != nullptr) &&
1786         unboxedOperandType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) {
1787         expr->Argument()->AddBoxingUnboxingFlags(checker->GetUnboxingFlag(unboxedOperandType));
1788     }
1789 
1790     checker->Context().CheckUnarySmartCastCondition(expr);
1791 
1792     return expr->TsType();
1793 }
1794 
Check(ir::UpdateExpression *expr) const1795 checker::Type *ETSAnalyzer::Check(ir::UpdateExpression *expr) const
1796 {
1797     ETSChecker *checker = GetETSChecker();
1798     if (expr->TsTypeOrError() != nullptr) {
1799         return expr->TsTypeOrError();
1800     }
1801 
1802     checker::Type *operandType = expr->argument_->Check(checker);
1803     if (expr->Argument()->IsIdentifier()) {
1804         checker->ValidateUnaryOperatorOperand(expr->Argument()->AsIdentifier()->Variable());
1805     } else if (expr->Argument()->IsTSAsExpression()) {
1806         if (auto *const asExprVar = expr->Argument()->AsTSAsExpression()->Variable(); asExprVar != nullptr) {
1807             checker->ValidateUnaryOperatorOperand(asExprVar);
1808         }
1809     } else if (expr->Argument()->IsTSNonNullExpression()) {
1810         if (auto *const nonNullExprVar = expr->Argument()->AsTSNonNullExpression()->Variable();
1811             nonNullExprVar != nullptr) {
1812             checker->ValidateUnaryOperatorOperand(nonNullExprVar);
1813         }
1814     } else {
1815         ASSERT(expr->Argument()->IsMemberExpression());
1816         varbinder::LocalVariable *propVar = expr->argument_->AsMemberExpression()->PropVar();
1817         if (propVar != nullptr) {
1818             checker->ValidateUnaryOperatorOperand(propVar);
1819         }
1820     }
1821 
1822     if (operandType->IsETSBigIntType()) {
1823         expr->SetTsType(operandType);
1824         return expr->TsType();
1825     }
1826 
1827     auto unboxedType = checker->ETSBuiltinTypeAsPrimitiveType(operandType);
1828     if (unboxedType == nullptr || !unboxedType->HasTypeFlag(checker::TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) {
1829         checker->LogTypeError("Bad operand type, the type of the operand must be numeric type.",
1830                               expr->Argument()->Start());
1831         expr->SetTsType(checker->GlobalTypeError());
1832         return expr->TsTypeOrError();
1833     }
1834 
1835     if (operandType->IsETSObjectType()) {
1836         expr->Argument()->AddBoxingUnboxingFlags(checker->GetUnboxingFlag(unboxedType) |
1837                                                  checker->GetBoxingFlag(unboxedType));
1838     }
1839 
1840     expr->SetTsType(operandType);
1841     return expr->TsType();
1842 }
1843 
1844 // compile methods for LITERAL EXPRESSIONS in alphabetical order
Check([[maybe_unused]] ir::BigIntLiteral *expr) const1845 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::BigIntLiteral *expr) const
1846 {
1847     ETSChecker *checker = GetETSChecker();
1848     expr->SetTsType(checker->CreateETSBigIntLiteralType(expr->Str()));
1849     return expr->TsType();
1850 }
1851 
Check(ir::BooleanLiteral *expr) const1852 checker::Type *ETSAnalyzer::Check(ir::BooleanLiteral *expr) const
1853 {
1854     ETSChecker *checker = GetETSChecker();
1855     if (expr->TsTypeOrError() == nullptr) {
1856         expr->SetTsType(checker->CreateETSBooleanType(expr->Value()));
1857     }
1858     return expr->TsType();
1859 }
1860 
Check(ir::CharLiteral *expr) const1861 checker::Type *ETSAnalyzer::Check(ir::CharLiteral *expr) const
1862 {
1863     ETSChecker *checker = GetETSChecker();
1864     if (expr->TsTypeOrError() == nullptr) {
1865         expr->SetTsType(checker->Allocator()->New<checker::CharType>(expr->Char()));
1866     }
1867     return expr->TsType();
1868 }
1869 
Check(ir::NullLiteral *expr) const1870 checker::Type *ETSAnalyzer::Check(ir::NullLiteral *expr) const
1871 {
1872     ETSChecker *checker = GetETSChecker();
1873     if (expr->TsTypeOrError() == nullptr) {
1874         expr->SetTsType(checker->GlobalETSNullType());
1875     }
1876     return expr->TsType();
1877 }
1878 
Check(ir::NamespaceDeclaration *st) const1879 checker::Type *ETSAnalyzer::Check(ir::NamespaceDeclaration *st) const
1880 {
1881     ETSChecker *checker = GetETSChecker();
1882     st->Definition()->Check(checker);
1883     return nullptr;
1884 }
1885 
Check([[maybe_unused]] ir::NamespaceDefinition *st) const1886 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::NamespaceDefinition *st) const
1887 {
1888     return nullptr;
1889 }
1890 
Check(ir::NumberLiteral *expr) const1891 checker::Type *ETSAnalyzer::Check(ir::NumberLiteral *expr) const
1892 {
1893     ETSChecker *checker = GetETSChecker();
1894     if (expr->Number().IsInt()) {
1895         expr->SetTsType(checker->CreateIntType(expr->Number().GetInt()));
1896         return expr->TsType();
1897     }
1898 
1899     if (expr->Number().IsLong()) {
1900         expr->SetTsType(checker->CreateLongType(expr->Number().GetLong()));
1901         return expr->TsType();
1902     }
1903 
1904     if (expr->Number().IsFloat()) {
1905         expr->SetTsType(checker->CreateFloatType(expr->Number().GetFloat()));
1906         return expr->TsType();
1907     }
1908 
1909     expr->SetTsType(checker->CreateDoubleType(expr->Number().GetDouble()));
1910     return expr->TsType();
1911 }
1912 
Check(ir::StringLiteral *expr) const1913 checker::Type *ETSAnalyzer::Check(ir::StringLiteral *expr) const
1914 {
1915     ETSChecker *checker = GetETSChecker();
1916     if (expr->TsTypeOrError() == nullptr) {
1917         expr->SetTsType(checker->CreateETSStringLiteralType(expr->Str()));
1918     }
1919     return expr->TsType();
1920 }
1921 
Check(ir::ImportDeclaration *st) const1922 checker::Type *ETSAnalyzer::Check(ir::ImportDeclaration *st) const
1923 {
1924     ETSChecker *checker = GetETSChecker();
1925     checker::Type *type = nullptr;
1926     for (auto *spec : st->Specifiers()) {
1927         if (spec->IsImportNamespaceSpecifier()) {
1928             type = spec->AsImportNamespaceSpecifier()->Check(checker);
1929         }
1930     }
1931 
1932     return type;
1933 }
1934 
Check(ir::ImportNamespaceSpecifier *st) const1935 checker::Type *ETSAnalyzer::Check(ir::ImportNamespaceSpecifier *st) const
1936 {
1937     ETSChecker *checker = GetETSChecker();
1938     if (st->Local()->Name().Empty()) {
1939         return nullptr;
1940     }
1941 
1942     if (st->Local()->AsIdentifier()->TsTypeOrError() != nullptr) {
1943         return st->Local()->TsTypeOrError();
1944     }
1945 
1946     auto *importDecl = st->Parent()->AsETSImportDeclaration();
1947 
1948     if (importDecl->IsPureDynamic()) {
1949         auto *type = checker->GlobalBuiltinDynamicType(importDecl->Language());
1950         checker->SetrModuleObjectTsType(st->Local(), type);
1951         return type;
1952     }
1953 
1954     return checker->GetImportSpecifierObjectType(importDecl, st->Local()->AsIdentifier());
1955 }
1956 
1957 // compile methods for STATEMENTS in alphabetical order
Check(ir::AssertStatement *st) const1958 checker::Type *ETSAnalyzer::Check(ir::AssertStatement *st) const
1959 {
1960     ETSChecker *checker = GetETSChecker();
1961     if (!(st->Test()->Check(checker)->HasTypeFlag(TypeFlag::ETS_BOOLEAN | TypeFlag::BOOLEAN_LIKE) ||
1962           st->Test()->Check(checker)->ToString() == "Boolean")) {
1963         checker->LogTypeError("Bad operand type, the type of the operand must be boolean type.", st->Test()->Start());
1964     }
1965 
1966     if (st->Second() != nullptr) {
1967         auto *msgType = st->second_->Check(checker);
1968 
1969         if (!msgType->IsETSStringType()) {
1970             checker->LogTypeError("Assert message must be string", st->Second()->Start());
1971         }
1972     }
1973 
1974     return nullptr;
1975 }
1976 
Check(ir::BlockStatement *st) const1977 checker::Type *ETSAnalyzer::Check(ir::BlockStatement *st) const
1978 {
1979     ETSChecker *checker = GetETSChecker();
1980     checker::ScopeContext scopeCtx(checker, st->Scope());
1981 
1982     // Iterator type checking of statements is modified to index type, to allow modifying the statement list during
1983     // checking without invalidating the iterator
1984     //---- Don't modify this to iterator, as it may break things during checking
1985     for (std::size_t idx = 0; idx < st->Statements().size(); ++idx) {
1986         auto *stmt = st->Statements()[idx];
1987         stmt->Check(checker);
1988 
1989         //  NOTE! Processing of trailing blocks was moved here so that smart casts could be applied correctly
1990         if (auto const tb = st->trailingBlocks_.find(stmt); tb != st->trailingBlocks_.end()) {
1991             auto *const trailingBlock = tb->second;
1992             trailingBlock->Check(checker);
1993             st->Statements().emplace(std::next(st->Statements().begin() + idx), trailingBlock);
1994             ++idx;
1995         }
1996     }
1997     if (UNLIKELY(checker->GetDebugInfoPlugin() != nullptr)) {
1998         // Compilation in eval-mode might require to create additional statements.
1999         // In this case, they must be created after iteration through statements ends.
2000         checker->GetDebugInfoPlugin()->AddPrologueEpilogue(st);
2001     }
2002 
2003     //  Remove possible smart casts for variables declared in inner scope:
2004     if (auto const *const scope = st->Scope();
2005         scope->IsFunctionScope() && st->Parent()->Parent()->Parent()->IsMethodDefinition()) {
2006         // When exiting method definition, just clear all smart casts
2007         checker->Context().ClearSmartCasts();
2008     } else if (!scope->IsGlobalScope()) {
2009         // otherwise only check inner declarations
2010         for (auto const *const decl : scope->Decls()) {
2011             if (decl->IsLetOrConstDecl() && decl->Node()->IsIdentifier()) {
2012                 checker->Context().RemoveSmartCast(decl->Node()->AsIdentifier()->Variable());
2013             }
2014         }
2015     }
2016 
2017     return nullptr;
2018 }
2019 
Check(ir::BreakStatement *st) const2020 checker::Type *ETSAnalyzer::Check(ir::BreakStatement *st) const
2021 {
2022     ETSChecker *checker = GetETSChecker();
2023     auto node = checker->FindJumpTarget(st);
2024     if (!node.has_value()) {
2025         return checker->GlobalTypeError();
2026     }
2027     st->SetTarget(*node);
2028 
2029     checker->Context().OnBreakStatement(st);
2030     return nullptr;
2031 }
2032 
Check(ir::ClassDeclaration *st) const2033 checker::Type *ETSAnalyzer::Check(ir::ClassDeclaration *st) const
2034 {
2035     ETSChecker *checker = GetETSChecker();
2036     st->Definition()->Check(checker);
2037     return nullptr;
2038 }
2039 
Check(ir::ContinueStatement *st) const2040 checker::Type *ETSAnalyzer::Check(ir::ContinueStatement *st) const
2041 {
2042     ETSChecker *checker = GetETSChecker();
2043     auto node = checker->FindJumpTarget(st);
2044     if (!node.has_value()) {
2045         return checker->GlobalTypeError();
2046     }
2047     st->SetTarget(*node);
2048 
2049     checker->AddStatus(CheckerStatus::MEET_CONTINUE);
2050     return nullptr;
2051 }
2052 
Check(ir::DoWhileStatement *st) const2053 checker::Type *ETSAnalyzer::Check(ir::DoWhileStatement *st) const
2054 {
2055     ETSChecker *checker = GetETSChecker();
2056     checker::ScopeContext scopeCtx(checker, st->Scope());
2057 
2058     //  NOTE: Smart casts are not processed correctly within the loops now, thus clear them at this point.
2059     auto [smartCasts, clearFlag] = checker->Context().EnterLoop(*st);
2060 
2061     checker->CheckTruthinessOfType(st->Test());
2062     st->Body()->Check(checker);
2063 
2064     checker->Context().ExitLoop(smartCasts, clearFlag, st);
2065     return nullptr;
2066 }
2067 
Check([[maybe_unused]] ir::EmptyStatement *st) const2068 checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::EmptyStatement *st) const
2069 {
2070     return nullptr;
2071 }
2072 
Check(ir::ExpressionStatement *st) const2073 checker::Type *ETSAnalyzer::Check(ir::ExpressionStatement *st) const
2074 {
2075     ETSChecker *checker = GetETSChecker();
2076     return st->GetExpression()->Check(checker);
2077 }
2078 
ValidateAndProcessIteratorType(ETSChecker *checker, Type *elemType, ir::ForOfStatement *const st)2079 static bool ValidateAndProcessIteratorType(ETSChecker *checker, Type *elemType, ir::ForOfStatement *const st)
2080 {
2081     checker::Type *iterType = GetIteratorType(checker, elemType, st->Left());
2082     if (iterType->IsTypeError()) {
2083         return false;
2084     }
2085     auto *const relation = checker->Relation();
2086     relation->SetFlags(checker::TypeRelationFlag::ASSIGNMENT_CONTEXT);
2087     relation->SetNode(st->Left()->IsVariableDeclaration()
2088                           ? st->Left()->AsVariableDeclaration()->Declarators().front()->Id()
2089                           : st->Left()->AsIdentifier());
2090 
2091     if (!relation->IsAssignableTo(elemType, iterType)) {
2092         std::stringstream ss {};
2093         ss << "Source element type '" << elemType->ToString() << "' is not assignable to the loop iterator type '"
2094            << iterType->ToString() << "'.";
2095         checker->LogTypeError(ss.str(), st->Start());
2096         return false;
2097     }
2098 
2099     relation->SetNode(nullptr);
2100     relation->SetFlags(checker::TypeRelationFlag::NONE);
2101 
2102     if (iterType->Variable() == nullptr && !iterType->IsETSObjectType() && elemType->IsETSObjectType() &&
2103         st->Left()->IsVariableDeclaration()) {
2104         for (auto &declarator : st->Left()->AsVariableDeclaration()->Declarators()) {
2105             checker->AddBoxingUnboxingFlagsToNode(declarator->Id(), iterType);
2106         }
2107     }
2108     return true;
2109 }
2110 // NOLINTBEGIN(modernize-avoid-c-arrays)
2111 static constexpr char const MISSING_SOURCE_EXPR_TYPE[] =
2112     "Cannot determine source expression type in the 'for-of' statement.";
2113 static constexpr char const INVALID_SOURCE_EXPR_TYPE[] =
2114     "'For-of' statement source expression is not of iterable type.";
2115 // NOLINTEND(modernize-avoid-c-arrays)
2116 
Check(ir::ForOfStatement *const st) const2117 checker::Type *ETSAnalyzer::Check(ir::ForOfStatement *const st) const
2118 {
2119     ETSChecker *checker = GetETSChecker();
2120     checker::ScopeContext scopeCtx(checker, st->Scope());
2121 
2122     //  NOTE: Smart casts are not processed correctly within the loops now, thus clear them at this point.
2123     auto [smartCasts, clearFlag] = checker->Context().EnterLoop(*st);
2124 
2125     checker::Type *const exprType = st->Right()->Check(checker);
2126     if (exprType == nullptr) {
2127         checker->LogTypeError(MISSING_SOURCE_EXPR_TYPE, st->Right()->Start());
2128         return checker->GlobalTypeError();
2129     }
2130 
2131     checker::Type *elemType = nullptr;
2132 
2133     if (exprType->IsETSStringType()) {
2134         elemType = checker->GetGlobalTypesHolder()->GlobalCharType();
2135     } else if (exprType->IsETSArrayType()) {
2136         elemType = exprType->AsETSArrayType()->ElementType()->Instantiate(checker->Allocator(), checker->Relation(),
2137                                                                           checker->GetGlobalTypesHolder());
2138         if (elemType != nullptr) {
2139             elemType->RemoveTypeFlag(checker::TypeFlag::CONSTANT);
2140         }
2141     } else if (exprType->IsETSObjectType() || exprType->IsETSUnionType() || exprType->IsETSTypeParameter()) {
2142         elemType = st->CheckIteratorMethod(checker);
2143     }
2144 
2145     if (elemType == nullptr) {
2146         checker->LogTypeError(INVALID_SOURCE_EXPR_TYPE, st->Right()->Start());
2147         return checker->GlobalTypeError();
2148     }
2149 
2150     st->Left()->Check(checker);
2151 
2152     if (!ValidateAndProcessIteratorType(checker, elemType, st)) {
2153         return checker->GlobalTypeError();
2154     };
2155 
2156     st->Body()->Check(checker);
2157 
2158     checker->Context().ExitLoop(smartCasts, clearFlag, st);
2159     return nullptr;
2160 }
2161 
Check(ir::ForUpdateStatement *st) const2162 checker::Type *ETSAnalyzer::Check(ir::ForUpdateStatement *st) const
2163 {
2164     ETSChecker *checker = GetETSChecker();
2165     checker::ScopeContext scopeCtx(checker, st->Scope());
2166 
2167     //  NOTE: Smart casts are not processed correctly within the loops now, thus clear them at this point.
2168     auto [smartCasts, clearFlag] = checker->Context().EnterLoop(*st);
2169 
2170     if (st->Init() != nullptr) {
2171         st->Init()->Check(checker);
2172     }
2173 
2174     if (st->Test() != nullptr) {
2175         checker->CheckTruthinessOfType(st->Test());
2176     }
2177 
2178     if (st->Update() != nullptr) {
2179         st->Update()->Check(checker);
2180     }
2181 
2182     st->Body()->Check(checker);
2183 
2184     checker->Context().ExitLoop(smartCasts, clearFlag, st);
2185     return nullptr;
2186 }
2187 
Check(ir::IfStatement *st) const2188 checker::Type *ETSAnalyzer::Check(ir::IfStatement *st) const
2189 {
2190     ETSChecker *const checker = GetETSChecker();
2191 
2192     SmartCastArray smartCasts = checker->Context().EnterTestExpression();
2193     checker->CheckTruthinessOfType(st->Test());
2194     SmartCastTypes testedTypes = checker->Context().ExitTestExpression();
2195     if (testedTypes.has_value()) {
2196         for (auto [variable, consequentType, _] : *testedTypes) {
2197             checker->ApplySmartCast(variable, consequentType);
2198         }
2199     }
2200 
2201     checker->Context().EnterPath();
2202     st->Consequent()->Check(checker);
2203     bool const consequentTerminated = checker->Context().ExitPath();
2204     SmartCastArray consequentSmartCasts = checker->Context().CloneSmartCasts();
2205 
2206     // Restore smart casts to initial state.
2207     checker->Context().RestoreSmartCasts(smartCasts);
2208     //  Apply the alternate smart casts
2209     if (testedTypes.has_value()) {
2210         for (auto [variable, _, alternateType] : *testedTypes) {
2211             checker->ApplySmartCast(variable, alternateType);
2212         }
2213     }
2214 
2215     if (st->Alternate() != nullptr) {
2216         checker->Context().EnterPath();
2217         st->Alternate()->Check(checker);
2218         bool const alternateTerminated = checker->Context().ExitPath();
2219         if (alternateTerminated) {
2220             if (!consequentTerminated) {
2221                 // Here we need to restore types from consequent if block.
2222                 checker->Context().RestoreSmartCasts(consequentSmartCasts);
2223             } else {
2224                 // Here we need to restore initial smart types.
2225                 checker->Context().RestoreSmartCasts(smartCasts);
2226             }
2227         } else if (!consequentTerminated) {
2228             // Here we need to combine types from consequent and alternate if blocks.
2229             checker->Context().CombineSmartCasts(consequentSmartCasts);
2230         }
2231     } else {
2232         if (!consequentTerminated) {
2233             // Here we need to combine types from consequent if block and initial.
2234             checker->Context().CombineSmartCasts(consequentSmartCasts);
2235         }
2236     }
2237 
2238     return nullptr;
2239 }
2240 
Check(ir::LabelledStatement *st) const2241 checker::Type *ETSAnalyzer::Check(ir::LabelledStatement *st) const
2242 {
2243     ETSChecker *checker = GetETSChecker();
2244     st->body_->Check(checker);
2245     return nullptr;
2246 }
2247 
CheckInferredFunctionReturnType(ir::ReturnStatement *st, ir::ScriptFunction *containingFunc, checker::Type *&funcReturnType, ir::TypeNode *returnTypeAnnotation, ETSChecker *checker) const2248 bool ETSAnalyzer::CheckInferredFunctionReturnType(ir::ReturnStatement *st, ir::ScriptFunction *containingFunc,
2249                                                   checker::Type *&funcReturnType, ir::TypeNode *returnTypeAnnotation,
2250                                                   ETSChecker *checker) const
2251 {
2252     funcReturnType = returnTypeAnnotation->GetType(checker);
2253     if (returnTypeAnnotation->IsTSThisType() && (st->Argument() == nullptr || !st->Argument()->IsThisExpression())) {
2254         checker->LogTypeError("The only allowed return value is 'this' if the method's return type is the 'this' type",
2255                               st->Start());
2256         return false;
2257     }
2258 
2259     // Case when function's return type is defined explicitly:
2260 
2261     if (st->argument_ == nullptr) {
2262         if (!funcReturnType->IsETSVoidType() && funcReturnType != checker->GlobalVoidType() &&
2263             !funcReturnType->IsETSAsyncFuncReturnType()) {
2264             checker->LogTypeError("Missing return value.", st->Start());
2265             return false;
2266         }
2267         funcReturnType = checker->GlobalVoidType();
2268     } else {
2269         const auto name = containingFunc->Scope()->InternalName().Mutf8();
2270         if (!CheckArgumentVoidType(funcReturnType, checker, name, st)) {
2271             return false;
2272         }
2273 
2274         if (st->argument_->IsObjectExpression()) {
2275             st->argument_->AsObjectExpression()->SetPreferredType(funcReturnType);
2276         }
2277         if (st->argument_->IsMemberExpression()) {
2278             checker->SetArrayPreferredTypeForNestedMemberExpressions(st->argument_->AsMemberExpression(),
2279                                                                      funcReturnType);
2280         }
2281 
2282         if (st->argument_->IsArrayExpression()) {
2283             st->argument_->AsArrayExpression()->SetPreferredType(funcReturnType);
2284         }
2285 
2286         checker::Type *argumentType = st->argument_->Check(checker);
2287         return CheckReturnType(checker, funcReturnType, argumentType, st->argument_, containingFunc->IsAsyncFunc());
2288     }
2289     return true;
2290 }
2291 
GetFunctionReturnType(ir::ReturnStatement *st, ir::ScriptFunction *containingFunc) const2292 checker::Type *ETSAnalyzer::GetFunctionReturnType(ir::ReturnStatement *st, ir::ScriptFunction *containingFunc) const
2293 {
2294     ASSERT(containingFunc->ReturnTypeAnnotation() != nullptr || containingFunc->Signature()->ReturnType() != nullptr);
2295 
2296     ETSChecker *checker = GetETSChecker();
2297     checker::Type *funcReturnType = nullptr;
2298 
2299     if (auto *const returnTypeAnnotation = containingFunc->ReturnTypeAnnotation(); returnTypeAnnotation != nullptr) {
2300         if (!CheckInferredFunctionReturnType(st, containingFunc, funcReturnType, returnTypeAnnotation, checker)) {
2301             return checker->GlobalTypeError();
2302         }
2303     } else {
2304         //  Case when function's return type should be inferred from return statement(s):
2305         if (containingFunc->Signature()->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE)) {
2306             InferReturnType(checker, containingFunc, funcReturnType,
2307                             st->argument_);  // This removes the NEED_RETURN_TYPE flag, so only the first return
2308                                              // statement going to land here...
2309         } else {
2310             //  All subsequent return statements:
2311             ProcessReturnStatements(checker, containingFunc, funcReturnType, st,
2312                                     st->argument_);  // and the remaining return statements will get processed here.
2313         }
2314     }
2315 
2316     if ((st->argument_ != nullptr) && st->argument_->IsArrayExpression() && funcReturnType->IsArrayType()) {
2317         checker->ModifyPreferredType(st->argument_->AsArrayExpression(), funcReturnType);
2318         st->argument_->Check(checker);
2319     }
2320 
2321     return funcReturnType;
2322 }
2323 
Check(ir::ReturnStatement *st) const2324 checker::Type *ETSAnalyzer::Check(ir::ReturnStatement *st) const
2325 {
2326     ETSChecker *checker = GetETSChecker();
2327 
2328     ir::AstNode *ancestor = util::Helpers::FindAncestorGivenByType(st, ir::AstNodeType::SCRIPT_FUNCTION);
2329     ASSERT(ancestor && ancestor->IsScriptFunction());
2330     auto *containingFunc = ancestor->AsScriptFunction();
2331 
2332     checker->AddStatus(CheckerStatus::MEET_RETURN);
2333 
2334     if (containingFunc->IsConstructor()) {
2335         if (st->argument_ != nullptr) {
2336             checker->LogTypeError("Return statement with expression isn't allowed in constructor.", st->Start());
2337             return checker->GlobalTypeError();
2338         }
2339         return nullptr;
2340     }
2341 
2342     st->returnType_ = GetFunctionReturnType(st, containingFunc);
2343 
2344     if (containingFunc->ReturnTypeAnnotation() == nullptr) {
2345         containingFunc->AddReturnStatement(st);
2346     }
2347 
2348     return nullptr;
2349 }
2350 
Check(ir::SwitchStatement *st) const2351 checker::Type *ETSAnalyzer::Check(ir::SwitchStatement *st) const
2352 {
2353     ETSChecker *checker = GetETSChecker();
2354     checker::ScopeContext scopeCtx(checker, st->Scope());
2355     checker::SavedTypeRelationFlagsContext savedTypeRelationFlagCtx(checker->Relation(),
2356                                                                     checker::TypeRelationFlag::NONE);
2357 
2358     auto *comparedExprType = checker->CheckSwitchDiscriminant(st->Discriminant());
2359     auto unboxedDiscType = (st->Discriminant()->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::UNBOXING_FLAG) != 0U
2360                                ? checker->ETSBuiltinTypeAsPrimitiveType(comparedExprType)
2361                                : comparedExprType;
2362 
2363     SmartCastArray smartCasts = checker->Context().CloneSmartCasts();
2364     bool hasDefaultCase = false;
2365 
2366     for (auto &it : st->Cases()) {
2367         checker->Context().EnterPath();
2368         it->CheckAndTestCase(checker, comparedExprType, unboxedDiscType, st->Discriminant(), hasDefaultCase);
2369         bool const caseTerminated = checker->Context().ExitPath();
2370 
2371         if (it != st->Cases().back()) {
2372             if (!caseTerminated) {
2373                 checker->Context().CombineSmartCasts(smartCasts);
2374             } else {
2375                 checker->Context().RestoreSmartCasts(smartCasts);
2376             }
2377         } else {
2378             if (!caseTerminated) {
2379                 //  if the recent switch case isn't terminated in any way, copy actual smart casts to the array of
2380                 //  smart casts for the other case blocks so that it can be processed in unified way
2381                 checker->Context().AddBreakSmartCasts(st, checker->Context().CloneSmartCasts());
2382             }
2383             checker->Context().ClearSmartCasts();
2384         }
2385     }
2386 
2387     // If default case is absent initial smart casts should be also applied here
2388     if (!hasDefaultCase) {
2389         checker->Context().AddBreakSmartCasts(st, std::move(smartCasts));
2390     }
2391 
2392     // Combine smart casts from all [non-terminated] case blocks with 'break'
2393     checker->Context().CombineBreakSmartCasts(st);
2394 
2395     checker->CheckForSameSwitchCases(st->Cases());
2396     return nullptr;
2397 }
2398 
Check(ir::ThrowStatement *st) const2399 checker::Type *ETSAnalyzer::Check(ir::ThrowStatement *st) const
2400 {
2401     ETSChecker *checker = GetETSChecker();
2402     auto *argType = st->argument_->Check(checker);
2403     checker->CheckExceptionOrErrorType(argType, st->Start());
2404 
2405     if (checker->Relation()->IsAssignableTo(argType, checker->GlobalBuiltinExceptionType())) {
2406         checker->CheckThrowingStatements(st);
2407     }
2408 
2409     checker->AddStatus(CheckerStatus::MEET_THROW);
2410     return nullptr;
2411 }
2412 
Check(ir::TryStatement *st) const2413 checker::Type *ETSAnalyzer::Check(ir::TryStatement *st) const
2414 {
2415     ETSChecker *checker = GetETSChecker();
2416     std::vector<checker::ETSObjectType *> exceptions {};
2417 
2418     std::vector<SmartCastArray> casts {};
2419     auto smartCasts = checker->Context().CheckTryBlock(*st->Block());
2420     st->Block()->Check(checker);
2421 
2422     bool defaultCatchFound = false;
2423     for (auto *catchClause : st->CatchClauses()) {
2424         if (defaultCatchFound) {
2425             checker->LogTypeError("Default catch clause should be the last in the try statement", catchClause->Start());
2426             return checker->GlobalTypeError();
2427         }
2428 
2429         checker->Context().RestoreSmartCasts(smartCasts);
2430 
2431         if (auto const exceptionType = catchClause->Check(checker);
2432             exceptionType != nullptr && catchClause->Param() != nullptr) {
2433             auto *clauseType = exceptionType->AsETSObjectType();
2434             checker->CheckExceptionClauseType(exceptions, catchClause, clauseType);
2435             exceptions.emplace_back(clauseType);
2436         }
2437 
2438         defaultCatchFound = catchClause->IsDefaultCatchClause();
2439 
2440         casts.emplace_back(checker->Context().CloneSmartCasts());
2441     }
2442 
2443     checker->Context().RestoreSmartCasts(smartCasts);
2444     if (!casts.empty()) {
2445         for (auto const &cast : casts) {
2446             checker->Context().CombineSmartCasts(cast);
2447         }
2448     }
2449 
2450     if (st->HasFinalizer()) {
2451         st->FinallyBlock()->Check(checker);
2452     }
2453 
2454     return nullptr;
2455 }
2456 
Check(ir::VariableDeclarator *st) const2457 checker::Type *ETSAnalyzer::Check(ir::VariableDeclarator *st) const
2458 {
2459     if (st->TsTypeOrError() != nullptr) {
2460         return st->TsTypeOrError();
2461     }
2462 
2463     ETSChecker *checker = GetETSChecker();
2464     ASSERT(st->Id()->IsIdentifier());
2465     auto *const ident = st->Id()->AsIdentifier();
2466     ir::ModifierFlags flags = ir::ModifierFlags::NONE;
2467 
2468     if (ident->Parent()->Parent()->AsVariableDeclaration()->Kind() ==
2469         ir::VariableDeclaration::VariableDeclarationKind::CONST) {
2470         flags |= ir::ModifierFlags::CONST;
2471     }
2472 
2473     if (ident->IsOptionalDeclaration()) {
2474         flags |= ir::ModifierFlags::OPTIONAL;
2475     }
2476 
2477     auto *const variableType = checker->CheckVariableDeclaration(ident, ident->TypeAnnotation(), st->Init(), flags);
2478     auto *smartType = variableType;
2479 
2480     //  Now try to define the actual type of Identifier so that smart cast can be used in further checker processing
2481     //  NOTE: T_S and K_o_t_l_i_n don't act in such way, but we can try - why not? :)
2482     if (auto *const initType = st->Init() != nullptr ? st->Init()->TsTypeOrError() : nullptr; initType != nullptr) {
2483         smartType = checker->ResolveSmartType(initType, variableType);
2484         //  Set smart type for identifier if it differs from annotated type
2485         //  Top-level and captured variables are not processed here!
2486         if (!checker->Relation()->IsIdenticalTo(variableType, smartType)) {
2487             ident->SetTsType(smartType);
2488             checker->Context().SetSmartCast(ident->Variable(), smartType);
2489         }
2490     }
2491 
2492     st->SetTsType(smartType);
2493     return smartType;
2494 }
2495 
Check(ir::VariableDeclaration *st) const2496 checker::Type *ETSAnalyzer::Check(ir::VariableDeclaration *st) const
2497 {
2498     ETSChecker *checker = GetETSChecker();
2499     for (auto *it : st->Declarators()) {
2500         it->Check(checker);
2501     }
2502 
2503     return nullptr;
2504 }
2505 
Check(ir::WhileStatement *st) const2506 checker::Type *ETSAnalyzer::Check(ir::WhileStatement *st) const
2507 {
2508     ETSChecker *checker = GetETSChecker();
2509     checker::ScopeContext scopeCtx(checker, st->Scope());
2510 
2511     //  NOTE: Smart casts are not processed correctly within the loops now, thus clear them at this point.
2512     auto [smartCasts, clearFlag] = checker->Context().EnterLoop(*st);
2513 
2514     checker->CheckTruthinessOfType(st->Test());
2515     st->Body()->Check(checker);
2516 
2517     checker->Context().ExitLoop(smartCasts, clearFlag, st);
2518     return nullptr;
2519 }
2520 
Check(ir::TSArrayType *node) const2521 checker::Type *ETSAnalyzer::Check(ir::TSArrayType *node) const
2522 {
2523     ETSChecker *checker = GetETSChecker();
2524     node->elementType_->Check(checker);
2525     node->SetTsType(node->GetType(checker));
2526 
2527     const auto arrayType = node->TsType()->AsETSArrayType();
2528     checker->CreateBuiltinArraySignature(arrayType, arrayType->Rank());
2529     return nullptr;
2530 }
2531 
Check(ir::TSAsExpression *expr) const2532 checker::Type *ETSAnalyzer::Check(ir::TSAsExpression *expr) const
2533 {
2534     ETSChecker *checker = GetETSChecker();
2535 
2536     if (expr->TsTypeOrError() != nullptr) {
2537         return expr->TsTypeOrError();
2538     }
2539 
2540     auto *const targetType = expr->TypeAnnotation()->AsTypeNode()->GetType(checker);
2541     // Object expression requires that its type be set by the context before checking. in this case, the target type
2542     // provides that context.
2543     if (expr->Expr()->IsObjectExpression()) {
2544         expr->Expr()->AsObjectExpression()->SetPreferredType(targetType);
2545     }
2546 
2547     if (expr->Expr()->IsArrayExpression()) {
2548         expr->Expr()->AsArrayExpression()->SetPreferredType(targetType);
2549     }
2550 
2551     auto *const sourceType = expr->Expr()->Check(checker);
2552     if (sourceType->IsTypeError()) {
2553         expr->SetTsType(checker->GlobalTypeError());
2554         return expr->TsTypeOrError();
2555     }
2556 
2557     if (targetType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) && sourceType->IsETSReferenceType()) {
2558         auto *const boxedTargetType = checker->PrimitiveTypeAsETSBuiltinType(targetType);
2559         if (!checker->Relation()->IsIdenticalTo(sourceType, boxedTargetType)) {
2560             expr->Expr()->AddAstNodeFlags(ir::AstNodeFlags::CHECKCAST);
2561         }
2562     }
2563 
2564     if (sourceType->DefinitelyETSNullish() && !targetType->PossiblyETSNullish()) {
2565         checker->LogTypeError("Cannot cast 'null' or 'undefined' to non-nullish type.", expr->Expr()->Start());
2566         expr->SetTsType(checker->GlobalTypeError());
2567         return expr->TsTypeOrError();
2568     }
2569 
2570     const checker::CastingContext ctx(
2571         checker->Relation(),
2572         std::initializer_list<TypeErrorMessageElement> {"Cannot cast type '", sourceType, "' to '", targetType, "'"},
2573         checker::CastingContext::ConstructorData {expr->Expr(), sourceType, targetType, expr->Expr()->Start()});
2574 
2575     if (sourceType->IsETSDynamicType() && targetType->IsLambdaObject()) {
2576         // NOTE: itrubachev. change targetType to created lambdaobject type.
2577         // Now targetType is not changed, only construct signature is added to it
2578         checker->BuildLambdaObjectClass(targetType->AsETSObjectType(),
2579                                         expr->TypeAnnotation()->AsETSFunctionType()->ReturnType());
2580     }
2581     expr->isUncheckedCast_ = ctx.UncheckedCast();
2582 
2583     // Make sure the array type symbol gets created for the assembler to be able to emit checkcast.
2584     // Because it might not exist, if this particular array type was never created explicitly.
2585     if (!expr->isUncheckedCast_ && targetType->IsETSArrayType()) {
2586         auto *const targetArrayType = targetType->AsETSArrayType();
2587         checker->CreateBuiltinArraySignature(targetArrayType, targetArrayType->Rank());
2588     }
2589 
2590     if (targetType == checker->GetGlobalTypesHolder()->GlobalBuiltinNeverType()) {
2591         checker->LogTypeError("Cast to 'never' is prohibited", expr->Start());
2592         expr->SetTsType(checker->GlobalTypeError());
2593         return expr->TsTypeOrError();
2594     }
2595 
2596     checker->ComputeApparentType(targetType);
2597     expr->SetTsType(targetType);
2598     return expr->TsType();
2599 }
2600 
Check(ir::TSEnumDeclaration *st) const2601 checker::Type *ETSAnalyzer::Check(ir::TSEnumDeclaration *st) const
2602 {
2603     ETSChecker *checker = GetETSChecker();
2604     varbinder::Variable *enumVar = st->Key()->Variable();
2605     ASSERT(enumVar != nullptr);
2606 
2607     if (enumVar->TsTypeOrError() == nullptr) {
2608         checker::Type *etsEnumType = nullptr;
2609         Check(st->BoxedClass());
2610         if (auto *const itemInit = st->Members().front()->AsTSEnumMember()->Init(); itemInit->IsNumberLiteral()) {
2611             etsEnumType = checker->CreateEnumIntTypeFromEnumDeclaration(st);
2612         } else if (itemInit->IsStringLiteral()) {
2613             etsEnumType = checker->CreateEnumStringTypeFromEnumDeclaration(st);
2614         } else {
2615             checker->LogTypeError("Invalid enumeration value type.", st->Start());
2616             st->SetTsType(checker->GlobalTypeError());
2617             return st->TsTypeOrError();
2618         }
2619         st->SetTsType(etsEnumType);
2620         etsEnumType->SetVariable(enumVar);
2621         enumVar->SetTsType(etsEnumType);
2622     } else if (st->TsTypeOrError() == nullptr) {
2623         st->SetTsType(enumVar->TsTypeOrError());
2624     }
2625 
2626     return st->TsTypeOrError();
2627 }
2628 
Check(ir::TSInterfaceDeclaration *st) const2629 checker::Type *ETSAnalyzer::Check(ir::TSInterfaceDeclaration *st) const
2630 {
2631     ETSChecker *checker = GetETSChecker();
2632 
2633     checker::ETSObjectType *interfaceType {};
2634 
2635     if (st->TsTypeOrError() != nullptr) {
2636         return st->TsTypeOrError();
2637     }
2638 
2639     interfaceType = checker->BuildBasicInterfaceProperties(st);
2640     ASSERT(interfaceType != nullptr);
2641     interfaceType->SetSuperType(checker->GlobalETSObjectType());
2642     checker->CheckInvokeMethodsLegitimacy(interfaceType);
2643     st->SetTsType(interfaceType);
2644 
2645     checker::ScopeContext scopeCtx(checker, st->Scope());
2646     auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_INTERFACE, interfaceType);
2647 
2648     for (auto *it : st->Body()->Body()) {
2649         it->Check(checker);
2650     }
2651 
2652     return nullptr;
2653 }
2654 
Check(ir::TSNonNullExpression *expr) const2655 checker::Type *ETSAnalyzer::Check(ir::TSNonNullExpression *expr) const
2656 {
2657     if (expr->TsTypeOrError() == nullptr) {
2658         ETSChecker *checker = GetETSChecker();
2659         auto exprType = expr->expr_->Check(checker);
2660         //  If the actual [smart] type is definitely 'null' or 'undefined' then probably CTE should be thrown.
2661         //  Anyway we'll definitely obtain NullPointerException at runtime.
2662         if (exprType->DefinitelyETSNullish()) {
2663             checker->LogTypeError(
2664                 "Bad operand type, the operand of the non-nullish expression is 'null' or 'undefined'.",
2665                 expr->Expr()->Start());
2666             expr->SetTsType(checker->GlobalTypeError());
2667             return expr->TsTypeOrError();
2668         }
2669         expr->SetTsType(checker->GetNonNullishType(exprType));
2670     }
2671     expr->SetOriginalType(expr->TsType());
2672     return expr->TsType();
2673 }
2674 
Check(ir::TSQualifiedName *expr) const2675 checker::Type *ETSAnalyzer::Check(ir::TSQualifiedName *expr) const
2676 {
2677     ETSChecker *checker = GetETSChecker();
2678     checker::Type *baseType = expr->Left()->Check(checker);
2679 
2680     if (baseType->IsETSObjectType()) {
2681         auto importDecl = baseType->AsETSObjectType()->GetDeclNode()->Parent()->Parent();
2682         // clang-format off
2683         auto searchName =
2684             importDecl->IsETSImportDeclaration()
2685                 ? checker->VarBinder()->AsETSBinder()->FindNameInAliasMap(
2686                     importDecl->AsETSImportDeclaration()->ResolvedSource()->Str(), expr->Right()->Name())
2687                 : expr->Right()->Name();
2688         // clang-format on
2689         // NOTE (oeotvos) This should be done differently in the follow-up patch.
2690         if (searchName.Empty()) {
2691             searchName = expr->Right()->Name();
2692         }
2693         varbinder::Variable *prop =
2694             baseType->AsETSObjectType()->GetProperty(searchName, checker::PropertySearchFlags::SEARCH_DECL);
2695         // NOTE(dslynko): in debugger evaluation mode must lazily generate module's properties here.
2696 
2697         if (prop == nullptr) {
2698             checker->LogTypeError({"'", expr->Right()->Name(), "' type does not exist."}, expr->Right()->Start());
2699             return checker->GlobalTypeError();
2700         }
2701 
2702         if (expr->Right()->Name().Is(searchName.Mutf8()) && prop->Declaration()->Node()->HasExportAlias()) {
2703             checker->LogTypeError({"Cannot find imported element '", searchName, "' exported with alias"},
2704                                   expr->Right()->Start());
2705             return checker->GlobalTypeError();
2706         }
2707 
2708         expr->Right()->SetVariable(prop);
2709         return checker->GetTypeOfVariable(prop);
2710     }
2711 
2712     checker->LogTypeError({"'", expr->Right()->Name(), "' type does not exist."}, expr->Right()->Start());
2713     return checker->GlobalTypeError();
2714 }
2715 
Check(ir::TSTypeAliasDeclaration *st) const2716 checker::Type *ETSAnalyzer::Check(ir::TSTypeAliasDeclaration *st) const
2717 {
2718     ETSChecker *checker = GetETSChecker();
2719     if (st->TypeParams() == nullptr) {
2720         const checker::SavedTypeRelationFlagsContext savedFlagsCtx(
2721             checker->Relation(), checker::TypeRelationFlag::NO_THROW_GENERIC_TYPEALIAS);
2722 
2723         if (st->TypeAnnotation()->TsTypeOrError() == nullptr) {
2724             st->TypeAnnotation()->Check(checker);
2725         }
2726 
2727         return nullptr;
2728     }
2729 
2730     if (st->TypeParameterTypes().empty()) {
2731         auto [typeParamTypes, ok] = checker->CreateUnconstrainedTypeParameters(st->TypeParams());
2732         st->SetTypeParameterTypes(std::move(typeParamTypes));
2733         if (ok) {
2734             checker->AssignTypeParameterConstraints(st->TypeParams());
2735         }
2736     }
2737 
2738     for (auto *const param : st->TypeParams()->Params()) {
2739         const auto *const res = st->TypeAnnotation()->FindChild([&param](const ir::AstNode *const node) {
2740             if (!node->IsIdentifier()) {
2741                 return false;
2742             }
2743 
2744             return param->Name()->AsIdentifier()->Variable() == node->AsIdentifier()->Variable();
2745         });
2746 
2747         if (res == nullptr) {
2748             checker->LogTypeError(
2749                 {"Type alias generic parameter '", param->Name()->Name(), "' is not used in type annotation"},
2750                 param->Start());
2751             return checker->GlobalTypeError();
2752         }
2753     }
2754 
2755     const checker::SavedTypeRelationFlagsContext savedFlagsCtx(checker->Relation(),
2756                                                                checker::TypeRelationFlag::NO_THROW_GENERIC_TYPEALIAS);
2757 
2758     if (st->TypeAnnotation()->TsTypeOrError() == nullptr) {
2759         st->TypeAnnotation()->Check(checker);
2760     }
2761 
2762     return nullptr;
2763 }
2764 }  // namespace ark::es2panda::checker
2765