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