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 *> ¶ms)
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