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 "ir/typeNode.h" 17#include "ir/expressions/literals/stringLiteral.h" 18#include "ir/expressions/literals/bigIntLiteral.h" 19#include "ir/expressions/literals/numberLiteral.h" 20#include "ir/expressions/arrayExpression.h" 21#include "ir/expressions/assignmentExpression.h" 22#include "ir/expressions/callExpression.h" 23#include "ir/expressions/objectExpression.h" 24#include "ir/expressions/identifier.h" 25#include "ir/base/scriptFunction.h" 26#include "ir/base/property.h" 27#include "ir/base/spreadElement.h" 28#include "ir/statements/blockStatement.h" 29#include "ir/statements/returnStatement.h" 30#include "ir/statements/functionDeclaration.h" 31#include "util/helpers.h" 32#include "varbinder/variable.h" 33#include "varbinder/scope.h" 34#include "varbinder/declaration.h" 35 36#include "checker/TSchecker.h" 37#include "checker/ts/destructuringContext.h" 38#include "checker/types/ts/objectDescriptor.h" 39#include "checker/types/ts/objectType.h" 40 41#include <cstddef> 42#include <cstdint> 43#include <memory> 44#include <utility> 45#include <vector> 46 47namespace ark::es2panda::checker { 48Type *TSChecker::HandleFunctionReturn(ir::ScriptFunction *func) 49{ 50 if (func->ReturnTypeAnnotation() != nullptr) { 51 func->ReturnTypeAnnotation()->Check(this); 52 Type *returnType = func->ReturnTypeAnnotation()->GetType(this); 53 54 if (func->IsArrow() && func->Body()->IsExpression()) { 55 ElaborateElementwise(returnType, func->Body()->AsExpression(), func->Body()->Start()); 56 } 57 58 if (returnType->IsNeverType()) { 59 ThrowTypeError("A function returning 'never' cannot have a reachable end point.", 60 func->ReturnTypeAnnotation()->Start()); 61 } 62 63 if (!MaybeTypeOfKind(returnType, TypeFlag::ANY_OR_VOID)) { 64 CheckAllCodePathsInNonVoidFunctionReturnOrThrow( 65 func, func->ReturnTypeAnnotation()->Start(), 66 "A function whose declared type is neither 'void' nor 'any' must return a value."); 67 } 68 69 return returnType; 70 } 71 72 if (func->Declare()) { 73 return GlobalAnyType(); 74 } 75 76 if (func->IsArrow() && func->Body()->IsExpression()) { 77 return func->Body()->Check(this); 78 } 79 80 ArenaVector<Type *> returnTypes(Allocator()->Adapter()); 81 CollectTypesFromReturnStatements(func->Body(), &returnTypes); 82 83 if (returnTypes.empty()) { 84 return GlobalVoidType(); 85 } 86 87 if (returnTypes.size() == 1 && returnTypes[0] == GlobalResolvingReturnType()) { 88 ThrowReturnTypeCircularityError(func); 89 } 90 91 for (auto *it : returnTypes) { 92 if (it == GlobalResolvingReturnType()) { 93 ThrowReturnTypeCircularityError(func); 94 } 95 } 96 97 return CreateUnionType(std::move(returnTypes)); 98} 99 100void TSChecker::ThrowReturnTypeCircularityError(ir::ScriptFunction *func) 101{ 102 if (func->ReturnTypeAnnotation() != nullptr) { 103 ThrowTypeError("Return type annotation circularly reference itself", func->ReturnTypeAnnotation()->Start()); 104 } 105 106 if (func->Id() != nullptr) { 107 ThrowTypeError({func->Id()->AsIdentifier()->Name(), 108 " implicitly has return type 'any' because it does not have a return type annotation and is " 109 "referenced directly or indirectly in one of its return expressions."}, 110 func->Id()->Start()); 111 } 112 113 ThrowTypeError( 114 "Function implicitly has return type 'any' because it does not have a return type annotation and is " 115 "referenced directly or indirectly in one of its return expressions.", 116 func->Start()); 117} 118 119std::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> TSChecker::CheckFunctionIdentifierParameter( 120 ir::Identifier *param) 121{ 122 ASSERT(param->Variable()); 123 varbinder::Variable *paramVar = param->Variable(); 124 bool isOptional = param->IsOptional(); 125 126 if (param->TypeAnnotation() == nullptr) { 127 ThrowTypeError({"Parameter ", param->Name(), " implicitly has any type."}, param->Start()); 128 } 129 130 if (isOptional) { 131 paramVar->AddFlag(varbinder::VariableFlags::OPTIONAL); 132 } 133 134 param->TypeAnnotation()->Check(this); 135 paramVar->SetTsType(param->TypeAnnotation()->GetType(this)); 136 return {paramVar->AsLocalVariable(), nullptr, isOptional}; 137} 138 139Type *TSChecker::CreateParameterTypeForArrayAssignmentPattern(ir::ArrayExpression *arrayPattern, Type *inferredType) 140{ 141 if (!inferredType->IsObjectType()) { 142 return inferredType; 143 } 144 145 ASSERT(inferredType->AsObjectType()->IsTupleType()); 146 TupleType *inferredTuple = inferredType->AsObjectType()->AsTupleType(); 147 148 if (inferredTuple->FixedLength() > arrayPattern->Elements().size()) { 149 return inferredType; 150 } 151 152 TupleType *newTuple = 153 inferredTuple->Instantiate(Allocator(), Relation(), GetGlobalTypesHolder())->AsObjectType()->AsTupleType(); 154 155 for (uint32_t index = inferredTuple->FixedLength(); index < arrayPattern->Elements().size(); index++) { 156 util::StringView memberIndex = util::Helpers::ToStringView(Allocator(), index); 157 varbinder::LocalVariable *newMember = varbinder::Scope::CreateVar( 158 Allocator(), memberIndex, varbinder::VariableFlags::PROPERTY | varbinder::VariableFlags::OPTIONAL, nullptr); 159 newMember->SetTsType(GlobalAnyType()); 160 newTuple->AddProperty(newMember); 161 } 162 163 return newTuple; 164} 165 166Type *TSChecker::CreateParameterTypeForObjectAssignmentPattern(ir::ObjectExpression *objectPattern, Type *inferredType) 167{ 168 if (!inferredType->IsObjectType()) { 169 return inferredType; 170 } 171 172 ObjectType *newObject = inferredType->Instantiate(Allocator(), Relation(), GetGlobalTypesHolder())->AsObjectType(); 173 174 for (auto *it : objectPattern->Properties()) { 175 if (it->IsRestElement()) { 176 continue; 177 } 178 179 ir::Property *prop = it->AsProperty(); 180 varbinder::LocalVariable *foundVar = newObject->GetProperty(prop->Key()->AsIdentifier()->Name(), true); 181 182 if (foundVar != nullptr) { 183 if (prop->Value()->IsAssignmentPattern()) { 184 foundVar->AddFlag(varbinder::VariableFlags::OPTIONAL); 185 } 186 187 continue; 188 } 189 190 ASSERT(prop->Value()->IsAssignmentPattern()); 191 ir::AssignmentExpression *assignmentPattern = prop->Value()->AsAssignmentPattern(); 192 193 varbinder::LocalVariable *newProp = varbinder::Scope::CreateVar( 194 Allocator(), prop->Key()->AsIdentifier()->Name(), 195 varbinder::VariableFlags::PROPERTY | varbinder::VariableFlags::OPTIONAL, nullptr); 196 newProp->SetTsType(GetBaseTypeOfLiteralType(CheckTypeCached(assignmentPattern->Right()))); 197 newObject->AddProperty(newProp); 198 } 199 200 newObject->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); 201 return newObject; 202} 203 204using ReturnedVariable = std::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool>; 205ReturnedVariable TSChecker::CheckFunctionAssignmentPatternParameter(ir::AssignmentExpression *param) 206{ 207 if (param->Left()->IsIdentifier()) { 208 ir::Identifier *paramIdent = param->Left()->AsIdentifier(); 209 varbinder::Variable *paramVar = paramIdent->Variable(); 210 ASSERT(paramVar); 211 212 if (paramIdent->TypeAnnotation() != nullptr) { 213 paramIdent->TypeAnnotation()->Check(this); 214 Type *paramType = paramIdent->TypeAnnotation()->GetType(this); 215 paramVar->SetTsType(paramType); 216 ElaborateElementwise(paramType, param->Right(), paramIdent->Start()); 217 return {paramVar->AsLocalVariable(), nullptr, true}; 218 } 219 220 paramVar->SetTsType(GetBaseTypeOfLiteralType(param->Right()->Check(this))); 221 paramVar->AddFlag(varbinder::VariableFlags::OPTIONAL); 222 return {paramVar->AsLocalVariable(), nullptr, true}; 223 } 224 225 Type *paramType = nullptr; 226 std::stringstream ss; 227 228 auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE | CheckerStatus::IN_PARAMETER); 229 230 if (param->Left()->IsArrayPattern()) { 231 ir::ArrayExpression *arrayPattern = param->Left()->AsArrayPattern(); 232 auto context = ArrayDestructuringContext( 233 {this, arrayPattern, false, true, arrayPattern->TypeAnnotation(), param->Right()}); 234 context.Start(); 235 paramType = CreateParameterTypeForArrayAssignmentPattern(arrayPattern, context.InferredType()); 236 CreatePatternParameterName(param->Left(), ss); 237 } else { 238 ir::ObjectExpression *objectPattern = param->Left()->AsObjectPattern(); 239 auto context = ObjectDestructuringContext( 240 {this, objectPattern, false, true, objectPattern->TypeAnnotation(), param->Right()}); 241 context.Start(); 242 paramType = CreateParameterTypeForObjectAssignmentPattern(objectPattern, context.InferredType()); 243 CreatePatternParameterName(param->Left(), ss); 244 } 245 246 util::UString pn(ss.str(), Allocator()); 247 varbinder::LocalVariable *patternVar = 248 varbinder::Scope::CreateVar(Allocator(), pn.View(), varbinder::VariableFlags::NONE, param); 249 patternVar->SetTsType(paramType); 250 patternVar->AddFlag(varbinder::VariableFlags::OPTIONAL); 251 return {patternVar->AsLocalVariable(), nullptr, true}; 252} 253 254std::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> TSChecker::CheckFunctionRestParameter( 255 ir::SpreadElement *param, SignatureInfo *signatureInfo) 256{ 257 ir::TypeNode *typeAnnotation = nullptr; 258 if (param->Argument() != nullptr) { 259 typeAnnotation = param->Argument()->AsAnnotatedExpression()->TypeAnnotation(); 260 } 261 262 Type *restType = Allocator()->New<ArrayType>(GlobalAnyType()); 263 264 if (typeAnnotation != nullptr) { 265 typeAnnotation->Check(this); 266 restType = typeAnnotation->GetType(this); 267 if (!restType->IsArrayType()) { 268 ThrowTypeError("A rest parameter must be of an array type", param->Start()); 269 } 270 } 271 272 switch (param->Argument()->Type()) { 273 case ir::AstNodeType::IDENTIFIER: { 274 ir::Identifier *restIdent = param->Argument()->AsIdentifier(); 275 ASSERT(restIdent->Variable()); 276 restIdent->Variable()->SetTsType(restType->AsArrayType()->ElementType()); 277 return {nullptr, restIdent->Variable()->AsLocalVariable(), false}; 278 } 279 case ir::AstNodeType::OBJECT_PATTERN: { 280 ASSERT(param->Argument()->IsObjectPattern()); 281 auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE); 282 auto destructuringContext = 283 ObjectDestructuringContext({this, param->Argument(), false, false, nullptr, nullptr}); 284 destructuringContext.SetInferredType(restType); 285 destructuringContext.SetSignatureInfo(signatureInfo); 286 destructuringContext.Start(); 287 return {nullptr, nullptr, false}; 288 } 289 case ir::AstNodeType::ARRAY_PATTERN: { 290 auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE); 291 auto destructuringContext = 292 ArrayDestructuringContext({this, param->Argument(), false, false, nullptr, nullptr}); 293 destructuringContext.SetInferredType(restType); 294 destructuringContext.SetSignatureInfo(signatureInfo); 295 destructuringContext.Start(); 296 return {nullptr, nullptr, false}; 297 } 298 default: { 299 UNREACHABLE(); 300 } 301 } 302} 303 304std::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> TSChecker::CheckFunctionArrayPatternParameter( 305 ir::ArrayExpression *param) 306{ 307 std::stringstream ss; 308 CreatePatternParameterName(param, ss); 309 util::UString pn(ss.str(), Allocator()); 310 varbinder::LocalVariable *patternVar = 311 varbinder::Scope::CreateVar(Allocator(), pn.View(), varbinder::VariableFlags::NONE, param); 312 313 if (param->TypeAnnotation() != nullptr) { 314 auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE); 315 auto destructuringContext = 316 ArrayDestructuringContext({this, param->AsArrayPattern(), false, false, param->TypeAnnotation(), nullptr}); 317 destructuringContext.Start(); 318 patternVar->SetTsType(destructuringContext.InferredType()); 319 return {patternVar->AsLocalVariable(), nullptr, false}; 320 } 321 322 patternVar->SetTsType(param->CheckPattern(this)); 323 return {patternVar->AsLocalVariable(), nullptr, false}; 324} 325 326std::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> TSChecker::CheckFunctionObjectPatternParameter( 327 ir::ObjectExpression *param) 328{ 329 std::stringstream ss; 330 CreatePatternParameterName(param, ss); 331 util::UString pn(ss.str(), Allocator()); 332 varbinder::LocalVariable *patternVar = 333 varbinder::Scope::CreateVar(Allocator(), pn.View(), varbinder::VariableFlags::NONE, param); 334 335 if (param->TypeAnnotation() != nullptr) { 336 auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE); 337 auto destructuringContext = ObjectDestructuringContext( 338 {this, param->AsObjectPattern(), false, false, param->TypeAnnotation(), nullptr}); 339 destructuringContext.Start(); 340 patternVar->SetTsType(destructuringContext.InferredType()); 341 return {patternVar->AsLocalVariable(), nullptr, false}; 342 } 343 344 patternVar->SetTsType(param->CheckPattern(this)); 345 return {patternVar->AsLocalVariable(), nullptr, false}; 346} 347 348std::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> TSChecker::CheckFunctionParameter( 349 ir::Expression *param, SignatureInfo *signatureInfo) 350{ 351 std::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> result; 352 if (param->TsType() != nullptr) { 353 ASSERT(param->TsType()->Variable()); 354 varbinder::Variable *var = param->TsType()->Variable(); 355 result = {var->AsLocalVariable(), nullptr, var->HasFlag(varbinder::VariableFlags::OPTIONAL)}; 356 return result; 357 } 358 359 bool cache = true; 360 switch (param->Type()) { 361 case ir::AstNodeType::IDENTIFIER: { 362 result = CheckFunctionIdentifierParameter(param->AsIdentifier()); 363 break; 364 } 365 case ir::AstNodeType::ASSIGNMENT_PATTERN: { 366 result = CheckFunctionAssignmentPatternParameter(param->AsAssignmentPattern()); 367 break; 368 } 369 case ir::AstNodeType::REST_ELEMENT: { 370 result = CheckFunctionRestParameter(param->AsRestElement(), signatureInfo); 371 cache = false; 372 break; 373 } 374 case ir::AstNodeType::ARRAY_PATTERN: { 375 result = CheckFunctionArrayPatternParameter(param->AsArrayPattern()); 376 break; 377 } 378 case ir::AstNodeType::OBJECT_PATTERN: { 379 result = CheckFunctionObjectPatternParameter(param->AsObjectPattern()); 380 break; 381 } 382 default: { 383 UNREACHABLE(); 384 } 385 } 386 387 if (cache) { 388 Type *placeholder = Allocator()->New<ArrayType>(GlobalAnyType()); 389 placeholder->SetVariable(std::get<0>(result)); 390 param->SetTsType(placeholder); 391 } 392 393 return result; 394} 395 396void TSChecker::CheckFunctionParameterDeclarations(const ArenaVector<ir::Expression *> ¶ms, 397 SignatureInfo *signatureInfo) 398{ 399 signatureInfo->restVar = nullptr; 400 signatureInfo->minArgCount = 0; 401 402 for (auto it = params.rbegin(); it != params.rend(); it++) { 403 auto [paramVar, restVar, isOptional] = CheckFunctionParameter(*it, signatureInfo); 404 405 if (restVar != nullptr) { 406 signatureInfo->restVar = restVar; 407 continue; 408 } 409 410 if (paramVar == nullptr) { 411 continue; 412 } 413 414 signatureInfo->params.insert(signatureInfo->params.begin(), paramVar); 415 416 if (!isOptional) { 417 signatureInfo->minArgCount++; 418 } 419 } 420} 421 422bool ShouldCreatePropertyValueName(ir::Expression *propValue) 423{ 424 return propValue->IsArrayPattern() || propValue->IsObjectPattern() || 425 (propValue->IsAssignmentPattern() && (propValue->AsAssignmentPattern()->Left()->IsArrayPattern() || 426 propValue->AsAssignmentPattern()->Left()->IsObjectPattern())); 427} 428 429void TSChecker::HandlePropertyPatternParameterName(ir::Property *prop, std::stringstream &ss) 430{ 431 util::StringView propName; 432 if (prop->Key()->IsIdentifier()) { 433 propName = prop->Key()->AsIdentifier()->Name(); 434 } else { 435 switch (prop->Key()->Type()) { 436 case ir::AstNodeType::NUMBER_LITERAL: { 437 propName = 438 util::Helpers::ToStringView(Allocator(), prop->Key()->AsNumberLiteral()->Number().GetDouble()); 439 break; 440 } 441 case ir::AstNodeType::BIGINT_LITERAL: { 442 propName = prop->Key()->AsBigIntLiteral()->Str(); 443 break; 444 } 445 case ir::AstNodeType::STRING_LITERAL: { 446 propName = prop->Key()->AsStringLiteral()->Str(); 447 break; 448 } 449 default: { 450 UNREACHABLE(); 451 break; 452 } 453 } 454 } 455 456 ss << propName; 457 458 if (ShouldCreatePropertyValueName(prop->Value())) { 459 ss << ": "; 460 TSChecker::CreatePatternParameterName(prop->Value(), ss); 461 } 462} 463 464void TSChecker::CreatePatternParameterName(ir::AstNode *node, std::stringstream &ss) 465{ 466 switch (node->Type()) { 467 case ir::AstNodeType::IDENTIFIER: { 468 ss << node->AsIdentifier()->Name(); 469 break; 470 } 471 case ir::AstNodeType::ARRAY_PATTERN: { 472 ss << "["; 473 474 const auto &elements = node->AsArrayPattern()->Elements(); 475 for (auto it = elements.begin(); it != elements.end(); it++) { 476 CreatePatternParameterName(*it, ss); 477 if (std::next(it) != elements.end()) { 478 ss << ", "; 479 } 480 } 481 482 ss << "]"; 483 break; 484 } 485 case ir::AstNodeType::OBJECT_PATTERN: { 486 ss << "{ "; 487 488 const auto &properties = node->AsObjectPattern()->Properties(); 489 for (auto it = properties.begin(); it != properties.end(); it++) { 490 CreatePatternParameterName(*it, ss); 491 if (std::next(it) != properties.end()) { 492 ss << ", "; 493 } 494 } 495 496 ss << " }"; 497 break; 498 } 499 case ir::AstNodeType::ASSIGNMENT_PATTERN: { 500 CreatePatternParameterName(node->AsAssignmentPattern()->Left(), ss); 501 break; 502 } 503 case ir::AstNodeType::PROPERTY: { 504 HandlePropertyPatternParameterName(node->AsProperty(), ss); 505 break; 506 } 507 case ir::AstNodeType::REST_ELEMENT: { 508 ss << "..."; 509 TSChecker::CreatePatternParameterName(node->AsRestElement()->Argument(), ss); 510 break; 511 } 512 default: 513 break; 514 } 515} 516 517ir::Statement *FindSubsequentFunctionNode(ir::BlockStatement *block, ir::ScriptFunction *node) 518{ 519 for (auto it = block->Statements().begin(); it != block->Statements().end(); it++) { 520 if ((*it)->IsFunctionDeclaration() && (*it)->AsFunctionDeclaration()->Function() == node) { 521 return *(++it); 522 } 523 } 524 525 UNREACHABLE(); 526 return nullptr; 527} 528 529void TSChecker::ValidateSubsequentNode(const ir::Statement *const subsequentNode, const ir::ScriptFunction *const func) 530{ 531 if (!subsequentNode->IsFunctionDeclaration()) { 532 ThrowTypeError("Function implementation is missing or not immediately following the declaration.", 533 func->Id()->Start()); 534 } 535 536 const ir::ScriptFunction *const subsequentFunc = subsequentNode->AsFunctionDeclaration()->Function(); 537 if (subsequentFunc->Id()->Name() != func->Id()->Name()) { 538 ThrowTypeError("Function implementation is missing or not immediately following the declaration.", 539 func->Id()->Start()); 540 } 541 542 if (subsequentFunc->Declare() != func->Declare()) { 543 ThrowTypeError("Overload signatures must all be ambient or non-ambient.", func->Id()->Start()); 544 } 545} 546 547void TSChecker::CheckOverloadSignatureCompatibility(Signature *bodyCallSignature, Signature *signature) 548{ 549 if (bodyCallSignature->ReturnType()->IsVoidType() || 550 IsTypeAssignableTo(bodyCallSignature->ReturnType(), signature->ReturnType()) || 551 IsTypeAssignableTo(signature->ReturnType(), bodyCallSignature->ReturnType())) { 552 bodyCallSignature->AssignmentTarget(Relation(), signature); 553 554 if (Relation()->IsTrue()) { 555 return; 556 } 557 } 558 559 ASSERT(signature->Function()); 560 ThrowTypeError("This overload signature is not compatible with its implementation signature", 561 signature->Function()->Id()->Start()); 562} 563 564void TSChecker::InferFunctionDeclarationType(const varbinder::FunctionDecl *decl, varbinder::Variable *funcVar) 565{ 566 ir::ScriptFunction *bodyDeclaration = decl->Decls().back(); 567 if (bodyDeclaration->IsOverload()) { 568 ThrowTypeError("Function implementation is missing or not immediately following the declaration.", 569 bodyDeclaration->Id()->Start()); 570 } 571 572 ObjectDescriptor *descWithOverload = Allocator()->New<ObjectDescriptor>(Allocator()); 573 for (auto it = decl->Decls().begin(); it != decl->Decls().end() - 1; it++) { 574 ir::ScriptFunction *func = *it; 575 ASSERT(func->IsOverload() && (*it)->Parent()->Parent()->IsBlockStatement()); 576 ir::Statement *subsequentNode = FindSubsequentFunctionNode((*it)->Parent()->Parent()->AsBlockStatement(), func); 577 ASSERT(subsequentNode); 578 ValidateSubsequentNode(subsequentNode, func); 579 580 ScopeContext scopeCtx(this, func->Scope()); 581 582 auto *overloadSignatureInfo = Allocator()->New<checker::SignatureInfo>(Allocator()); 583 CheckFunctionParameterDeclarations(func->Params(), overloadSignatureInfo); 584 585 Type *returnType = GlobalAnyType(); 586 587 if (func->ReturnTypeAnnotation() != nullptr) { 588 func->ReturnTypeAnnotation()->Check(this); 589 returnType = func->ReturnTypeAnnotation()->GetType(this); 590 } 591 592 Signature *overloadSignature = Allocator()->New<checker::Signature>(overloadSignatureInfo, returnType, func); 593 descWithOverload->callSignatures.push_back(overloadSignature); 594 } 595 596 ScopeContext scopeCtx(this, bodyDeclaration->Scope()); 597 598 auto *signatureInfo = Allocator()->New<checker::SignatureInfo>(Allocator()); 599 CheckFunctionParameterDeclarations(bodyDeclaration->Params(), signatureInfo); 600 auto *bodyCallSignature = Allocator()->New<checker::Signature>(signatureInfo, GlobalResolvingReturnType()); 601 602 if (descWithOverload->callSignatures.empty()) { 603 Type *funcType = CreateFunctionTypeWithSignature(bodyCallSignature); 604 funcType->SetVariable(funcVar); 605 funcVar->SetTsType(funcType); 606 } 607 608 bodyCallSignature->SetReturnType(HandleFunctionReturn(bodyDeclaration)); 609 610 if (!descWithOverload->callSignatures.empty()) { 611 Type *funcType = Allocator()->New<FunctionType>(descWithOverload); 612 funcType->SetVariable(funcVar); 613 funcVar->SetTsType(funcType); 614 615 for (auto *iter : descWithOverload->callSignatures) { 616 CheckOverloadSignatureCompatibility(bodyCallSignature, iter); 617 } 618 } 619} 620 621void TSChecker::CollectTypesFromReturnStatements(ir::AstNode *parent, ArenaVector<Type *> *returnTypes) 622{ 623 parent->Iterate([this, returnTypes](ir::AstNode *childNode) -> void { 624 if (childNode->IsScriptFunction()) { 625 return; 626 } 627 628 if (childNode->IsReturnStatement()) { 629 ir::ReturnStatement *returnStmt = childNode->AsReturnStatement(); 630 631 if (returnStmt->Argument() == nullptr) { 632 return; 633 } 634 635 returnTypes->push_back( 636 GetBaseTypeOfLiteralType(CheckTypeCached(childNode->AsReturnStatement()->Argument()))); 637 } 638 639 CollectTypesFromReturnStatements(childNode, returnTypes); 640 }); 641} 642 643static bool SearchForReturnOrThrow(ir::AstNode *parent) 644{ 645 bool found = false; 646 647 parent->Iterate([&found](ir::AstNode *childNode) -> void { 648 if (childNode->IsThrowStatement() || childNode->IsReturnStatement()) { 649 found = true; 650 return; 651 } 652 653 if (childNode->IsScriptFunction()) { 654 return; 655 } 656 657 SearchForReturnOrThrow(childNode); 658 }); 659 660 return found; 661} 662 663void TSChecker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(ir::ScriptFunction *func, 664 lexer::SourcePosition lineInfo, const char *errMsg) 665{ 666 if (!SearchForReturnOrThrow(func->Body())) { 667 ThrowTypeError(errMsg, lineInfo); 668 } 669 // NOTE: aszilagyi. this function is not fully implement the TSC one, in the future if we will have a 670 // noImplicitReturn compiler option for TypeScript we should update this function 671} 672 673ArgRange TSChecker::GetArgRange(const ArenaVector<Signature *> &signatures, 674 ArenaVector<Signature *> *potentialSignatures, uint32_t callArgsSize, 675 bool *haveSignatureWithRest) 676{ 677 uint32_t minArg = UINT32_MAX; 678 uint32_t maxArg = 0; 679 680 for (auto *it : signatures) { 681 if (it->RestVar() != nullptr) { 682 *haveSignatureWithRest = true; 683 } 684 685 if (it->MinArgCount() < minArg) { 686 minArg = it->MinArgCount(); 687 } 688 689 if (it->Params().size() > maxArg) { 690 maxArg = it->Params().size(); 691 } 692 693 if (callArgsSize >= it->MinArgCount() && (callArgsSize <= it->Params().size() || it->RestVar() != nullptr)) { 694 potentialSignatures->push_back(it); 695 } 696 } 697 698 return {minArg, maxArg}; 699} 700 701bool TSChecker::CallMatchesSignature(const ArenaVector<ir::Expression *> &args, Signature *signature, bool throwError) 702{ 703 for (size_t index = 0; index < args.size(); index++) { 704 checker::Type *sigArgType = nullptr; 705 bool validateRestArg = false; 706 707 if (index >= signature->Params().size()) { 708 ASSERT(signature->RestVar()); 709 validateRestArg = true; 710 sigArgType = signature->RestVar()->TsType(); 711 } else { 712 sigArgType = signature->Params()[index]->TsType(); 713 } 714 715 if (validateRestArg || !throwError) { 716 checker::Type *callArgType = GetBaseTypeOfLiteralType(args[index]->Check(this)); 717 if (IsTypeAssignableTo(callArgType, sigArgType)) { 718 continue; 719 } 720 721 if (throwError) { 722 ThrowTypeError( 723 {"Argument of type '", callArgType, "' is not assignable to parameter of type '", sigArgType, "'."}, 724 args[index]->Start()); 725 } 726 return false; 727 } 728 729 ElaborateElementwise(sigArgType, args[index], args[index]->Start()); 730 } 731 732 return true; 733} 734 735Type *TSChecker::ResolveCallOrNewExpression(const ArenaVector<Signature *> &signatures, 736 ArenaVector<ir::Expression *> arguments, 737 const lexer::SourcePosition &errPos) 738{ 739 if (signatures.empty()) { 740 ThrowTypeError("This expression is not callable.", errPos); 741 } 742 743 ArenaVector<checker::Signature *> potentialSignatures(Allocator()->Adapter()); 744 bool haveSignatureWithRest = false; 745 746 auto argRange = GetArgRange(signatures, &potentialSignatures, arguments.size(), &haveSignatureWithRest); 747 748 if (potentialSignatures.empty()) { 749 if (haveSignatureWithRest) { 750 ThrowTypeError({"Expected at least ", argRange.first, " arguments, but got ", arguments.size(), "."}, 751 errPos); 752 } 753 754 if (signatures.size() == 1 && argRange.first == argRange.second) { 755 lexer::SourcePosition loc = 756 (argRange.first > arguments.size()) ? errPos : arguments[argRange.second]->Start(); 757 ThrowTypeError({"Expected ", argRange.first, " arguments, but got ", arguments.size(), "."}, loc); 758 } 759 760 ThrowTypeError({"Expected ", argRange.first, "-", argRange.second, " arguments, but got ", arguments.size()}, 761 errPos); 762 } 763 764 checker::Type *returnType = nullptr; 765 for (auto *it : potentialSignatures) { 766 if (CallMatchesSignature(arguments, it, potentialSignatures.size() == 1)) { 767 returnType = it->ReturnType(); 768 break; 769 } 770 } 771 772 if (returnType == nullptr) { 773 ThrowTypeError("No overload matches this call.", errPos); 774 } 775 776 return returnType; 777} 778} // namespace ark::es2panda::checker 779