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