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([¶m](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