1 /**
2 * Copyright (c) 2021-2024 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 ark::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 = ArrayDestructuringContext(
233 {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(
240 {this, objectPattern, false, true, objectPattern->TypeAnnotation(), 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 = ObjectDestructuringContext(
338 {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 std::tuple<varbinder::LocalVariable *, varbinder::LocalVariable *, bool> result;
352 if (param->TsType() != nullptr) {
353 ASSERT(param->TsType()->Variable());
354 varbinder::Variable *var = param->TsType()->Variable();
355 result = {var->AsLocalVariable(), nullptr, var->HasFlag(varbinder::VariableFlags::OPTIONAL)};
356 return result;
357 }
358
359 bool cache = true;
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 *> ¶ms, 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
HandlePropertyPatternParameterName(ir::Property *prop, std::stringstream &ss)429 void TSChecker::HandlePropertyPatternParameterName(ir::Property *prop, std::stringstream &ss)
430 {
431 util::StringView propName;
432 if (prop->Key()->IsIdentifier()) {
433 propName = prop->Key()->AsIdentifier()->Name();
434 } else {
435 switch (prop->Key()->Type()) {
436 case ir::AstNodeType::NUMBER_LITERAL: {
437 propName =
438 util::Helpers::ToStringView(Allocator(), prop->Key()->AsNumberLiteral()->Number().GetDouble());
439 break;
440 }
441 case ir::AstNodeType::BIGINT_LITERAL: {
442 propName = prop->Key()->AsBigIntLiteral()->Str();
443 break;
444 }
445 case ir::AstNodeType::STRING_LITERAL: {
446 propName = prop->Key()->AsStringLiteral()->Str();
447 break;
448 }
449 default: {
450 UNREACHABLE();
451 break;
452 }
453 }
454 }
455
456 ss << propName;
457
458 if (ShouldCreatePropertyValueName(prop->Value())) {
459 ss << ": ";
460 TSChecker::CreatePatternParameterName(prop->Value(), ss);
461 }
462 }
463
CreatePatternParameterName(ir::AstNode *node, std::stringstream &ss)464 void TSChecker::CreatePatternParameterName(ir::AstNode *node, std::stringstream &ss)
465 {
466 switch (node->Type()) {
467 case ir::AstNodeType::IDENTIFIER: {
468 ss << node->AsIdentifier()->Name();
469 break;
470 }
471 case ir::AstNodeType::ARRAY_PATTERN: {
472 ss << "[";
473
474 const auto &elements = node->AsArrayPattern()->Elements();
475 for (auto it = elements.begin(); it != elements.end(); it++) {
476 CreatePatternParameterName(*it, ss);
477 if (std::next(it) != elements.end()) {
478 ss << ", ";
479 }
480 }
481
482 ss << "]";
483 break;
484 }
485 case ir::AstNodeType::OBJECT_PATTERN: {
486 ss << "{ ";
487
488 const auto &properties = node->AsObjectPattern()->Properties();
489 for (auto it = properties.begin(); it != properties.end(); it++) {
490 CreatePatternParameterName(*it, ss);
491 if (std::next(it) != properties.end()) {
492 ss << ", ";
493 }
494 }
495
496 ss << " }";
497 break;
498 }
499 case ir::AstNodeType::ASSIGNMENT_PATTERN: {
500 CreatePatternParameterName(node->AsAssignmentPattern()->Left(), ss);
501 break;
502 }
503 case ir::AstNodeType::PROPERTY: {
504 HandlePropertyPatternParameterName(node->AsProperty(), ss);
505 break;
506 }
507 case ir::AstNodeType::REST_ELEMENT: {
508 ss << "...";
509 TSChecker::CreatePatternParameterName(node->AsRestElement()->Argument(), ss);
510 break;
511 }
512 default:
513 break;
514 }
515 }
516
FindSubsequentFunctionNode(ir::BlockStatement *block, ir::ScriptFunction *node)517 ir::Statement *FindSubsequentFunctionNode(ir::BlockStatement *block, ir::ScriptFunction *node)
518 {
519 for (auto it = block->Statements().begin(); it != block->Statements().end(); it++) {
520 if ((*it)->IsFunctionDeclaration() && (*it)->AsFunctionDeclaration()->Function() == node) {
521 return *(++it);
522 }
523 }
524
525 UNREACHABLE();
526 return nullptr;
527 }
528
ValidateSubsequentNode(const ir::Statement *const subsequentNode, const ir::ScriptFunction *const func)529 void TSChecker::ValidateSubsequentNode(const ir::Statement *const subsequentNode, const ir::ScriptFunction *const func)
530 {
531 if (!subsequentNode->IsFunctionDeclaration()) {
532 ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
533 func->Id()->Start());
534 }
535
536 const ir::ScriptFunction *const subsequentFunc = subsequentNode->AsFunctionDeclaration()->Function();
537 if (subsequentFunc->Id()->Name() != func->Id()->Name()) {
538 ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
539 func->Id()->Start());
540 }
541
542 if (subsequentFunc->Declare() != func->Declare()) {
543 ThrowTypeError("Overload signatures must all be ambient or non-ambient.", func->Id()->Start());
544 }
545 }
546
CheckOverloadSignatureCompatibility(Signature *bodyCallSignature, Signature *signature)547 void TSChecker::CheckOverloadSignatureCompatibility(Signature *bodyCallSignature, Signature *signature)
548 {
549 if (bodyCallSignature->ReturnType()->IsVoidType() ||
550 IsTypeAssignableTo(bodyCallSignature->ReturnType(), signature->ReturnType()) ||
551 IsTypeAssignableTo(signature->ReturnType(), bodyCallSignature->ReturnType())) {
552 bodyCallSignature->AssignmentTarget(Relation(), signature);
553
554 if (Relation()->IsTrue()) {
555 return;
556 }
557 }
558
559 ASSERT(signature->Function());
560 ThrowTypeError("This overload signature is not compatible with its implementation signature",
561 signature->Function()->Id()->Start());
562 }
563
InferFunctionDeclarationType(const varbinder::FunctionDecl *decl, varbinder::Variable *funcVar)564 void TSChecker::InferFunctionDeclarationType(const varbinder::FunctionDecl *decl, varbinder::Variable *funcVar)
565 {
566 ir::ScriptFunction *bodyDeclaration = decl->Decls().back();
567 if (bodyDeclaration->IsOverload()) {
568 ThrowTypeError("Function implementation is missing or not immediately following the declaration.",
569 bodyDeclaration->Id()->Start());
570 }
571
572 ObjectDescriptor *descWithOverload = Allocator()->New<ObjectDescriptor>(Allocator());
573 for (auto it = decl->Decls().begin(); it != decl->Decls().end() - 1; it++) {
574 ir::ScriptFunction *func = *it;
575 ASSERT(func->IsOverload() && (*it)->Parent()->Parent()->IsBlockStatement());
576 ir::Statement *subsequentNode = FindSubsequentFunctionNode((*it)->Parent()->Parent()->AsBlockStatement(), func);
577 ASSERT(subsequentNode);
578 ValidateSubsequentNode(subsequentNode, func);
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() != nullptr) {
588 func->ReturnTypeAnnotation()->Check(this);
589 returnType = func->ReturnTypeAnnotation()->GetType(this);
590 }
591
592 Signature *overloadSignature = Allocator()->New<checker::Signature>(overloadSignatureInfo, returnType, func);
593 descWithOverload->callSignatures.push_back(overloadSignature);
594 }
595
596 ScopeContext scopeCtx(this, bodyDeclaration->Scope());
597
598 auto *signatureInfo = Allocator()->New<checker::SignatureInfo>(Allocator());
599 CheckFunctionParameterDeclarations(bodyDeclaration->Params(), signatureInfo);
600 auto *bodyCallSignature = Allocator()->New<checker::Signature>(signatureInfo, GlobalResolvingReturnType());
601
602 if (descWithOverload->callSignatures.empty()) {
603 Type *funcType = CreateFunctionTypeWithSignature(bodyCallSignature);
604 funcType->SetVariable(funcVar);
605 funcVar->SetTsType(funcType);
606 }
607
608 bodyCallSignature->SetReturnType(HandleFunctionReturn(bodyDeclaration));
609
610 if (!descWithOverload->callSignatures.empty()) {
611 Type *funcType = Allocator()->New<FunctionType>(descWithOverload);
612 funcType->SetVariable(funcVar);
613 funcVar->SetTsType(funcType);
614
615 for (auto *iter : descWithOverload->callSignatures) {
616 CheckOverloadSignatureCompatibility(bodyCallSignature, iter);
617 }
618 }
619 }
620
CollectTypesFromReturnStatements(ir::AstNode *parent, ArenaVector<Type *> *returnTypes)621 void TSChecker::CollectTypesFromReturnStatements(ir::AstNode *parent, ArenaVector<Type *> *returnTypes)
622 {
623 parent->Iterate([this, returnTypes](ir::AstNode *childNode) -> void {
624 if (childNode->IsScriptFunction()) {
625 return;
626 }
627
628 if (childNode->IsReturnStatement()) {
629 ir::ReturnStatement *returnStmt = childNode->AsReturnStatement();
630
631 if (returnStmt->Argument() == nullptr) {
632 return;
633 }
634
635 returnTypes->push_back(
636 GetBaseTypeOfLiteralType(CheckTypeCached(childNode->AsReturnStatement()->Argument())));
637 }
638
639 CollectTypesFromReturnStatements(childNode, returnTypes);
640 });
641 }
642
SearchForReturnOrThrow(ir::AstNode *parent)643 static bool SearchForReturnOrThrow(ir::AstNode *parent)
644 {
645 bool found = false;
646
647 parent->Iterate([&found](ir::AstNode *childNode) -> void {
648 if (childNode->IsThrowStatement() || childNode->IsReturnStatement()) {
649 found = true;
650 return;
651 }
652
653 if (childNode->IsScriptFunction()) {
654 return;
655 }
656
657 SearchForReturnOrThrow(childNode);
658 });
659
660 return found;
661 }
662
CheckAllCodePathsInNonVoidFunctionReturnOrThrow(ir::ScriptFunction *func, lexer::SourcePosition lineInfo, const char *errMsg)663 void TSChecker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(ir::ScriptFunction *func,
664 lexer::SourcePosition lineInfo, const char *errMsg)
665 {
666 if (!SearchForReturnOrThrow(func->Body())) {
667 ThrowTypeError(errMsg, lineInfo);
668 }
669 // NOTE: aszilagyi. this function is not fully implement the TSC one, in the future if we will have a
670 // noImplicitReturn compiler option for TypeScript we should update this function
671 }
672
GetArgRange(const ArenaVector<Signature *> &signatures, ArenaVector<Signature *> *potentialSignatures, uint32_t callArgsSize, bool *haveSignatureWithRest)673 ArgRange TSChecker::GetArgRange(const ArenaVector<Signature *> &signatures,
674 ArenaVector<Signature *> *potentialSignatures, uint32_t callArgsSize,
675 bool *haveSignatureWithRest)
676 {
677 uint32_t minArg = UINT32_MAX;
678 uint32_t maxArg = 0;
679
680 for (auto *it : signatures) {
681 if (it->RestVar() != nullptr) {
682 *haveSignatureWithRest = true;
683 }
684
685 if (it->MinArgCount() < minArg) {
686 minArg = it->MinArgCount();
687 }
688
689 if (it->Params().size() > maxArg) {
690 maxArg = it->Params().size();
691 }
692
693 if (callArgsSize >= it->MinArgCount() && (callArgsSize <= it->Params().size() || it->RestVar() != nullptr)) {
694 potentialSignatures->push_back(it);
695 }
696 }
697
698 return {minArg, maxArg};
699 }
700
CallMatchesSignature(const ArenaVector<ir::Expression *> &args, Signature *signature, bool throwError)701 bool TSChecker::CallMatchesSignature(const ArenaVector<ir::Expression *> &args, Signature *signature, bool throwError)
702 {
703 for (size_t index = 0; index < args.size(); index++) {
704 checker::Type *sigArgType = nullptr;
705 bool validateRestArg = false;
706
707 if (index >= signature->Params().size()) {
708 ASSERT(signature->RestVar());
709 validateRestArg = true;
710 sigArgType = signature->RestVar()->TsType();
711 } else {
712 sigArgType = signature->Params()[index]->TsType();
713 }
714
715 if (validateRestArg || !throwError) {
716 checker::Type *callArgType = GetBaseTypeOfLiteralType(args[index]->Check(this));
717 if (IsTypeAssignableTo(callArgType, sigArgType)) {
718 continue;
719 }
720
721 if (throwError) {
722 ThrowTypeError(
723 {"Argument of type '", callArgType, "' is not assignable to parameter of type '", sigArgType, "'."},
724 args[index]->Start());
725 }
726 return false;
727 }
728
729 ElaborateElementwise(sigArgType, args[index], args[index]->Start());
730 }
731
732 return true;
733 }
734
ResolveCallOrNewExpression(const ArenaVector<Signature *> &signatures, ArenaVector<ir::Expression *> arguments, const lexer::SourcePosition &errPos)735 Type *TSChecker::ResolveCallOrNewExpression(const ArenaVector<Signature *> &signatures,
736 ArenaVector<ir::Expression *> arguments,
737 const lexer::SourcePosition &errPos)
738 {
739 if (signatures.empty()) {
740 ThrowTypeError("This expression is not callable.", errPos);
741 }
742
743 ArenaVector<checker::Signature *> potentialSignatures(Allocator()->Adapter());
744 bool haveSignatureWithRest = false;
745
746 auto argRange = GetArgRange(signatures, &potentialSignatures, arguments.size(), &haveSignatureWithRest);
747
748 if (potentialSignatures.empty()) {
749 if (haveSignatureWithRest) {
750 ThrowTypeError({"Expected at least ", argRange.first, " arguments, but got ", arguments.size(), "."},
751 errPos);
752 }
753
754 if (signatures.size() == 1 && argRange.first == argRange.second) {
755 lexer::SourcePosition loc =
756 (argRange.first > arguments.size()) ? errPos : arguments[argRange.second]->Start();
757 ThrowTypeError({"Expected ", argRange.first, " arguments, but got ", arguments.size(), "."}, loc);
758 }
759
760 ThrowTypeError({"Expected ", argRange.first, "-", argRange.second, " arguments, but got ", arguments.size()},
761 errPos);
762 }
763
764 checker::Type *returnType = nullptr;
765 for (auto *it : potentialSignatures) {
766 if (CallMatchesSignature(arguments, it, potentialSignatures.size() == 1)) {
767 returnType = it->ReturnType();
768 break;
769 }
770 }
771
772 if (returnType == nullptr) {
773 ThrowTypeError("No overload matches this call.", errPos);
774 }
775
776 return returnType;
777 }
778 } // namespace ark::es2panda::checker
779