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