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