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