1 /**
2 * Copyright (c) 2021-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 "signature.h"
17
18 #include "checker/ETSchecker.h"
19 #include "ets/etsObjectType.h"
20 #include "compiler/lowering/util.h"
21
22 namespace ark::es2panda::checker {
23
InternalName() const24 util::StringView Signature::InternalName() const
25 {
26 return internalName_.Empty() && func_ != nullptr ? func_->Scope()->InternalName() : internalName_;
27 }
28
Substitute(TypeRelation * relation,const Substitution * substitution)29 Signature *Signature::Substitute(TypeRelation *relation, const Substitution *substitution)
30 {
31 if (substitution == nullptr || substitution->empty()) {
32 return this;
33 }
34 auto *checker = relation->GetChecker()->AsETSChecker();
35 auto *allocator = checker->ProgramAllocator();
36 bool anyChange = false;
37 SignatureInfo *newSigInfo = allocator->New<SignatureInfo>(allocator);
38 ES2PANDA_ASSERT(newSigInfo != nullptr);
39 if (!signatureInfo_->typeParams.empty()) {
40 for (auto *tparam : signatureInfo_->typeParams) {
41 auto *newTparam = tparam->Substitute(relation, substitution);
42 newSigInfo->typeParams.push_back(newTparam);
43 anyChange |= (newTparam != tparam);
44 }
45 }
46 newSigInfo->minArgCount = signatureInfo_->minArgCount;
47
48 for (auto *param : signatureInfo_->params) {
49 auto *newParam = param;
50 auto *newParamType = param->TsType()->Substitute(relation, substitution);
51 if (newParamType != param->TsType()) {
52 anyChange = true;
53 newParam = param->Copy(allocator, param->Declaration());
54 if (newParamType->IsETSVoidType()) {
55 // since `void` is not allowed to be used as param type
56 newParamType = checker->GlobalETSUndefinedType();
57 }
58 newParam->SetTsType(newParamType);
59 }
60 newSigInfo->params.push_back(newParam);
61 }
62
63 if (signatureInfo_->restVar != nullptr) {
64 auto *newRestVar = signatureInfo_->restVar;
65 auto *newRestType = signatureInfo_->restVar->TsType()->Substitute(relation, substitution);
66 if (newRestType != signatureInfo_->restVar->TsType()) {
67 anyChange = true;
68 newRestVar = signatureInfo_->restVar->Copy(allocator, signatureInfo_->restVar->Declaration());
69 newRestVar->SetTsType(newRestType);
70 }
71 newSigInfo->restVar = newRestVar;
72 }
73
74 if (!anyChange) {
75 newSigInfo = signatureInfo_;
76 }
77
78 auto *newReturnType = returnType_->Substitute(relation, substitution);
79 if (newReturnType == returnType_ && !anyChange) {
80 return this;
81 }
82
83 return CreateSignatureForSubstitute(allocator, newSigInfo, newReturnType);
84 }
85
CreateSignatureForSubstitute(ArenaAllocator * allocator,SignatureInfo * sigInfo,Type * returnType)86 Signature *Signature::CreateSignatureForSubstitute(ArenaAllocator *allocator, SignatureInfo *sigInfo, Type *returnType)
87 {
88 auto *result = allocator->New<Signature>(sigInfo, returnType, func_);
89 ES2PANDA_ASSERT(result != nullptr);
90 result->flags_ = flags_;
91 result->internalName_ = internalName_;
92 result->ownerObj_ = ownerObj_;
93 result->ownerVar_ = ownerVar_;
94 return result;
95 }
96
ToAssemblerType(std::stringstream & ss) const97 void Signature::ToAssemblerType(std::stringstream &ss) const
98 {
99 ss << compiler::Signatures::MANGLE_BEGIN;
100
101 for (const auto *param : signatureInfo_->params) {
102 param->TsType()->ToAssemblerTypeWithRank(ss);
103 ss << compiler::Signatures::MANGLE_SEPARATOR;
104 }
105
106 if (signatureInfo_->restVar != nullptr) {
107 signatureInfo_->restVar->TsType()->ToAssemblerTypeWithRank(ss);
108 ss << compiler::Signatures::MANGLE_SEPARATOR;
109 }
110
111 returnType_->ToAssemblerTypeWithRank(ss);
112 ss << compiler::Signatures::MANGLE_SEPARATOR;
113 }
114
Copy(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)115 Signature *Signature::Copy(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes)
116 {
117 SignatureInfo *copiedInfo = allocator->New<SignatureInfo>(signatureInfo_, allocator);
118 ES2PANDA_ASSERT(copiedInfo != nullptr);
119 for (size_t idx = 0U; idx < signatureInfo_->params.size(); ++idx) {
120 auto *const paramType = signatureInfo_->params[idx]->TsType();
121 if (paramType->HasTypeFlag(TypeFlag::GENERIC) && paramType->IsETSObjectType()) {
122 copiedInfo->params[idx]->SetTsType(paramType->Instantiate(allocator, relation, globalTypes));
123 auto originalTypeArgs = paramType->AsETSObjectType()->GetOriginalBaseType()->TypeArguments();
124 copiedInfo->params[idx]->TsType()->AsETSObjectType()->SetTypeArguments(std::move(originalTypeArgs));
125 } else {
126 copiedInfo->params[idx]->SetTsType(
127 ETSChecker::TryToInstantiate(paramType, allocator, relation, globalTypes));
128 }
129 }
130
131 auto *const copiedSignature = allocator->New<Signature>(copiedInfo, returnType_, func_);
132 ES2PANDA_ASSERT(copiedSignature != nullptr);
133 copiedSignature->flags_ = flags_;
134 copiedSignature->internalName_ = internalName_;
135 copiedSignature->ownerObj_ = ownerObj_;
136 copiedSignature->ownerVar_ = ownerVar_;
137
138 return copiedSignature;
139 }
140
ToString(std::stringstream & ss,const varbinder::Variable * variable,bool printAsMethod,bool precise) const141 void Signature::ToString(std::stringstream &ss, const varbinder::Variable *variable, bool printAsMethod,
142 bool precise) const
143 {
144 if (!signatureInfo_->typeParams.empty()) {
145 ss << "<";
146 for (auto it = signatureInfo_->typeParams.begin(); it != signatureInfo_->typeParams.end(); ++it) {
147 (*it)->ToString(ss, precise);
148 if (std::next(it) != signatureInfo_->typeParams.end()) {
149 ss << ", ";
150 }
151 }
152 ss << ">";
153 }
154
155 ss << "(";
156
157 for (auto it = signatureInfo_->params.begin(); it != signatureInfo_->params.end(); it++) {
158 ss << (!(*it)->Name().StartsWith(compiler::GENSYM_CORE) ? (*it)->Name().Utf8() : compiler::DUMMY_ID);
159
160 if ((*it)->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
161 ss << "?";
162 }
163
164 ss << ": ";
165
166 (*it)->TsType()->ToString(ss, precise);
167
168 if (std::next(it) != signatureInfo_->params.end()) {
169 ss << ", ";
170 }
171 }
172
173 if (signatureInfo_->restVar != nullptr) {
174 if (!signatureInfo_->params.empty()) {
175 ss << ", ";
176 }
177
178 ss << "...";
179 ss << (!signatureInfo_->restVar->Name().StartsWith(compiler::GENSYM_CORE)
180 ? signatureInfo_->restVar->Name().Utf8()
181 : compiler::DUMMY_ID);
182 ss << ": ";
183 signatureInfo_->restVar->TsType()->ToString(ss, precise);
184 }
185
186 ss << ")";
187
188 if (printAsMethod || (variable != nullptr && variable->HasFlag(varbinder::VariableFlags::METHOD))) {
189 ss << ": ";
190 } else {
191 ss << " => ";
192 }
193
194 returnType_->ToString(ss, precise);
195
196 if (HasSignatureFlag(SignatureFlags::THROWS)) {
197 ss << " throws";
198 } else if (HasSignatureFlag(SignatureFlags::RETHROWS)) {
199 ss << " rethrows";
200 }
201 }
202
ToString() const203 std::string Signature::ToString() const
204 {
205 std::stringstream ss;
206 ToString(ss, nullptr);
207 return ss.str();
208 }
209
210 // this function intentionally ignores relation->Result
MethodSignaturesAreCompatible(TypeRelation * relation,bool checkIdentical,Signature * const super,Signature * const sub)211 static bool MethodSignaturesAreCompatible(TypeRelation *relation, bool checkIdentical, Signature *const super,
212 Signature *const sub)
213 {
214 ES2PANDA_ASSERT(!sub->HasRestParameter() || (sub->ArgCount() == sub->MinArgCount()));
215 ES2PANDA_ASSERT(!super->HasRestParameter() || (super->ArgCount() == super->MinArgCount()));
216
217 if (sub->ArgCount() != super->ArgCount()) {
218 return false;
219 }
220
221 if (sub->HasRestParameter() != super->HasRestParameter()) {
222 return false;
223 }
224
225 auto const areCompatible = [relation, checkIdentical](Type *superT, Type *subT) {
226 return checkIdentical ? relation->IsIdenticalTo(superT, subT) : relation->IsSupertypeOf(superT, subT);
227 };
228 if (!relation->NoReturnTypeCheck() && !areCompatible(super->ReturnType(), sub->ReturnType())) {
229 return false;
230 }
231 for (size_t idx = 0; idx < sub->ArgCount(); ++idx) {
232 if (!areCompatible(sub->Params()[idx]->TsType(), super->Params()[idx]->TsType())) {
233 return false;
234 }
235 }
236 return !sub->HasRestParameter() || relation->IsIdenticalTo(sub->RestVar()->TsType(), super->RestVar()->TsType());
237 }
238
IsSubtypeOf(TypeRelation * relation,Signature * super)239 void Signature::IsSubtypeOf(TypeRelation *relation, Signature *super)
240 {
241 auto sub = this;
242 if (sub->HasSignatureFlag(SignatureFlags::GETTER_OR_SETTER) !=
243 super->HasSignatureFlag(SignatureFlags::GETTER_OR_SETTER)) {
244 relation->Result(false);
245 return;
246 }
247
248 if (!relation->GetChecker()->IsETSChecker() && sub->MinArgCount() != super->MinArgCount() &&
249 sub->RestVar() == nullptr && super->RestVar() == nullptr) {
250 relation->Result(false);
251 return;
252 }
253
254 relation->Result(MethodSignaturesAreCompatible(relation, !relation->IsOverridingCheck(), super, sub));
255 }
256
257 // This function is not used by ets extension
AssignmentTarget(TypeRelation * relation,Signature * source)258 void Signature::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Signature *source)
259 {
260 if (signatureInfo_->restVar == nullptr && source->MinArgCount() > signatureInfo_->params.size()) {
261 relation->Result(false);
262 return;
263 }
264
265 for (size_t i = 0; i < source->Params().size(); i++) {
266 if (signatureInfo_->restVar == nullptr && i >= Params().size()) {
267 break;
268 }
269
270 if (signatureInfo_->restVar != nullptr) {
271 relation->IsAssignableTo(source->Params()[i]->TsType(), signatureInfo_->restVar->TsType());
272
273 if (!relation->IsTrue()) {
274 return;
275 }
276
277 continue;
278 }
279
280 relation->IsAssignableTo(source->Params()[i]->TsType(), Params()[i]->TsType());
281
282 if (!relation->IsTrue()) {
283 return;
284 }
285 }
286
287 relation->IsAssignableTo(source->ReturnType(), returnType_);
288
289 if (relation->IsTrue() && signatureInfo_->restVar != nullptr && source->RestVar() != nullptr) {
290 relation->IsAssignableTo(source->RestVar()->TsType(), signatureInfo_->restVar->TsType());
291 }
292 }
293
ToArrowSignature(ETSChecker * checker)294 Signature *Signature::ToArrowSignature(ETSChecker *checker)
295 {
296 auto *allocator = checker->ProgramAllocator();
297 auto *sigInfo = allocator->New<SignatureInfo>(signatureInfo_, allocator);
298 ES2PANDA_ASSERT(sigInfo != nullptr);
299 for (auto param : sigInfo->params) {
300 param->SetTsType(checker->MaybeBoxType(param->TsType()));
301 }
302 auto *retType = checker->MaybeBoxType(returnType_);
303
304 auto *resultSig = allocator->New<Signature>(sigInfo, retType);
305 ES2PANDA_ASSERT(resultSig != nullptr);
306 resultSig->flags_ = flags_;
307 resultSig->SetOwner(Owner());
308 resultSig->SetOwnerVar(OwnerVar());
309 ES2PANDA_ASSERT(!resultSig->HasFunction());
310 return resultSig;
311 }
312
313 } // namespace ark::es2panda::checker
314