• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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