• 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