• 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         if (!restType->IsArrayType()) {
284             // TODO(aszilagyi): handle tuple type for rest
285             ThrowTypeError("A rest parameter must be of an array type", param->Start());
286         }
287     }
288 
289     switch (param->Argument()->Type()) {
290         case ir::AstNodeType::IDENTIFIER: {
291             const ir::Identifier *restIdent = param->Argument()->AsIdentifier();
292             ASSERT(restIdent->Variable());
293             restIdent->Variable()->SetTsType(restType->AsArrayType()->ElementType());
294             return {nullptr, restIdent->Variable()->AsLocalVariable(), false};
295         }
296         case ir::AstNodeType::OBJECT_PATTERN: {
297             ASSERT(param->Argument()->IsObjectPattern());
298             auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE);
299             auto destructuringContext =
300                 ObjectDestructuringContext(this, param->Argument(), false, false, nullptr, nullptr);
301             destructuringContext.SetInferedType(restType);
302             destructuringContext.SetSignatureInfo(signatureInfo);
303             destructuringContext.Start();
304             return {nullptr, nullptr, false};
305         }
306         case ir::AstNodeType::ARRAY_PATTERN: {
307             auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE);
308             auto destructuringContext =
309                 ArrayDestructuringContext(this, param->Argument(), false, false, nullptr, nullptr);
310             destructuringContext.SetInferedType(restType);
311             destructuringContext.SetSignatureInfo(signatureInfo);
312             destructuringContext.Start();
313             return {nullptr, nullptr, false};
314         }
315         default: {
316             UNREACHABLE();
317         }
318     }
319 }
320 
CheckFunctionArrayPatternParameter(const ir::ArrayExpression * param)321 std::tuple<binder::LocalVariable *, binder::LocalVariable *, bool> Checker::CheckFunctionArrayPatternParameter(
322     const ir::ArrayExpression *param)
323 {
324     std::stringstream ss;
325     CreatePatternParameterName(param, ss);
326     util::UString pn(ss.str(), allocator_);
327     binder::LocalVariable *patternVar =
328         binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param);
329 
330     if (param->TypeAnnotation()) {
331         auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE);
332         auto destructuringContext =
333             ArrayDestructuringContext(this, param->AsArrayPattern(), false, false, param->TypeAnnotation(), nullptr);
334         destructuringContext.Start();
335         patternVar->SetTsType(destructuringContext.InferedType());
336         return {patternVar->AsLocalVariable(), nullptr, false};
337     }
338 
339     patternVar->SetTsType(param->CheckPattern(this));
340     return {patternVar->AsLocalVariable(), nullptr, false};
341 }
342 
CheckFunctionObjectPatternParameter(const ir::ObjectExpression * param)343 std::tuple<binder::LocalVariable *, binder::LocalVariable *, bool> Checker::CheckFunctionObjectPatternParameter(
344     const ir::ObjectExpression *param)
345 {
346     std::stringstream ss;
347     CreatePatternParameterName(param, ss);
348     util::UString pn(ss.str(), allocator_);
349     binder::LocalVariable *patternVar =
350         binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param);
351 
352     if (param->TypeAnnotation()) {
353         auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE);
354         auto destructuringContext =
355             ObjectDestructuringContext(this, param->AsObjectPattern(), false, false, param->TypeAnnotation(), nullptr);
356         destructuringContext.Start();
357         patternVar->SetTsType(destructuringContext.InferedType());
358         return {patternVar->AsLocalVariable(), nullptr, false};
359     }
360 
361     patternVar->SetTsType(param->CheckPattern(this));
362     return {patternVar->AsLocalVariable(), nullptr, false};
363 }
364 
CheckFunctionParameter(const ir::Expression * param,SignatureInfo * signatureInfo)365 std::tuple<binder::LocalVariable *, binder::LocalVariable *, bool> Checker::CheckFunctionParameter(
366     const ir::Expression *param, SignatureInfo *signatureInfo)
367 {
368     auto found = nodeCache_.find(param);
369     if (found != nodeCache_.end()) {
370         ASSERT(found->second->Variable());
371         binder::Variable *var = found->second->Variable();
372         return {var->AsLocalVariable(), nullptr, var->HasFlag(binder::VariableFlags::OPTIONAL)};
373     }
374 
375     std::tuple<binder::LocalVariable *, binder::LocalVariable *, bool> result;
376     bool cache = true;
377 
378     switch (param->Type()) {
379         case ir::AstNodeType::IDENTIFIER: {
380             result = CheckFunctionIdentifierParameter(param->AsIdentifier());
381             break;
382         }
383         case ir::AstNodeType::ASSIGNMENT_PATTERN: {
384             result = CheckFunctionAssignmentPatternParameter(param->AsAssignmentPattern());
385             break;
386         }
387         case ir::AstNodeType::REST_ELEMENT: {
388             result = CheckFunctionRestParameter(param->AsRestElement(), signatureInfo);
389             cache = false;
390             break;
391         }
392         case ir::AstNodeType::ARRAY_PATTERN: {
393             result = CheckFunctionArrayPatternParameter(param->AsArrayPattern());
394             break;
395         }
396         case ir::AstNodeType::OBJECT_PATTERN: {
397             result = CheckFunctionObjectPatternParameter(param->AsObjectPattern());
398             break;
399         }
400         default: {
401             UNREACHABLE();
402         }
403     }
404 
405     if (cache) {
406         Type *placeholder = allocator_->New<ArrayType>(GlobalAnyType());
407         placeholder->SetVariable(std::get<0>(result));
408         nodeCache_.insert({param, placeholder});
409     }
410 
411     return result;
412 }
413 
CheckFunctionParameterDeclarations(const ArenaVector<ir::Expression * > & params,SignatureInfo * signatureInfo)414 void Checker::CheckFunctionParameterDeclarations(const ArenaVector<ir::Expression *> &params,
415                                                  SignatureInfo *signatureInfo)
416 {
417     signatureInfo->restVar = nullptr;
418     signatureInfo->minArgCount = 0;
419 
420     for (auto it = params.rbegin(); it != params.rend(); it++) {
421         auto [paramVar, restVar, isOptional] = CheckFunctionParameter(*it, signatureInfo);
422 
423         if (restVar) {
424             signatureInfo->restVar = restVar;
425             continue;
426         }
427 
428         if (!paramVar) {
429             continue;
430         }
431 
432         signatureInfo->params.insert(signatureInfo->params.begin(), paramVar);
433 
434         if (!isOptional) {
435             signatureInfo->minArgCount++;
436         }
437     }
438 }
439 
ShouldCreatePropertyValueName(const ir::Expression * propValue)440 bool ShouldCreatePropertyValueName(const ir::Expression *propValue)
441 {
442     return propValue->IsArrayPattern() || propValue->IsObjectPattern() ||
443            (propValue->IsAssignmentPattern() && (propValue->AsAssignmentPattern()->Left()->IsArrayPattern() ||
444                                                   propValue->AsAssignmentPattern()->Left()->IsObjectPattern()));
445 }
446 
CreatePatternParameterName(const ir::AstNode * node,std::stringstream & ss)447 void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstream &ss)
448 {
449     switch (node->Type()) {
450         case ir::AstNodeType::IDENTIFIER: {
451             ss << node->AsIdentifier()->Name();
452             break;
453         }
454         case ir::AstNodeType::ARRAY_PATTERN: {
455             ss << "[";
456 
457             const auto &elements = node->AsArrayPattern()->Elements();
458             for (auto it = elements.begin(); it != elements.end(); it++) {
459                 CreatePatternParameterName(*it, ss);
460                 if (std::next(it) != elements.end()) {
461                     ss << ", ";
462                 }
463             }
464 
465             ss << "]";
466             break;
467         }
468         case ir::AstNodeType::OBJECT_PATTERN: {
469             ss << "{ ";
470 
471             const auto &properties = node->AsObjectPattern()->Properties();
472             for (auto it = properties.begin(); it != properties.end(); it++) {
473                 CreatePatternParameterName(*it, ss);
474                 if (std::next(it) != properties.end()) {
475                     ss << ", ";
476                 }
477             }
478 
479             ss << " }";
480             break;
481         }
482         case ir::AstNodeType::ASSIGNMENT_PATTERN: {
483             CreatePatternParameterName(node->AsAssignmentPattern()->Left(), ss);
484             break;
485         }
486         case ir::AstNodeType::PROPERTY: {
487             const ir::Property *prop = node->AsProperty();
488             util::StringView propName;
489 
490             if (prop->Key()->IsIdentifier()) {
491                 propName = prop->Key()->AsIdentifier()->Name();
492             } else {
493                 switch (prop->Key()->Type()) {
494                     case ir::AstNodeType::NUMBER_LITERAL: {
495                         propName = util::Helpers::ToStringView(allocator_, prop->Key()->AsNumberLiteral()->Number());
496                         break;
497                     }
498                     case ir::AstNodeType::BIGINT_LITERAL: {
499                         propName = prop->Key()->AsBigIntLiteral()->Str();
500                         break;
501                     }
502                     case ir::AstNodeType::STRING_LITERAL: {
503                         propName = prop->Key()->AsStringLiteral()->Str();
504                         break;
505                     }
506                     default: {
507                         UNREACHABLE();
508                         break;
509                     }
510                 }
511             }
512 
513             ss << propName;
514 
515             if (ShouldCreatePropertyValueName(prop->Value())) {
516                 ss << ": ";
517                 Checker::CreatePatternParameterName(prop->Value(), ss);
518             }
519 
520             break;
521         }
522         case ir::AstNodeType::REST_ELEMENT: {
523             ss << "...";
524             Checker::CreatePatternParameterName(node->AsRestElement()->Argument(), ss);
525             break;
526         }
527         default:
528             break;
529     }
530 }
531 
FindSubsequentFunctionNode(const ir::BlockStatement * block,const ir::ScriptFunction * node)532 const ir::Statement *FindSubsequentFunctionNode(const ir::BlockStatement *block, const ir::ScriptFunction *node)
533 {
534     for (auto it = block->Statements().begin(); it != block->Statements().end(); it++) {
535         if ((*it)->IsFunctionDeclaration() && (*it)->AsFunctionDeclaration()->Function() == node) {
536             return *(++it);
537         }
538     }
539 
540     UNREACHABLE();
541     return nullptr;
542 }
543 
InferFunctionDeclarationType(const binder::FunctionDecl * decl,binder::Variable * funcVar)544 void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, binder::Variable *funcVar)
545 {
546     const ir::ScriptFunction *bodyDeclaration = decl->Decls().back();
547 
548     if (bodyDeclaration->IsOverload()) {
549         ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
550                        bodyDeclaration->Id()->Start());
551     }
552 
553     ObjectDescriptor *descWithOverload = allocator_->New<ObjectDescriptor>(allocator_);
554 
555     for (auto it = decl->Decls().begin(); it != decl->Decls().end() - 1; it++) {
556         const ir::ScriptFunction *func = *it;
557         ASSERT(func->IsOverload() && (*it)->Parent()->Parent()->IsBlockStatement());
558         const ir::Statement *subsequentNode =
559             FindSubsequentFunctionNode((*it)->Parent()->Parent()->AsBlockStatement(), func);
560         ASSERT(subsequentNode);
561 
562         if (!subsequentNode->IsFunctionDeclaration()) {
563             ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
564                            func->Id()->Start());
565         }
566 
567         const ir::ScriptFunction *subsequentFunc = subsequentNode->AsFunctionDeclaration()->Function();
568 
569         if (subsequentFunc->Id()->Name() != func->Id()->Name()) {
570             ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
571                            func->Id()->Start());
572         }
573 
574         if (subsequentFunc->Declare() != func->Declare()) {
575             ThrowTypeError("Overload signatures must all be ambient or non-ambient.", func->Id()->Start());
576         }
577 
578         ScopeContext scopeCtx(this, func->Scope());
579 
580         auto *overloadSignatureInfo = allocator_->New<checker::SignatureInfo>(allocator_);
581         CheckFunctionParameterDeclarations(func->Params(), overloadSignatureInfo);
582 
583         Type *returnType = GlobalAnyType();
584 
585         if (func->ReturnTypeAnnotation()) {
586             func->ReturnTypeAnnotation()->Check(this);
587             returnType = func->ReturnTypeAnnotation()->AsTypeNode()->GetType(this);
588         }
589 
590         Signature *overloadSignature = allocator_->New<checker::Signature>(overloadSignatureInfo, returnType);
591         overloadSignature->SetNode(func);
592         descWithOverload->callSignatures.push_back(overloadSignature);
593     }
594 
595     ScopeContext scopeCtx(this, bodyDeclaration->Scope());
596 
597     auto *signatureInfo = allocator_->New<checker::SignatureInfo>(allocator_);
598     CheckFunctionParameterDeclarations(bodyDeclaration->Params(), signatureInfo);
599     auto *bodyCallSignature = allocator_->New<checker::Signature>(signatureInfo, GlobalResolvingReturnType());
600 
601     if (descWithOverload->callSignatures.empty()) {
602         Type *funcType = CreateFunctionTypeWithSignature(bodyCallSignature);
603         funcType->SetVariable(funcVar);
604         funcVar->SetTsType(funcType);
605     }
606 
607     bodyCallSignature->SetReturnType(HandleFunctionReturn(bodyDeclaration));
608 
609     if (!descWithOverload->callSignatures.empty()) {
610         Type *funcType = allocator_->New<FunctionType>(descWithOverload);
611         funcType->SetVariable(funcVar);
612         funcVar->SetTsType(funcType);
613 
614         for (auto *iter : descWithOverload->callSignatures) {
615             if (bodyCallSignature->ReturnType()->IsVoidType() ||
616                 IsTypeAssignableTo(bodyCallSignature->ReturnType(), iter->ReturnType()) ||
617                 IsTypeAssignableTo(iter->ReturnType(), bodyCallSignature->ReturnType())) {
618                 bodyCallSignature->AssignmentTarget(relation_, iter);
619 
620                 if (relation_->IsTrue()) {
621                     continue;
622                 }
623             }
624 
625             ASSERT(iter->Node() && iter->Node()->IsScriptFunction());
626             ThrowTypeError("This overload signature is not compatible with its implementation signature",
627                            iter->Node()->AsScriptFunction()->Id()->Start());
628         }
629     }
630 }
631 
CollectTypesFromReturnStatements(const ir::AstNode * parent,ArenaVector<Type * > * returnTypes)632 void Checker::CollectTypesFromReturnStatements(const ir::AstNode *parent, ArenaVector<Type *> *returnTypes)
633 {
634     parent->Iterate([this, returnTypes](ir::AstNode *childNode) -> void {
635         if (childNode->IsScriptFunction()) {
636             return;
637         }
638 
639         if (childNode->IsReturnStatement()) {
640             ir::ReturnStatement *returnStmt = childNode->AsReturnStatement();
641 
642             if (!returnStmt->Argument()) {
643                 return;
644             }
645 
646             returnTypes->push_back(
647                 GetBaseTypeOfLiteralType(CheckTypeCached(childNode->AsReturnStatement()->Argument())));
648         }
649 
650         CollectTypesFromReturnStatements(childNode, returnTypes);
651     });
652 }
653 
SearchForReturnOrThrow(const ir::AstNode * parent)654 static bool SearchForReturnOrThrow(const ir::AstNode *parent)
655 {
656     bool found = false;
657 
658     parent->Iterate([&found](const ir::AstNode *childNode) -> void {
659         if (childNode->IsThrowStatement() || childNode->IsReturnStatement()) {
660             found = true;
661             return;
662         }
663 
664         if (childNode->IsScriptFunction()) {
665             return;
666         }
667 
668         SearchForReturnOrThrow(childNode);
669     });
670 
671     return found;
672 }
673 
CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFunction * func,lexer::SourcePosition lineInfo,const char * errMsg)674 void Checker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFunction *func,
675                                                               lexer::SourcePosition lineInfo, const char *errMsg)
676 {
677     if (!SearchForReturnOrThrow(func->Body())) {
678         ThrowTypeError(errMsg, lineInfo);
679     }
680     // TODO(aszilagyi): this function is not fully implement the TSC one, in the future if we will have a
681     // noImplicitReturn compiler option for TypeScript we should update this function
682 }
683 
GetArgRange(const ArenaVector<Signature * > & signatures,ArenaVector<Signature * > * potentialSignatures,uint32_t callArgsSize,bool * haveSignatureWithRest)684 ArgRange Checker::GetArgRange(const ArenaVector<Signature *> &signatures, ArenaVector<Signature *> *potentialSignatures,
685                               uint32_t callArgsSize, bool *haveSignatureWithRest)
686 {
687     uint32_t minArg = UINT32_MAX;
688     uint32_t maxArg = 0;
689 
690     for (auto *it : signatures) {
691         if (it->RestVar()) {
692             *haveSignatureWithRest = true;
693         }
694 
695         if (it->MinArgCount() < minArg) {
696             minArg = it->MinArgCount();
697         }
698 
699         if (it->Params().size() > maxArg) {
700             maxArg = it->Params().size();
701         }
702 
703         if (callArgsSize >= it->MinArgCount() && (callArgsSize <= it->Params().size() || it->RestVar())) {
704             potentialSignatures->push_back(it);
705         }
706     }
707 
708     return {minArg, maxArg};
709 }
710 
CallMatchesSignature(const ArenaVector<ir::Expression * > & args,Signature * signature,bool throwError)711 bool Checker::CallMatchesSignature(const ArenaVector<ir::Expression *> &args, Signature *signature, bool throwError)
712 {
713     for (size_t index = 0; index < args.size(); index++) {
714         checker::Type *sigArgType = nullptr;
715         bool validateRestArg = false;
716 
717         if (index >= signature->Params().size()) {
718             ASSERT(signature->RestVar());
719             validateRestArg = true;
720             sigArgType = signature->RestVar()->TsType();
721         } else {
722             sigArgType = signature->Params()[index]->TsType();
723         }
724 
725         if (validateRestArg || !throwError) {
726             checker::Type *callArgType = GetBaseTypeOfLiteralType(args[index]->Check(this));
727             if (!IsTypeAssignableTo(callArgType, sigArgType)) {
728                 if (throwError) {
729                     ThrowTypeError({"Argument of type '", callArgType, "' is not assignable to parameter of type '",
730                                     sigArgType, "'."},
731                                    args[index]->Start());
732                 }
733 
734                 return false;
735             }
736 
737             continue;
738         }
739 
740         ElaborateElementwise(sigArgType, args[index], args[index]->Start());
741     }
742 
743     return true;
744 }
745 
resolveCallOrNewExpression(const ArenaVector<Signature * > & signatures,ArenaVector<ir::Expression * > arguments,const lexer::SourcePosition & errPos)746 Type *Checker::resolveCallOrNewExpression(const ArenaVector<Signature *> &signatures,
747                                           ArenaVector<ir::Expression *> arguments, const lexer::SourcePosition &errPos)
748 {
749     if (signatures.empty()) {
750         ThrowTypeError("This expression is not callable.", errPos);
751     }
752 
753     ArenaVector<checker::Signature *> potentialSignatures(allocator_->Adapter());
754     bool haveSignatureWithRest = false;
755 
756     auto argRange = GetArgRange(signatures, &potentialSignatures, arguments.size(), &haveSignatureWithRest);
757 
758     if (potentialSignatures.empty()) {
759         if (haveSignatureWithRest) {
760             ThrowTypeError({"Expected at least ", argRange.first, " arguments, but got ", arguments.size(), "."},
761                            errPos);
762         }
763 
764         if (signatures.size() == 1 && argRange.first == argRange.second) {
765             lexer::SourcePosition loc =
766                 (argRange.first > arguments.size()) ? errPos : arguments[argRange.second]->Start();
767             ThrowTypeError({"Expected ", argRange.first, " arguments, but got ", arguments.size(), "."}, loc);
768         }
769 
770         ThrowTypeError({"Expected ", argRange.first, "-", argRange.second, " arguments, but got ", arguments.size()},
771                        errPos);
772     }
773 
774     checker::Type *returnType = nullptr;
775     for (auto *it : potentialSignatures) {
776         if (CallMatchesSignature(arguments, it, potentialSignatures.size() == 1)) {
777             returnType = it->ReturnType();
778             break;
779         }
780     }
781 
782     if (!returnType) {
783         ThrowTypeError("No overload matches this call.", errPos);
784     }
785 
786     return returnType;
787 }
788 
789 }  // namespace panda::es2panda::checker
790