1 /**
2  * Copyright (c) 2021-2024 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 ark::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 = ArrayDestructuringContext(
233             {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(
240             {this, objectPattern, false, true, objectPattern->TypeAnnotation(), 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 = ObjectDestructuringContext(
338             {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     std::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> result;
352     if (param->TsType() != nullptr) {
353         ASSERT(param->TsType()->Variable());
354         varbinder::Variable *var = param->TsType()->Variable();
355         result = {var->AsLocalVariable(), nullptr, var->HasFlag(varbinder::VariableFlags::OPTIONAL)};
356         return result;
357     }
358 
359     bool cache = true;
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 
HandlePropertyPatternParameterName(ir::Property *prop, std::stringstream &ss)429 void TSChecker::HandlePropertyPatternParameterName(ir::Property *prop, std::stringstream &ss)
430 {
431     util::StringView propName;
432     if (prop->Key()->IsIdentifier()) {
433         propName = prop->Key()->AsIdentifier()->Name();
434     } else {
435         switch (prop->Key()->Type()) {
436             case ir::AstNodeType::NUMBER_LITERAL: {
437                 propName =
438                     util::Helpers::ToStringView(Allocator(), prop->Key()->AsNumberLiteral()->Number().GetDouble());
439                 break;
440             }
441             case ir::AstNodeType::BIGINT_LITERAL: {
442                 propName = prop->Key()->AsBigIntLiteral()->Str();
443                 break;
444             }
445             case ir::AstNodeType::STRING_LITERAL: {
446                 propName = prop->Key()->AsStringLiteral()->Str();
447                 break;
448             }
449             default: {
450                 UNREACHABLE();
451                 break;
452             }
453         }
454     }
455 
456     ss << propName;
457 
458     if (ShouldCreatePropertyValueName(prop->Value())) {
459         ss << ": ";
460         TSChecker::CreatePatternParameterName(prop->Value(), ss);
461     }
462 }
463 
CreatePatternParameterName(ir::AstNode *node, std::stringstream &ss)464 void TSChecker::CreatePatternParameterName(ir::AstNode *node, std::stringstream &ss)
465 {
466     switch (node->Type()) {
467         case ir::AstNodeType::IDENTIFIER: {
468             ss << node->AsIdentifier()->Name();
469             break;
470         }
471         case ir::AstNodeType::ARRAY_PATTERN: {
472             ss << "[";
473 
474             const auto &elements = node->AsArrayPattern()->Elements();
475             for (auto it = elements.begin(); it != elements.end(); it++) {
476                 CreatePatternParameterName(*it, ss);
477                 if (std::next(it) != elements.end()) {
478                     ss << ", ";
479                 }
480             }
481 
482             ss << "]";
483             break;
484         }
485         case ir::AstNodeType::OBJECT_PATTERN: {
486             ss << "{ ";
487 
488             const auto &properties = node->AsObjectPattern()->Properties();
489             for (auto it = properties.begin(); it != properties.end(); it++) {
490                 CreatePatternParameterName(*it, ss);
491                 if (std::next(it) != properties.end()) {
492                     ss << ", ";
493                 }
494             }
495 
496             ss << " }";
497             break;
498         }
499         case ir::AstNodeType::ASSIGNMENT_PATTERN: {
500             CreatePatternParameterName(node->AsAssignmentPattern()->Left(), ss);
501             break;
502         }
503         case ir::AstNodeType::PROPERTY: {
504             HandlePropertyPatternParameterName(node->AsProperty(), ss);
505             break;
506         }
507         case ir::AstNodeType::REST_ELEMENT: {
508             ss << "...";
509             TSChecker::CreatePatternParameterName(node->AsRestElement()->Argument(), ss);
510             break;
511         }
512         default:
513             break;
514     }
515 }
516 
FindSubsequentFunctionNode(ir::BlockStatement *block, ir::ScriptFunction *node)517 ir::Statement *FindSubsequentFunctionNode(ir::BlockStatement *block, ir::ScriptFunction *node)
518 {
519     for (auto it = block->Statements().begin(); it != block->Statements().end(); it++) {
520         if ((*it)->IsFunctionDeclaration() && (*it)->AsFunctionDeclaration()->Function() == node) {
521             return *(++it);
522         }
523     }
524 
525     UNREACHABLE();
526     return nullptr;
527 }
528 
ValidateSubsequentNode(const ir::Statement *const subsequentNode, const ir::ScriptFunction *const func)529 void TSChecker::ValidateSubsequentNode(const ir::Statement *const subsequentNode, const ir::ScriptFunction *const func)
530 {
531     if (!subsequentNode->IsFunctionDeclaration()) {
532         ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
533                        func->Id()->Start());
534     }
535 
536     const ir::ScriptFunction *const subsequentFunc = subsequentNode->AsFunctionDeclaration()->Function();
537     if (subsequentFunc->Id()->Name() != func->Id()->Name()) {
538         ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
539                        func->Id()->Start());
540     }
541 
542     if (subsequentFunc->Declare() != func->Declare()) {
543         ThrowTypeError("Overload signatures must all be ambient or non-ambient.", func->Id()->Start());
544     }
545 }
546 
CheckOverloadSignatureCompatibility(Signature *bodyCallSignature, Signature *signature)547 void TSChecker::CheckOverloadSignatureCompatibility(Signature *bodyCallSignature, Signature *signature)
548 {
549     if (bodyCallSignature->ReturnType()->IsVoidType() ||
550         IsTypeAssignableTo(bodyCallSignature->ReturnType(), signature->ReturnType()) ||
551         IsTypeAssignableTo(signature->ReturnType(), bodyCallSignature->ReturnType())) {
552         bodyCallSignature->AssignmentTarget(Relation(), signature);
553 
554         if (Relation()->IsTrue()) {
555             return;
556         }
557     }
558 
559     ASSERT(signature->Function());
560     ThrowTypeError("This overload signature is not compatible with its implementation signature",
561                    signature->Function()->Id()->Start());
562 }
563 
InferFunctionDeclarationType(const varbinder::FunctionDecl *decl, varbinder::Variable *funcVar)564 void TSChecker::InferFunctionDeclarationType(const varbinder::FunctionDecl *decl, varbinder::Variable *funcVar)
565 {
566     ir::ScriptFunction *bodyDeclaration = decl->Decls().back();
567     if (bodyDeclaration->IsOverload()) {
568         ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
569                        bodyDeclaration->Id()->Start());
570     }
571 
572     ObjectDescriptor *descWithOverload = Allocator()->New<ObjectDescriptor>(Allocator());
573     for (auto it = decl->Decls().begin(); it != decl->Decls().end() - 1; it++) {
574         ir::ScriptFunction *func = *it;
575         ASSERT(func->IsOverload() && (*it)->Parent()->Parent()->IsBlockStatement());
576         ir::Statement *subsequentNode = FindSubsequentFunctionNode((*it)->Parent()->Parent()->AsBlockStatement(), func);
577         ASSERT(subsequentNode);
578         ValidateSubsequentNode(subsequentNode, func);
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() != nullptr) {
588             func->ReturnTypeAnnotation()->Check(this);
589             returnType = func->ReturnTypeAnnotation()->GetType(this);
590         }
591 
592         Signature *overloadSignature = Allocator()->New<checker::Signature>(overloadSignatureInfo, returnType, func);
593         descWithOverload->callSignatures.push_back(overloadSignature);
594     }
595 
596     ScopeContext scopeCtx(this, bodyDeclaration->Scope());
597 
598     auto *signatureInfo = Allocator()->New<checker::SignatureInfo>(Allocator());
599     CheckFunctionParameterDeclarations(bodyDeclaration->Params(), signatureInfo);
600     auto *bodyCallSignature = Allocator()->New<checker::Signature>(signatureInfo, GlobalResolvingReturnType());
601 
602     if (descWithOverload->callSignatures.empty()) {
603         Type *funcType = CreateFunctionTypeWithSignature(bodyCallSignature);
604         funcType->SetVariable(funcVar);
605         funcVar->SetTsType(funcType);
606     }
607 
608     bodyCallSignature->SetReturnType(HandleFunctionReturn(bodyDeclaration));
609 
610     if (!descWithOverload->callSignatures.empty()) {
611         Type *funcType = Allocator()->New<FunctionType>(descWithOverload);
612         funcType->SetVariable(funcVar);
613         funcVar->SetTsType(funcType);
614 
615         for (auto *iter : descWithOverload->callSignatures) {
616             CheckOverloadSignatureCompatibility(bodyCallSignature, iter);
617         }
618     }
619 }
620 
CollectTypesFromReturnStatements(ir::AstNode *parent, ArenaVector<Type *> *returnTypes)621 void TSChecker::CollectTypesFromReturnStatements(ir::AstNode *parent, ArenaVector<Type *> *returnTypes)
622 {
623     parent->Iterate([this, returnTypes](ir::AstNode *childNode) -> void {
624         if (childNode->IsScriptFunction()) {
625             return;
626         }
627 
628         if (childNode->IsReturnStatement()) {
629             ir::ReturnStatement *returnStmt = childNode->AsReturnStatement();
630 
631             if (returnStmt->Argument() == nullptr) {
632                 return;
633             }
634 
635             returnTypes->push_back(
636                 GetBaseTypeOfLiteralType(CheckTypeCached(childNode->AsReturnStatement()->Argument())));
637         }
638 
639         CollectTypesFromReturnStatements(childNode, returnTypes);
640     });
641 }
642 
SearchForReturnOrThrow(ir::AstNode *parent)643 static bool SearchForReturnOrThrow(ir::AstNode *parent)
644 {
645     bool found = false;
646 
647     parent->Iterate([&found](ir::AstNode *childNode) -> void {
648         if (childNode->IsThrowStatement() || childNode->IsReturnStatement()) {
649             found = true;
650             return;
651         }
652 
653         if (childNode->IsScriptFunction()) {
654             return;
655         }
656 
657         SearchForReturnOrThrow(childNode);
658     });
659 
660     return found;
661 }
662 
CheckAllCodePathsInNonVoidFunctionReturnOrThrow(ir::ScriptFunction *func, lexer::SourcePosition lineInfo, const char *errMsg)663 void TSChecker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(ir::ScriptFunction *func,
664                                                                 lexer::SourcePosition lineInfo, const char *errMsg)
665 {
666     if (!SearchForReturnOrThrow(func->Body())) {
667         ThrowTypeError(errMsg, lineInfo);
668     }
669     // NOTE: aszilagyi. this function is not fully implement the TSC one, in the future if we will have a
670     // noImplicitReturn compiler option for TypeScript we should update this function
671 }
672 
GetArgRange(const ArenaVector<Signature *> &signatures, ArenaVector<Signature *> *potentialSignatures, uint32_t callArgsSize, bool *haveSignatureWithRest)673 ArgRange TSChecker::GetArgRange(const ArenaVector<Signature *> &signatures,
674                                 ArenaVector<Signature *> *potentialSignatures, uint32_t callArgsSize,
675                                 bool *haveSignatureWithRest)
676 {
677     uint32_t minArg = UINT32_MAX;
678     uint32_t maxArg = 0;
679 
680     for (auto *it : signatures) {
681         if (it->RestVar() != nullptr) {
682             *haveSignatureWithRest = true;
683         }
684 
685         if (it->MinArgCount() < minArg) {
686             minArg = it->MinArgCount();
687         }
688 
689         if (it->Params().size() > maxArg) {
690             maxArg = it->Params().size();
691         }
692 
693         if (callArgsSize >= it->MinArgCount() && (callArgsSize <= it->Params().size() || it->RestVar() != nullptr)) {
694             potentialSignatures->push_back(it);
695         }
696     }
697 
698     return {minArg, maxArg};
699 }
700 
CallMatchesSignature(const ArenaVector<ir::Expression *> &args, Signature *signature, bool throwError)701 bool TSChecker::CallMatchesSignature(const ArenaVector<ir::Expression *> &args, Signature *signature, bool throwError)
702 {
703     for (size_t index = 0; index < args.size(); index++) {
704         checker::Type *sigArgType = nullptr;
705         bool validateRestArg = false;
706 
707         if (index >= signature->Params().size()) {
708             ASSERT(signature->RestVar());
709             validateRestArg = true;
710             sigArgType = signature->RestVar()->TsType();
711         } else {
712             sigArgType = signature->Params()[index]->TsType();
713         }
714 
715         if (validateRestArg || !throwError) {
716             checker::Type *callArgType = GetBaseTypeOfLiteralType(args[index]->Check(this));
717             if (IsTypeAssignableTo(callArgType, sigArgType)) {
718                 continue;
719             }
720 
721             if (throwError) {
722                 ThrowTypeError(
723                     {"Argument of type '", callArgType, "' is not assignable to parameter of type '", sigArgType, "'."},
724                     args[index]->Start());
725             }
726             return false;
727         }
728 
729         ElaborateElementwise(sigArgType, args[index], args[index]->Start());
730     }
731 
732     return true;
733 }
734 
ResolveCallOrNewExpression(const ArenaVector<Signature *> &signatures, ArenaVector<ir::Expression *> arguments, const lexer::SourcePosition &errPos)735 Type *TSChecker::ResolveCallOrNewExpression(const ArenaVector<Signature *> &signatures,
736                                             ArenaVector<ir::Expression *> arguments,
737                                             const lexer::SourcePosition &errPos)
738 {
739     if (signatures.empty()) {
740         ThrowTypeError("This expression is not callable.", errPos);
741     }
742 
743     ArenaVector<checker::Signature *> potentialSignatures(Allocator()->Adapter());
744     bool haveSignatureWithRest = false;
745 
746     auto argRange = GetArgRange(signatures, &potentialSignatures, arguments.size(), &haveSignatureWithRest);
747 
748     if (potentialSignatures.empty()) {
749         if (haveSignatureWithRest) {
750             ThrowTypeError({"Expected at least ", argRange.first, " arguments, but got ", arguments.size(), "."},
751                            errPos);
752         }
753 
754         if (signatures.size() == 1 && argRange.first == argRange.second) {
755             lexer::SourcePosition loc =
756                 (argRange.first > arguments.size()) ? errPos : arguments[argRange.second]->Start();
757             ThrowTypeError({"Expected ", argRange.first, " arguments, but got ", arguments.size(), "."}, loc);
758         }
759 
760         ThrowTypeError({"Expected ", argRange.first, "-", argRange.second, " arguments, but got ", arguments.size()},
761                        errPos);
762     }
763 
764     checker::Type *returnType = nullptr;
765     for (auto *it : potentialSignatures) {
766         if (CallMatchesSignature(arguments, it, potentialSignatures.size() == 1)) {
767             returnType = it->ReturnType();
768             break;
769         }
770     }
771 
772     if (returnType == nullptr) {
773         ThrowTypeError("No overload matches this call.", errPos);
774     }
775 
776     return returnType;
777 }
778 }  // namespace ark::es2panda::checker
779