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 30namespace ark::es2panda::checker { 31 32ETSChecker *ETSAnalyzer::GetETSChecker() const 33{ 34 return static_cast<ETSChecker *>(GetChecker()); 35} 36 37// from base folder 38checker::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 59checker::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 74checker::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 96checker::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 122static 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 151checker::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 210void 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 257checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::Property *expr) const 258{ 259 return nullptr; 260} 261 262checker::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 271checker::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 278checker::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 305checker::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 336checker::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 366checker::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 399void 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 434checker::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 486checker::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 501checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSPackageDeclaration *st) const 502{ 503 return nullptr; 504} 505 506checker::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 528checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSPrimitiveType *node) const 529{ 530 ETSChecker *checker = GetETSChecker(); 531 return node->GetType(checker); 532} 533 534checker::Type *ETSAnalyzer::Check(ir::ETSStructDeclaration *node) const 535{ 536 ETSChecker *checker = GetETSChecker(); 537 node->Definition()->Check(checker); 538 return nullptr; 539} 540 541checker::Type *ETSAnalyzer::Check(ir::ETSTypeReference *node) const 542{ 543 ETSChecker *checker = GetETSChecker(); 544 return node->GetType(checker); 545} 546 547checker::Type *ETSAnalyzer::Check(ir::ETSTypeReferencePart *node) const 548{ 549 ETSChecker *checker = GetETSChecker(); 550 return node->GetType(checker); 551} 552 553checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSNullType *node) const 554{ 555 return nullptr; 556} 557 558checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSUndefinedType *node) const 559{ 560 return nullptr; 561} 562 563checker::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 571checker::Type *ETSAnalyzer::GetPreferredType(ir::ArrayExpression *expr) const 572{ 573 return expr->preferredType_; 574} 575 576static 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 615static 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 675checker::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 725checker::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 794static 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 806checker::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 835checker::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 881std::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 930checker::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 951checker::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 980checker::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 997checker::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 1016checker::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 1055checker::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 1118static 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 1131static 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 1143checker::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 1182checker::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 1227static 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 1236checker::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 1298checker::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 1317std::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 1345static 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 1354checker::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 1416checker::Type *ETSAnalyzer::PreferredType(ir::ObjectExpression *expr) const 1417{ 1418 return expr->preferredType_; 1419} 1420 1421static 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 1438checker::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 1514void 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 1568checker::Type *ETSAnalyzer::Check(ir::OpaqueTypeNode *expr) const 1569{ 1570 return expr->TsType(); 1571} 1572 1573checker::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 1588checker::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 1599checker::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 1624checker::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 1664static 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 1707static 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 1723checker::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 1735checker::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 1795checker::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 1845checker::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 1852checker::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 1861checker::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 1870checker::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 1879checker::Type *ETSAnalyzer::Check(ir::NamespaceDeclaration *st) const 1880{ 1881 ETSChecker *checker = GetETSChecker(); 1882 st->Definition()->Check(checker); 1883 return nullptr; 1884} 1885 1886checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::NamespaceDefinition *st) const 1887{ 1888 return nullptr; 1889} 1890 1891checker::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 1913checker::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 1922checker::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 1935checker::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 1958checker::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 1977checker::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 2020checker::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 2033checker::Type *ETSAnalyzer::Check(ir::ClassDeclaration *st) const 2034{ 2035 ETSChecker *checker = GetETSChecker(); 2036 st->Definition()->Check(checker); 2037 return nullptr; 2038} 2039 2040checker::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 2053checker::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 2068checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::EmptyStatement *st) const 2069{ 2070 return nullptr; 2071} 2072 2073checker::Type *ETSAnalyzer::Check(ir::ExpressionStatement *st) const 2074{ 2075 ETSChecker *checker = GetETSChecker(); 2076 return st->GetExpression()->Check(checker); 2077} 2078 2079static 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) 2111static constexpr char const MISSING_SOURCE_EXPR_TYPE[] = 2112 "Cannot determine source expression type in the 'for-of' statement."; 2113static 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 2117checker::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 2162checker::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 2188checker::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 2241checker::Type *ETSAnalyzer::Check(ir::LabelledStatement *st) const 2242{ 2243 ETSChecker *checker = GetETSChecker(); 2244 st->body_->Check(checker); 2245 return nullptr; 2246} 2247 2248bool 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 2292checker::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 2324checker::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 2351checker::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 2399checker::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 2413checker::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 2457checker::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 2496checker::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 2506checker::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 2521checker::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 2532checker::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 2601checker::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 2629checker::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 2655checker::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 2675checker::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 2716checker::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