1 /*
2 * Copyright (c) 2025 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 "optionalArgumentsLowering.h"
17 #include "compiler/lowering/util.h"
18 #include "ir/expressions/literals/undefinedLiteral.h"
19 #include "checker/ETSchecker.h"
20
21 namespace ark::es2panda::compiler {
22 static void TransformArguments(public_lib::Context *ctx, ir::Expression *callLike, checker::Signature *signature,
23 ArenaVector<ir::Expression *> &arguments);
24
TransformArgumentsForTrailingLambda(public_lib::Context * ctx,ir::CallExpression * callExpr,checker::Signature * sig)25 static void TransformArgumentsForTrailingLambda(public_lib::Context *ctx, ir::CallExpression *callExpr,
26 checker::Signature *sig)
27 {
28 ES2PANDA_ASSERT(!callExpr->Arguments().empty());
29 auto lastArg = callExpr->Arguments().back();
30 callExpr->Arguments().pop_back();
31 TransformArguments(ctx, callExpr, sig, callExpr->Arguments());
32 // Here the last param to match the trailing lamda must be optional, so we pop the last argument.
33 callExpr->Arguments().pop_back();
34 callExpr->Arguments().push_back(lastArg);
35 }
36
TransformArguments(public_lib::Context * ctx,ir::Expression * callLike,checker::Signature * signature,ArenaVector<ir::Expression * > & arguments)37 static void TransformArguments(public_lib::Context *ctx, ir::Expression *callLike, checker::Signature *signature,
38 ArenaVector<ir::Expression *> &arguments)
39 {
40 if (signature->ArgCount() < arguments.size()) {
41 ES2PANDA_ASSERT(signature->HasRestParameter());
42 return;
43 }
44 ES2PANDA_ASSERT(signature->ArgCount() >= signature->MinArgCount());
45 if (arguments.size() < signature->MinArgCount()) { // #22952: workaround for dynamic types
46 auto callee = callLike->IsCallExpression() ? callLike->AsCallExpression()->Callee()
47 : callLike->AsETSNewClassInstanceExpression()->GetTypeRef();
48 if (callee->TsType()->HasTypeFlag(checker::TypeFlag::ETS_DYNAMIC_FLAG)) {
49 return;
50 }
51 }
52 ES2PANDA_ASSERT((callLike->IsCallExpression() && callLike->AsCallExpression()->IsTrailingCall()) ||
53 arguments.size() >= signature->MinArgCount());
54
55 auto const checker = ctx->checker->AsETSChecker();
56 auto const allocator = ctx->allocator;
57
58 size_t missing = signature->ArgCount() - arguments.size();
59 for (size_t i = 0; i < missing; ++i) {
60 auto undefArg = allocator->New<ir::UndefinedLiteral>();
61 ES2PANDA_ASSERT(undefArg != nullptr);
62 undefArg->SetTsType(checker->GlobalETSUndefinedType());
63 arguments.push_back(undefArg);
64 undefArg->SetParent(callLike);
65 }
66 }
67
PerformForModule(public_lib::Context * ctx,parser::Program * program)68 bool OptionalArgumentsLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program)
69 {
70 program->Ast()->TransformChildrenRecursivelyPreorder(
71 // CC-OFFNXT(G.FMT.14-CPP) project code style
72 [ctx](ir::AstNode *const node) -> ir::AstNode * {
73 if (node->IsCallExpression()) {
74 auto callExpr = node->AsCallExpression();
75 if (callExpr->Signature() == nullptr) {
76 ctx->parser->LogError(diagnostic::IMPROPER_NESTING_INTERFACE, {}, node->Start());
77 return node;
78 }
79
80 callExpr->IsTrailingCall()
81 ? TransformArgumentsForTrailingLambda(ctx, callExpr->AsCallExpression(), callExpr->Signature())
82 : TransformArguments(ctx, callExpr, callExpr->Signature(), callExpr->Arguments());
83 } else if (node->IsETSNewClassInstanceExpression()) {
84 auto newExpr = node->AsETSNewClassInstanceExpression();
85 if (newExpr->GetSignature() == nullptr) {
86 ctx->parser->LogError(diagnostic::IMPROPER_NESTING_INTERFACE, {}, node->Start());
87 return node;
88 }
89 TransformArguments(ctx, newExpr, newExpr->GetSignature(), newExpr->GetArguments());
90 }
91 return node;
92 },
93 Name());
94
95 return true;
96 }
97
PostconditionForModule(public_lib::Context * ctx,parser::Program const * program)98 bool OptionalArgumentsLowering::PostconditionForModule([[maybe_unused]] public_lib::Context *ctx,
99 parser::Program const *program)
100 {
101 return !program->Ast()->IsAnyChild([](ir::AstNode const *node) {
102 if (!node->IsScriptFunction()) {
103 return false;
104 }
105 for (auto p : node->AsScriptFunction()->Params()) {
106 if (p->AsETSParameterExpression()->Initializer() != nullptr) {
107 return true;
108 }
109 }
110 return false;
111 });
112 }
113
114 } // namespace ark::es2panda::compiler
115