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