• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *> &params,
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