• 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 "declareOverloadLowering.h"
17 
18 #include "compiler/lowering/scopesInit/scopesInitPhase.h"
19 #include "compiler/lowering/util.h"
20 #include "util/options.h"
21 
22 namespace ark::es2panda::compiler {
23 
GenerateOverloadHelperParams(public_lib::Context * ctx,uint32_t minArg,size_t maxArg,bool hasRestVar,ArenaVector<ir::Expression * > & params)24 void GenerateOverloadHelperParams(public_lib::Context *ctx, uint32_t minArg, size_t maxArg, bool hasRestVar,
25                                   ArenaVector<ir::Expression *> &params)
26 {
27     auto *checker = ctx->checker->AsETSChecker();
28     auto *allocator = ctx->allocator;
29 
30     if (!hasRestVar) {
31         for (size_t idx = 0; idx < maxArg; ++idx) {
32             auto *id = Gensym(allocator);
33             auto *typeAnnotation = ctx->AllocNode<ir::OpaqueTypeNode>(checker->GlobalETSAnyType(), allocator);
34             id->SetTsTypeAnnotation(typeAnnotation);
35             typeAnnotation->SetParent(id);
36             auto *param = ctx->AllocNode<ir::ETSParameterExpression>(id, false, allocator);
37             ES2PANDA_ASSERT(param);
38             param->SetOptional(idx >= minArg);
39             params.push_back(param);
40         }
41         return;
42     }
43 
44     auto *restIdent = Gensym(allocator);
45     auto *spread = ctx->AllocNode<ir::SpreadElement>(ir::AstNodeType::REST_ELEMENT, allocator, restIdent);
46     auto *arr = checker->CreateETSArrayType(checker->GlobalETSAnyType(), false);
47     auto *typeAnnotation = ctx->AllocNode<ir::OpaqueTypeNode>(arr, allocator);
48 
49     spread->SetTsTypeAnnotation(typeAnnotation);
50     spread->SetTsType(arr);
51     restIdent->SetTsType(arr);
52     auto *param = ctx->AllocNode<ir::ETSParameterExpression>(spread, nullptr, allocator);
53 
54     restIdent->SetParent(spread);
55     typeAnnotation->SetParent(spread);
56     spread->SetParent(param);
57     params.push_back(param);
58 }
59 
BuildOverloadHelperFunction(public_lib::Context * ctx,ir::MethodDefinition * method)60 void BuildOverloadHelperFunction(public_lib::Context *ctx, ir::MethodDefinition *method)
61 {
62     auto *checker = ctx->checker->AsETSChecker();
63     auto *allocator = ctx->allocator;
64     auto *varBinder = ctx->checker->VarBinder()->AsETSBinder();
65 
66     auto const &[minArg, maxArg, needHelperOverload, isDeclare, hasRestVar, returnVoid] = method->GetOverloadInfo();
67     ES2PANDA_ASSERT(needHelperOverload && method->Function() != nullptr);
68 
69     auto params = ArenaVector<ir::Expression *>(allocator->Adapter());
70     GenerateOverloadHelperParams(ctx, minArg, maxArg, hasRestVar, params);
71 
72     auto *returnType = returnVoid ? checker->GlobalVoidType() : checker->GlobalETSAnyType();
73     auto *returnAnno = ctx->AllocNode<ir::OpaqueTypeNode>(returnType, allocator);
74 
75     ir::ScriptFunctionFlags functionFlag = method->Function()->Flags();
76     auto *func = ctx->AllocNode<ir::ScriptFunction>(
77         allocator,
78         ir::ScriptFunction::ScriptFunctionData {nullptr, ir::FunctionSignature(nullptr, std::move(params), returnAnno),
79                                                 functionFlag, method->Function()->Modifiers()});
80     ES2PANDA_ASSERT(func != nullptr && method->Id() != nullptr);
81     auto *methodId = ctx->AllocNode<ir::Identifier>(method->Id()->Name(), allocator);
82     func->SetIdent(methodId);
83     auto *funcExpr = ctx->AllocNode<ir::FunctionExpression>(func);
84     auto *methodIdClone = methodId->Clone(allocator, nullptr);
85     auto *helperOverload = ctx->AllocNode<ir::MethodDefinition>(method->Kind(), methodIdClone, funcExpr,
86                                                                 method->Modifiers(), allocator, false);
87 
88     method->AddOverload(helperOverload);
89     ES2PANDA_ASSERT(helperOverload->Function() != nullptr);
90     ES2PANDA_ASSERT(helperOverload->Id() != nullptr);
91     helperOverload->Function()->ClearFlag((ir::ScriptFunctionFlags::OVERLOAD));
92     helperOverload->SetParent(method);
93 
94     checker::SavedCheckerContext scc(checker, checker->Context().Status(), method->Function()->Signature()->Owner());
95     Rebind(ctx->phaseManager, varBinder, helperOverload);
96     helperOverload->Function()->AddFlag((ir::ScriptFunctionFlags::OVERLOAD));
97     auto funcScope = helperOverload->Function()->Scope();
98     funcScope->BindName(method->Function()->Scope()->Name());
99 
100     helperOverload->Function()->Id()->SetVariable(helperOverload->Id()->Variable());
101     checker->BuildFunctionSignature(helperOverload->Function(), method->IsConstructor());
102 
103     auto *const overloadType = checker->BuildMethodType(helperOverload->Function());
104     helperOverload->SetTsType(overloadType);
105 
106     ES2PANDA_ASSERT(method->TsType()->IsETSFunctionType());
107     method->TsType()->AsETSFunctionType()->SetHelperSignature(helperOverload->Function()->Signature());
108 }
109 
UpdateCallSignature(public_lib::Context * ctx,ir::CallExpression * expr)110 void UpdateCallSignature(public_lib::Context *ctx, ir::CallExpression *expr)
111 {
112     ES2PANDA_ASSERT(expr->Signature()->HasSignatureFlag(checker::SignatureFlags::DUPLICATE_ASM));
113 
114     auto *checker = ctx->checker->AsETSChecker();
115     expr->SetTsType(nullptr);
116     expr->Check(checker);
117 }
118 
PerformForModule(public_lib::Context * ctx,parser::Program * program)119 bool DeclareOverloadLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program)
120 {
121     // Note: Generate helper overload method
122     program->Ast()->TransformChildrenRecursively(
123         [ctx](ir::AstNode *ast) {
124             if (ast->IsMethodDefinition() && ast->AsMethodDefinition()->GetOverloadInfo().needHelperOverload) {
125                 BuildOverloadHelperFunction(ctx, ast->AsMethodDefinition());
126             }
127             return ast;
128         },
129         Name());
130 
131     // Note: Update signature for call expression
132     program->Ast()->TransformChildrenRecursively(
133         [ctx](ir::AstNode *ast) {
134             if (!ast->IsCallExpression() || ast->AsCallExpression()->Signature() == nullptr) {
135                 return ast;
136             }
137 
138             if (ast->AsCallExpression()->Signature()->HasSignatureFlag(checker::SignatureFlags::DUPLICATE_ASM)) {
139                 UpdateCallSignature(ctx, ast->AsCallExpression());
140             }
141 
142             return ast;
143         },
144         Name());
145     return true;
146 }
147 
148 }  // namespace ark::es2panda::compiler
149