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