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