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 if (!restType->IsArrayType()) {
284 // TODO(aszilagyi): handle tuple type for rest
285 ThrowTypeError("A rest parameter must be of an array type", param->Start());
286 }
287 }
288
289 switch (param->Argument()->Type()) {
290 case ir::AstNodeType::IDENTIFIER: {
291 const ir::Identifier *restIdent = param->Argument()->AsIdentifier();
292 ASSERT(restIdent->Variable());
293 restIdent->Variable()->SetTsType(restType->AsArrayType()->ElementType());
294 return {nullptr, restIdent->Variable()->AsLocalVariable(), false};
295 }
296 case ir::AstNodeType::OBJECT_PATTERN: {
297 ASSERT(param->Argument()->IsObjectPattern());
298 auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE);
299 auto destructuringContext =
300 ObjectDestructuringContext(this, param->Argument(), false, false, nullptr, nullptr);
301 destructuringContext.SetInferedType(restType);
302 destructuringContext.SetSignatureInfo(signatureInfo);
303 destructuringContext.Start();
304 return {nullptr, nullptr, false};
305 }
306 case ir::AstNodeType::ARRAY_PATTERN: {
307 auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE);
308 auto destructuringContext =
309 ArrayDestructuringContext(this, param->Argument(), false, false, nullptr, nullptr);
310 destructuringContext.SetInferedType(restType);
311 destructuringContext.SetSignatureInfo(signatureInfo);
312 destructuringContext.Start();
313 return {nullptr, nullptr, false};
314 }
315 default: {
316 UNREACHABLE();
317 }
318 }
319 }
320
CheckFunctionArrayPatternParameter(const ir::ArrayExpression * param)321 std::tuple<binder::LocalVariable *, binder::LocalVariable *, bool> Checker::CheckFunctionArrayPatternParameter(
322 const ir::ArrayExpression *param)
323 {
324 std::stringstream ss;
325 CreatePatternParameterName(param, ss);
326 util::UString pn(ss.str(), allocator_);
327 binder::LocalVariable *patternVar =
328 binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param);
329
330 if (param->TypeAnnotation()) {
331 auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE);
332 auto destructuringContext =
333 ArrayDestructuringContext(this, param->AsArrayPattern(), false, false, param->TypeAnnotation(), nullptr);
334 destructuringContext.Start();
335 patternVar->SetTsType(destructuringContext.InferedType());
336 return {patternVar->AsLocalVariable(), nullptr, false};
337 }
338
339 patternVar->SetTsType(param->CheckPattern(this));
340 return {patternVar->AsLocalVariable(), nullptr, false};
341 }
342
CheckFunctionObjectPatternParameter(const ir::ObjectExpression * param)343 std::tuple<binder::LocalVariable *, binder::LocalVariable *, bool> Checker::CheckFunctionObjectPatternParameter(
344 const ir::ObjectExpression *param)
345 {
346 std::stringstream ss;
347 CreatePatternParameterName(param, ss);
348 util::UString pn(ss.str(), allocator_);
349 binder::LocalVariable *patternVar =
350 binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param);
351
352 if (param->TypeAnnotation()) {
353 auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE);
354 auto destructuringContext =
355 ObjectDestructuringContext(this, param->AsObjectPattern(), false, false, param->TypeAnnotation(), nullptr);
356 destructuringContext.Start();
357 patternVar->SetTsType(destructuringContext.InferedType());
358 return {patternVar->AsLocalVariable(), nullptr, false};
359 }
360
361 patternVar->SetTsType(param->CheckPattern(this));
362 return {patternVar->AsLocalVariable(), nullptr, false};
363 }
364
CheckFunctionParameter(const ir::Expression * param,SignatureInfo * signatureInfo)365 std::tuple<binder::LocalVariable *, binder::LocalVariable *, bool> Checker::CheckFunctionParameter(
366 const ir::Expression *param, SignatureInfo *signatureInfo)
367 {
368 auto found = nodeCache_.find(param);
369 if (found != nodeCache_.end()) {
370 ASSERT(found->second->Variable());
371 binder::Variable *var = found->second->Variable();
372 return {var->AsLocalVariable(), nullptr, var->HasFlag(binder::VariableFlags::OPTIONAL)};
373 }
374
375 std::tuple<binder::LocalVariable *, binder::LocalVariable *, bool> result;
376 bool cache = true;
377
378 switch (param->Type()) {
379 case ir::AstNodeType::IDENTIFIER: {
380 result = CheckFunctionIdentifierParameter(param->AsIdentifier());
381 break;
382 }
383 case ir::AstNodeType::ASSIGNMENT_PATTERN: {
384 result = CheckFunctionAssignmentPatternParameter(param->AsAssignmentPattern());
385 break;
386 }
387 case ir::AstNodeType::REST_ELEMENT: {
388 result = CheckFunctionRestParameter(param->AsRestElement(), signatureInfo);
389 cache = false;
390 break;
391 }
392 case ir::AstNodeType::ARRAY_PATTERN: {
393 result = CheckFunctionArrayPatternParameter(param->AsArrayPattern());
394 break;
395 }
396 case ir::AstNodeType::OBJECT_PATTERN: {
397 result = CheckFunctionObjectPatternParameter(param->AsObjectPattern());
398 break;
399 }
400 default: {
401 UNREACHABLE();
402 }
403 }
404
405 if (cache) {
406 Type *placeholder = allocator_->New<ArrayType>(GlobalAnyType());
407 placeholder->SetVariable(std::get<0>(result));
408 nodeCache_.insert({param, placeholder});
409 }
410
411 return result;
412 }
413
CheckFunctionParameterDeclarations(const ArenaVector<ir::Expression * > & params,SignatureInfo * signatureInfo)414 void Checker::CheckFunctionParameterDeclarations(const ArenaVector<ir::Expression *> ¶ms,
415 SignatureInfo *signatureInfo)
416 {
417 signatureInfo->restVar = nullptr;
418 signatureInfo->minArgCount = 0;
419
420 for (auto it = params.rbegin(); it != params.rend(); it++) {
421 auto [paramVar, restVar, isOptional] = CheckFunctionParameter(*it, signatureInfo);
422
423 if (restVar) {
424 signatureInfo->restVar = restVar;
425 continue;
426 }
427
428 if (!paramVar) {
429 continue;
430 }
431
432 signatureInfo->params.insert(signatureInfo->params.begin(), paramVar);
433
434 if (!isOptional) {
435 signatureInfo->minArgCount++;
436 }
437 }
438 }
439
ShouldCreatePropertyValueName(const ir::Expression * propValue)440 bool ShouldCreatePropertyValueName(const ir::Expression *propValue)
441 {
442 return propValue->IsArrayPattern() || propValue->IsObjectPattern() ||
443 (propValue->IsAssignmentPattern() && (propValue->AsAssignmentPattern()->Left()->IsArrayPattern() ||
444 propValue->AsAssignmentPattern()->Left()->IsObjectPattern()));
445 }
446
CreatePatternParameterName(const ir::AstNode * node,std::stringstream & ss)447 void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstream &ss)
448 {
449 switch (node->Type()) {
450 case ir::AstNodeType::IDENTIFIER: {
451 ss << node->AsIdentifier()->Name();
452 break;
453 }
454 case ir::AstNodeType::ARRAY_PATTERN: {
455 ss << "[";
456
457 const auto &elements = node->AsArrayPattern()->Elements();
458 for (auto it = elements.begin(); it != elements.end(); it++) {
459 CreatePatternParameterName(*it, ss);
460 if (std::next(it) != elements.end()) {
461 ss << ", ";
462 }
463 }
464
465 ss << "]";
466 break;
467 }
468 case ir::AstNodeType::OBJECT_PATTERN: {
469 ss << "{ ";
470
471 const auto &properties = node->AsObjectPattern()->Properties();
472 for (auto it = properties.begin(); it != properties.end(); it++) {
473 CreatePatternParameterName(*it, ss);
474 if (std::next(it) != properties.end()) {
475 ss << ", ";
476 }
477 }
478
479 ss << " }";
480 break;
481 }
482 case ir::AstNodeType::ASSIGNMENT_PATTERN: {
483 CreatePatternParameterName(node->AsAssignmentPattern()->Left(), ss);
484 break;
485 }
486 case ir::AstNodeType::PROPERTY: {
487 const ir::Property *prop = node->AsProperty();
488 util::StringView propName;
489
490 if (prop->Key()->IsIdentifier()) {
491 propName = prop->Key()->AsIdentifier()->Name();
492 } else {
493 switch (prop->Key()->Type()) {
494 case ir::AstNodeType::NUMBER_LITERAL: {
495 propName = util::Helpers::ToStringView(allocator_, prop->Key()->AsNumberLiteral()->Number());
496 break;
497 }
498 case ir::AstNodeType::BIGINT_LITERAL: {
499 propName = prop->Key()->AsBigIntLiteral()->Str();
500 break;
501 }
502 case ir::AstNodeType::STRING_LITERAL: {
503 propName = prop->Key()->AsStringLiteral()->Str();
504 break;
505 }
506 default: {
507 UNREACHABLE();
508 break;
509 }
510 }
511 }
512
513 ss << propName;
514
515 if (ShouldCreatePropertyValueName(prop->Value())) {
516 ss << ": ";
517 Checker::CreatePatternParameterName(prop->Value(), ss);
518 }
519
520 break;
521 }
522 case ir::AstNodeType::REST_ELEMENT: {
523 ss << "...";
524 Checker::CreatePatternParameterName(node->AsRestElement()->Argument(), ss);
525 break;
526 }
527 default:
528 break;
529 }
530 }
531
FindSubsequentFunctionNode(const ir::BlockStatement * block,const ir::ScriptFunction * node)532 const ir::Statement *FindSubsequentFunctionNode(const ir::BlockStatement *block, const ir::ScriptFunction *node)
533 {
534 for (auto it = block->Statements().begin(); it != block->Statements().end(); it++) {
535 if ((*it)->IsFunctionDeclaration() && (*it)->AsFunctionDeclaration()->Function() == node) {
536 return *(++it);
537 }
538 }
539
540 UNREACHABLE();
541 return nullptr;
542 }
543
InferFunctionDeclarationType(const binder::FunctionDecl * decl,binder::Variable * funcVar)544 void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, binder::Variable *funcVar)
545 {
546 const ir::ScriptFunction *bodyDeclaration = decl->Decls().back();
547
548 if (bodyDeclaration->IsOverload()) {
549 ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
550 bodyDeclaration->Id()->Start());
551 }
552
553 ObjectDescriptor *descWithOverload = allocator_->New<ObjectDescriptor>(allocator_);
554
555 for (auto it = decl->Decls().begin(); it != decl->Decls().end() - 1; it++) {
556 const ir::ScriptFunction *func = *it;
557 ASSERT(func->IsOverload() && (*it)->Parent()->Parent()->IsBlockStatement());
558 const ir::Statement *subsequentNode =
559 FindSubsequentFunctionNode((*it)->Parent()->Parent()->AsBlockStatement(), func);
560 ASSERT(subsequentNode);
561
562 if (!subsequentNode->IsFunctionDeclaration()) {
563 ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
564 func->Id()->Start());
565 }
566
567 const ir::ScriptFunction *subsequentFunc = subsequentNode->AsFunctionDeclaration()->Function();
568
569 if (subsequentFunc->Id()->Name() != func->Id()->Name()) {
570 ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
571 func->Id()->Start());
572 }
573
574 if (subsequentFunc->Declare() != func->Declare()) {
575 ThrowTypeError("Overload signatures must all be ambient or non-ambient.", func->Id()->Start());
576 }
577
578 ScopeContext scopeCtx(this, func->Scope());
579
580 auto *overloadSignatureInfo = allocator_->New<checker::SignatureInfo>(allocator_);
581 CheckFunctionParameterDeclarations(func->Params(), overloadSignatureInfo);
582
583 Type *returnType = GlobalAnyType();
584
585 if (func->ReturnTypeAnnotation()) {
586 func->ReturnTypeAnnotation()->Check(this);
587 returnType = func->ReturnTypeAnnotation()->AsTypeNode()->GetType(this);
588 }
589
590 Signature *overloadSignature = allocator_->New<checker::Signature>(overloadSignatureInfo, returnType);
591 overloadSignature->SetNode(func);
592 descWithOverload->callSignatures.push_back(overloadSignature);
593 }
594
595 ScopeContext scopeCtx(this, bodyDeclaration->Scope());
596
597 auto *signatureInfo = allocator_->New<checker::SignatureInfo>(allocator_);
598 CheckFunctionParameterDeclarations(bodyDeclaration->Params(), signatureInfo);
599 auto *bodyCallSignature = allocator_->New<checker::Signature>(signatureInfo, GlobalResolvingReturnType());
600
601 if (descWithOverload->callSignatures.empty()) {
602 Type *funcType = CreateFunctionTypeWithSignature(bodyCallSignature);
603 funcType->SetVariable(funcVar);
604 funcVar->SetTsType(funcType);
605 }
606
607 bodyCallSignature->SetReturnType(HandleFunctionReturn(bodyDeclaration));
608
609 if (!descWithOverload->callSignatures.empty()) {
610 Type *funcType = allocator_->New<FunctionType>(descWithOverload);
611 funcType->SetVariable(funcVar);
612 funcVar->SetTsType(funcType);
613
614 for (auto *iter : descWithOverload->callSignatures) {
615 if (bodyCallSignature->ReturnType()->IsVoidType() ||
616 IsTypeAssignableTo(bodyCallSignature->ReturnType(), iter->ReturnType()) ||
617 IsTypeAssignableTo(iter->ReturnType(), bodyCallSignature->ReturnType())) {
618 bodyCallSignature->AssignmentTarget(relation_, iter);
619
620 if (relation_->IsTrue()) {
621 continue;
622 }
623 }
624
625 ASSERT(iter->Node() && iter->Node()->IsScriptFunction());
626 ThrowTypeError("This overload signature is not compatible with its implementation signature",
627 iter->Node()->AsScriptFunction()->Id()->Start());
628 }
629 }
630 }
631
CollectTypesFromReturnStatements(const ir::AstNode * parent,ArenaVector<Type * > * returnTypes)632 void Checker::CollectTypesFromReturnStatements(const ir::AstNode *parent, ArenaVector<Type *> *returnTypes)
633 {
634 parent->Iterate([this, returnTypes](ir::AstNode *childNode) -> void {
635 if (childNode->IsScriptFunction()) {
636 return;
637 }
638
639 if (childNode->IsReturnStatement()) {
640 ir::ReturnStatement *returnStmt = childNode->AsReturnStatement();
641
642 if (!returnStmt->Argument()) {
643 return;
644 }
645
646 returnTypes->push_back(
647 GetBaseTypeOfLiteralType(CheckTypeCached(childNode->AsReturnStatement()->Argument())));
648 }
649
650 CollectTypesFromReturnStatements(childNode, returnTypes);
651 });
652 }
653
SearchForReturnOrThrow(const ir::AstNode * parent)654 static bool SearchForReturnOrThrow(const ir::AstNode *parent)
655 {
656 bool found = false;
657
658 parent->Iterate([&found](const ir::AstNode *childNode) -> void {
659 if (childNode->IsThrowStatement() || childNode->IsReturnStatement()) {
660 found = true;
661 return;
662 }
663
664 if (childNode->IsScriptFunction()) {
665 return;
666 }
667
668 SearchForReturnOrThrow(childNode);
669 });
670
671 return found;
672 }
673
CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFunction * func,lexer::SourcePosition lineInfo,const char * errMsg)674 void Checker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFunction *func,
675 lexer::SourcePosition lineInfo, const char *errMsg)
676 {
677 if (!SearchForReturnOrThrow(func->Body())) {
678 ThrowTypeError(errMsg, lineInfo);
679 }
680 // TODO(aszilagyi): this function is not fully implement the TSC one, in the future if we will have a
681 // noImplicitReturn compiler option for TypeScript we should update this function
682 }
683
GetArgRange(const ArenaVector<Signature * > & signatures,ArenaVector<Signature * > * potentialSignatures,uint32_t callArgsSize,bool * haveSignatureWithRest)684 ArgRange Checker::GetArgRange(const ArenaVector<Signature *> &signatures, ArenaVector<Signature *> *potentialSignatures,
685 uint32_t callArgsSize, bool *haveSignatureWithRest)
686 {
687 uint32_t minArg = UINT32_MAX;
688 uint32_t maxArg = 0;
689
690 for (auto *it : signatures) {
691 if (it->RestVar()) {
692 *haveSignatureWithRest = true;
693 }
694
695 if (it->MinArgCount() < minArg) {
696 minArg = it->MinArgCount();
697 }
698
699 if (it->Params().size() > maxArg) {
700 maxArg = it->Params().size();
701 }
702
703 if (callArgsSize >= it->MinArgCount() && (callArgsSize <= it->Params().size() || it->RestVar())) {
704 potentialSignatures->push_back(it);
705 }
706 }
707
708 return {minArg, maxArg};
709 }
710
CallMatchesSignature(const ArenaVector<ir::Expression * > & args,Signature * signature,bool throwError)711 bool Checker::CallMatchesSignature(const ArenaVector<ir::Expression *> &args, Signature *signature, bool throwError)
712 {
713 for (size_t index = 0; index < args.size(); index++) {
714 checker::Type *sigArgType = nullptr;
715 bool validateRestArg = false;
716
717 if (index >= signature->Params().size()) {
718 ASSERT(signature->RestVar());
719 validateRestArg = true;
720 sigArgType = signature->RestVar()->TsType();
721 } else {
722 sigArgType = signature->Params()[index]->TsType();
723 }
724
725 if (validateRestArg || !throwError) {
726 checker::Type *callArgType = GetBaseTypeOfLiteralType(args[index]->Check(this));
727 if (!IsTypeAssignableTo(callArgType, sigArgType)) {
728 if (throwError) {
729 ThrowTypeError({"Argument of type '", callArgType, "' is not assignable to parameter of type '",
730 sigArgType, "'."},
731 args[index]->Start());
732 }
733
734 return false;
735 }
736
737 continue;
738 }
739
740 ElaborateElementwise(sigArgType, args[index], args[index]->Start());
741 }
742
743 return true;
744 }
745
resolveCallOrNewExpression(const ArenaVector<Signature * > & signatures,ArenaVector<ir::Expression * > arguments,const lexer::SourcePosition & errPos)746 Type *Checker::resolveCallOrNewExpression(const ArenaVector<Signature *> &signatures,
747 ArenaVector<ir::Expression *> arguments, const lexer::SourcePosition &errPos)
748 {
749 if (signatures.empty()) {
750 ThrowTypeError("This expression is not callable.", errPos);
751 }
752
753 ArenaVector<checker::Signature *> potentialSignatures(allocator_->Adapter());
754 bool haveSignatureWithRest = false;
755
756 auto argRange = GetArgRange(signatures, &potentialSignatures, arguments.size(), &haveSignatureWithRest);
757
758 if (potentialSignatures.empty()) {
759 if (haveSignatureWithRest) {
760 ThrowTypeError({"Expected at least ", argRange.first, " arguments, but got ", arguments.size(), "."},
761 errPos);
762 }
763
764 if (signatures.size() == 1 && argRange.first == argRange.second) {
765 lexer::SourcePosition loc =
766 (argRange.first > arguments.size()) ? errPos : arguments[argRange.second]->Start();
767 ThrowTypeError({"Expected ", argRange.first, " arguments, but got ", arguments.size(), "."}, loc);
768 }
769
770 ThrowTypeError({"Expected ", argRange.first, "-", argRange.second, " arguments, but got ", arguments.size()},
771 errPos);
772 }
773
774 checker::Type *returnType = nullptr;
775 for (auto *it : potentialSignatures) {
776 if (CallMatchesSignature(arguments, it, potentialSignatures.size() == 1)) {
777 returnType = it->ReturnType();
778 break;
779 }
780 }
781
782 if (!returnType) {
783 ThrowTypeError("No overload matches this call.", errPos);
784 }
785
786 return returnType;
787 }
788
789 } // namespace panda::es2panda::checker
790