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