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